浏览代码

[Rebase] Reconciling changes from upstream

- New features like SyncMirrors() that weren't caught by the rebase.
- Import path renames (gogits -> gogs, gogs -> G-Node)
- Merged lines from functions that were changed in both locations
(G-Node/master and gogs/master)
- Functio renames (Str2Html -> Str2HTML)
Achilleas Koutsou 6 年之前
父节点
当前提交
91867bbb87

+ 2 - 2
cmd/serv.go

@@ -16,11 +16,11 @@ import (
 	"github.com/urfave/cli"
 	log "gopkg.in/clog.v1"
 
+	"syscall"
+
 	"github.com/G-Node/gogs/models"
 	"github.com/G-Node/gogs/models/errors"
 	"github.com/G-Node/gogs/pkg/setting"
-	http "github.com/G-Node/gogs/routes/repo"
-	"syscall"
 )
 
 const (

+ 3 - 6
cmd/web.go

@@ -33,6 +33,7 @@ import (
 	"github.com/G-Node/gogs/models"
 	"github.com/G-Node/gogs/pkg/bindata"
 	"github.com/G-Node/gogs/pkg/context"
+	"github.com/G-Node/gogs/pkg/dav"
 	"github.com/G-Node/gogs/pkg/form"
 	"github.com/G-Node/gogs/pkg/mailer"
 	"github.com/G-Node/gogs/pkg/setting"
@@ -44,7 +45,6 @@ import (
 	"github.com/G-Node/gogs/routes/org"
 	"github.com/G-Node/gogs/routes/repo"
 	"github.com/G-Node/gogs/routes/user"
-	"github.com/G-Node/gogs/pkg/dav"
 	"golang.org/x/net/webdav"
 )
 
@@ -67,10 +67,8 @@ func checkVersion() {
 	if err != nil {
 		log.Fatal(2, "Fail to read 'templates/.VERSION': %v", err)
 	}
-	tplVer := string(data)
-	log.Trace("tmpl:version:%s", tplVer)
-	log.Trace("App:version:%s", setting.AppVer)
-	if strings.TrimSpace(tplVer) != setting.AppVer {
+	tplVer := strings.TrimSpace(string(data))
+	if tplVer != setting.AppVer {
 		if version.Compare(tplVer, setting.AppVer, ">") {
 			log.Fatal(2, "Binary version is lower than template file version, did you forget to recompile Gogs?")
 		} else {
@@ -181,7 +179,6 @@ func runWeb(c *cli.Context) error {
 
 	m := newMacaron()
 
-
 	reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})
 	ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView})
 	ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})

二进制
docker/aarch64/resin-xbuild


二进制
docker/armhf/resin-xbuild


+ 3 - 18
models/admin.go

@@ -14,9 +14,8 @@ import (
 	"github.com/go-xorm/xorm"
 	log "gopkg.in/clog.v1"
 
-	"github.com/G-Node/gogs/pkg/setting"
+	gannex "github.com/G-Node/go-annex"
 	"github.com/G-Node/gogs/pkg/tool"
-	"github.com/G-Node/go-annex"
 )
 
 type NoticeType int
@@ -73,15 +72,9 @@ func CreateRepositoryNotice(desc string) error {
 // RemoveAllWithNotice removes all directories in given path and
 // creates a system notice when error occurs.
 func RemoveAllWithNotice(title, path string) {
-	var err error
-	// LEGACY [Go 1.7]: workaround for Go not being able to remove read-only files/folders: https://github.com/golang/go/issues/9606
-	// this bug should be fixed on Go 1.7, so the workaround should be removed when Gogs don't support Go 1.6 anymore:
-	// https://github.com/golang/go/commit/2ffb3e5d905b5622204d199128dec06cefd57790
-	// Note: Windows complains when delete target does not exist, therefore we can skip deletion in such cases.
-
 	if msg, err := gannex.AUInit(path); err != nil {
 		if strings.Contains(msg, "If you don't care about preserving the data") {
-			log.Trace("Annex uninit Repo:%s", msg)
+			log.Trace("Annex uninit Repo: %s", msg)
 		} else {
 			log.Error(1, "Could not annex uninit repo. Error: %s,%s", err, msg)
 		}
@@ -89,15 +82,7 @@ func RemoveAllWithNotice(title, path string) {
 		log.Trace("Annex uninit Repo:%s", msg)
 	}
 
-	if setting.IsWindows && com.IsExist(path) {
-		// converting "/" to "\" in path on Windows
-		path = strings.Replace(path, "/", "\\", -1)
-		err = exec.Command("cmd", "/C", "rmdir", "/S", "/Q", path).Run()
-	} else {
-		err = os.RemoveAll(path)
-	}
-
-	if err != nil {
+	if err := os.RemoveAll(path); err != nil {
 		desc := fmt.Sprintf("%s [%s]: %v", title, path, err)
 		log.Warn(desc)
 		if err = CreateRepositoryNotice(desc); err != nil {

+ 1 - 1
models/migrations/v18.go

@@ -9,7 +9,7 @@ import (
 
 	"github.com/go-xorm/xorm"
 
-	"github.com/gogs/gogs/pkg/setting"
+	"github.com/G-Node/gogs/pkg/setting"
 )
 
 func updateRepositoryDescriptionField(x *xorm.Engine) error {

+ 95 - 1
models/mirror.go

@@ -382,6 +382,100 @@ func SyncMirrors() {
 			continue
 		}
 
+		// TODO:
+		// - Create "Mirror Sync" webhook event
+		// - Create mirror sync (create, push and delete) events and trigger the "mirror sync" webhooks
+
+		var gitRepo *git.Repository
+		if len(results) == 0 {
+			log.Trace("SyncMirrors [repo_id: %d]: no commits fetched", m.RepoID)
+		} else {
+			gitRepo, err = git.OpenRepository(m.Repo.RepoPath())
+			if err != nil {
+				log.Error(2, "OpenRepository [%d]: %v", m.RepoID, err)
+				continue
+			}
+		}
+
+		for _, result := range results {
+			// Discard GitHub pull requests, i.e. refs/pull/*
+			if strings.HasPrefix(result.refName, "refs/pull/") {
+				continue
+			}
+
+			// Delete reference
+			if result.newCommitID == GIT_SHORT_EMPTY_SHA {
+				if err = MirrorSyncDeleteAction(m.Repo, result.refName); err != nil {
+					log.Error(2, "MirrorSyncDeleteAction [repo_id: %d]: %v", m.RepoID, err)
+				}
+				continue
+			}
+
+			// New reference
+			isNewRef := false
+			if result.oldCommitID == GIT_SHORT_EMPTY_SHA {
+				if err = MirrorSyncCreateAction(m.Repo, result.refName); err != nil {
+					log.Error(2, "MirrorSyncCreateAction [repo_id: %d]: %v", m.RepoID, err)
+					continue
+				}
+				isNewRef = true
+			}
+
+			// Push commits
+			var commits *list.List
+			var oldCommitID string
+			var newCommitID string
+			if !isNewRef {
+				oldCommitID, err = git.GetFullCommitID(gitRepo.Path, result.oldCommitID)
+				if err != nil {
+					log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
+					continue
+				}
+				newCommitID, err = git.GetFullCommitID(gitRepo.Path, result.newCommitID)
+				if err != nil {
+					log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
+					continue
+				}
+				commits, err = gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID)
+				if err != nil {
+					log.Error(2, "CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
+					continue
+				}
+			} else {
+				refNewCommitID, err := gitRepo.GetBranchCommitID(result.refName)
+				if err != nil {
+					log.Error(2, "GetFullCommitID [%d]: %v", m.RepoID, err)
+					continue
+				}
+				if newCommit, err := gitRepo.GetCommit(refNewCommitID); err != nil {
+					log.Error(2, "GetCommit [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommitID, err)
+					continue
+				} else {
+					// TODO: Get the commits for the new ref until the closest ancestor branch like Github does
+					commits, err = newCommit.CommitsBeforeLimit(10)
+					if err != nil {
+						log.Error(2, "CommitsBeforeLimit [repo_id: %d, commit_id: %s]: %v", m.RepoID, refNewCommitID, err)
+					}
+					oldCommitID = git.EMPTY_SHA
+					newCommitID = refNewCommitID
+				}
+			}
+			if err = MirrorSyncPushAction(m.Repo, MirrorSyncPushActionOptions{
+				RefName:     result.refName,
+				OldCommitID: oldCommitID,
+				NewCommitID: newCommitID,
+				Commits:     ListToPushCommits(commits),
+			}); err != nil {
+				log.Error(2, "MirrorSyncPushAction [repo_id: %d]: %v", m.RepoID, err)
+				continue
+			}
+		}
+
+		if _, err = x.Exec("UPDATE mirror SET updated_unix = ? WHERE repo_id = ?", time.Now().Unix(), m.RepoID); err != nil {
+			log.Error(2, "Update 'mirror.updated_unix' [%d]: %v", m.RepoID, err)
+			continue
+		}
+
 		// Get latest commit date and compare to current repository updated time,
 		// update if latest commit date is newer.
 		commitDate, err := git.GetLatestCommitDate(m.Repo.RepoPath(), "")
@@ -393,7 +487,7 @@ func SyncMirrors() {
 		}
 
 		if _, err = x.Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", commitDate.Unix(), m.RepoID); err != nil {
-			log.Error(2, "Update repository 'updated_unix' [%d]: %v", m.RepoID, err)
+			log.Error(2, "Update 'repository.updated_unix' [%d]: %v", m.RepoID, err)
 			continue
 		}
 	}

+ 1 - 1
models/org_team.go

@@ -10,7 +10,7 @@ import (
 
 	"github.com/go-xorm/xorm"
 
-	"github.com/gogs/gogs/models/errors"
+	"github.com/G-Node/gogs/models/errors"
 )
 
 const OWNER_TEAM = "Owners"

+ 9 - 4
models/repo.go

@@ -28,9 +28,10 @@ import (
 	"gopkg.in/ini.v1"
 
 	git "github.com/G-Node/git-module"
-	api "github.com/gogits/go-gogs-client"
+	api "github.com/gogs/go-gogs-client"
 
 	"github.com/G-Node/gogs/models/errors"
+	"github.com/G-Node/gogs/pkg/avatar"
 	"github.com/G-Node/gogs/pkg/bindata"
 	"github.com/G-Node/gogs/pkg/markup"
 	"github.com/G-Node/gogs/pkg/process"
@@ -384,9 +385,13 @@ func (repo *Repository) APIFormat(permission *api.Permission, user ...*User) *ap
 		// Reserved for go-gogs-client change
 		//		AvatarUrl:     repo.AvatarLink(),
 	}
-	if repo.IsFork && repo.BaseRepo != nil {
-		// FIXME: check precise permission for base repository
-		apiRepo.Parent = repo.BaseRepo.APIFormat(nil)
+	if repo.IsFork {
+		p := &api.Permission{Pull: true}
+		if len(user) != 0 {
+			p.Admin = user[0].IsAdminOfRepo(repo)
+			p.Push = user[0].IsWriterOfRepo(repo)
+		}
+		apiRepo.Parent = repo.BaseRepo.APIFormat(p)
 	}
 	return apiRepo
 }

+ 2 - 1
models/repo_branch.go

@@ -8,9 +8,10 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/Unknwon/com"
 	"github.com/G-Node/git-module"
+	"github.com/Unknwon/com"
 
+	"github.com/G-Node/gogs/models/errors"
 	"github.com/G-Node/gogs/pkg/tool"
 )
 

+ 23 - 77
models/repo_editor.go

@@ -18,15 +18,19 @@ import (
 
 	"github.com/Unknwon/com"
 	gouuid "github.com/satori/go.uuid"
+	log "gopkg.in/clog.v1"
 
 	git "github.com/G-Node/git-module"
 
-	"github.com/G-Node/gogs/pkg/process"
-	"github.com/G-Node/gogs/pkg/setting"
-	"github.com/G-Node/go-annex"
-	"encoding/json"
 	"bytes"
+	"encoding/json"
 	"net/http"
+
+	gannex "github.com/G-Node/go-annex"
+	"github.com/G-Node/gogs/models/errors"
+	"github.com/G-Node/gogs/pkg/process"
+	"github.com/G-Node/gogs/pkg/setting"
+	"github.com/G-Node/gogs/pkg/tool"
 )
 
 const (
@@ -196,40 +200,6 @@ func (repo *Repository) UpdateRepoFile(doer *User, opts UpdateRepoFileOptions) (
 		return fmt.Errorf("git push origin %s: %v", opts.NewBranch, err)
 	}
 
-	gitRepo, err := git.OpenRepository(repo.RepoPath())
-	if err != nil {
-		log.Error(2, "OpenRepository: %v", err)
-		return nil
-	}
-	commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
-	if err != nil {
-		log.Error(2, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
-		return nil
-	}
-
-	// Simulate push event.
-	pushCommits := &PushCommits{
-		Len:     1,
-		Commits: []*PushCommit{CommitToPushCommit(commit)},
-	}
-	oldCommitID := opts.LastCommitID
-	if opts.NewBranch != opts.OldBranch {
-		oldCommitID = git.EMPTY_SHA
-	}
-	if err := CommitRepoAction(CommitRepoActionOptions{
-		PusherName:  doer.Name,
-		RepoOwnerID: repo.MustOwner().ID,
-		RepoName:    repo.Name,
-		RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
-		OldCommitID: oldCommitID,
-		NewCommitID: commit.ID.String(),
-		Commits:     pushCommits,
-	}); err != nil {
-		log.Error(2, "CommitRepoAction: %v", err)
-		return nil
-	}
-
-	go AddTestPullRequestTask(doer, repo.ID, opts.NewBranch, true)
 	if setting.Search.Do {
 		StartIndexing(doer, repo.MustOwner(), repo)
 	}
@@ -516,23 +486,30 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
 	localPath := repo.LocalCopyPath()
 	dirPath := path.Join(localPath, opts.TreePath)
 	os.MkdirAll(dirPath, os.ModePerm)
-	log.Trace("localpath:%s", localPath)
-	// prepare annex
 
-	// Copy uploaded files into repository.
+	// Copy uploaded files into repository
 	for _, upload := range uploads {
 		tmpPath := upload.LocalPath()
-		targetPath := path.Join(dirPath, upload.Name)
-		os.MkdirAll(filepath.Dir(targetPath), os.ModePerm)
-		repoFileName := path.Join(opts.TreePath, upload.Name)
 		if !com.IsFile(tmpPath) {
 			continue
 		}
-		// needed for annex, due to symlinks
-		os.Remove(targetPath)
+
+		// Prevent copying files into .git directory, see https://github.com/gogs/gogs/issues/5558.
+		if isRepositoryGitPath(upload.Name) {
+			continue
+		}
+
+		targetPath := path.Join(dirPath, upload.Name)
+		if err = com.Copy(tmpPath, targetPath); err != nil {
+			return fmt.Errorf("copy: %v", err)
+		}
+		repoFileName := path.Join(opts.TreePath, upload.Name)
+
 		if err = com.Copy(tmpPath, targetPath); err != nil {
 			return fmt.Errorf("copy: %v", err)
 		}
+		// needed for annex, due to symlinks
+		os.Remove(targetPath)
 		log.Trace("Check for annexing: %s", upload.Name)
 		if finfo, err := os.Stat(targetPath); err == nil {
 			log.Trace("Filesize is:%d", finfo.Size())
@@ -584,36 +561,6 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
 		log.Trace("Annex sync:%s", msg)
 	}
 
-	gitRepo, err := git.OpenRepository(repo.RepoPath())
-	if err != nil {
-		log.Error(2, "OpenRepository: %v", err)
-		return nil
-	}
-	commit, err := gitRepo.GetBranchCommit(opts.NewBranch)
-	if err != nil {
-		log.Error(2, "GetBranchCommit [branch: %s]: %v", opts.NewBranch, err)
-		return nil
-	}
-
-	// Simulate push event.
-	pushCommits := &PushCommits{
-		Len:     1,
-		Commits: []*PushCommit{CommitToPushCommit(commit)},
-	}
-	if err := CommitRepoAction(CommitRepoActionOptions{
-		PusherName:  doer.Name,
-		RepoOwnerID: repo.MustOwner().ID,
-		RepoName:    repo.Name,
-		RefFullName: git.BRANCH_PREFIX + opts.NewBranch,
-		OldCommitID: opts.LastCommitID,
-		NewCommitID: commit.ID.String(),
-		Commits:     pushCommits,
-	}); err != nil {
-		log.Error(2, "CommitRepoAction: %v", err)
-		return nil
-	}
-	go AddTestPullRequestTask(doer, repo.ID, opts.NewBranch, true)
-
 	// We better start out cleaning now. No use keeping files around with annex
 	if msg, err := gannex.AUInit(localPath); err != nil {
 		log.Error(1, "Annex uninit failed with error: %v,%s, at: %s/ This repository might fail at "+
@@ -623,7 +570,6 @@ func (repo *Repository) UploadRepoFiles(doer *User, opts UploadRepoFileOptions)
 	if setting.Search.Do {
 		StartIndexing(doer, repo.MustOwner(), repo)
 	}
-
 	RemoveAllWithNotice("Cleaning out after upload", localPath)
 	return DeleteUploads(uploads...)
 }

+ 8 - 8
models/user.go

@@ -27,7 +27,7 @@ import (
 	log "gopkg.in/clog.v1"
 
 	"github.com/G-Node/git-module"
-	api "github.com/gogits/go-gogs-client"
+	api "github.com/gogs/go-gogs-client"
 
 	"github.com/G-Node/gogs/models/errors"
 	"github.com/G-Node/gogs/pkg/avatar"
@@ -42,7 +42,7 @@ const USER_AVATAR_URL_PREFIX = "avatars"
 type UserType int
 
 const (
-	USER_TYPE_INDIVIDUAL   UserType = iota // Historic reason to make it starts at 0.
+	USER_TYPE_INDIVIDUAL UserType = iota // Historic reason to make it starts at 0.
 	USER_TYPE_ORGANIZATION
 )
 
@@ -53,10 +53,10 @@ type User struct {
 	Name      string `xorm:"UNIQUE NOT NULL"`
 	FullName  string
 	// Email is the primary email address (to be used for communication)
-	Email       string        `xorm:"NOT NULL"`
-	Passwd      string        `xorm:"NOT NULL"`
+	Email       string `xorm:"NOT NULL"`
+	Passwd      string `xorm:"NOT NULL"`
 	LoginType   LoginType
-	LoginSource int64         `xorm:"NOT NULL DEFAULT 0"`
+	LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
 	LoginName   string
 	Type        UserType
 	OwnedOrgs   []*User       `xorm:"-" json:"-"`
@@ -64,8 +64,8 @@ type User struct {
 	Repos       []*Repository `xorm:"-" json:"-"`
 	Location    string
 	Website     string
-	Rands       string        `xorm:"VARCHAR(10)"`
-	Salt        string        `xorm:"VARCHAR(10)"`
+	Rands       string `xorm:"VARCHAR(10)"`
+	Salt        string `xorm:"VARCHAR(10)"`
 
 	Created     time.Time `xorm:"-" json:"-"`
 	CreatedUnix int64
@@ -135,8 +135,8 @@ func (u *User) APIFormat() *api.User {
 		UserName:  u.Name,
 		Login:     u.Name,
 		FullName:  u.FullName,
-		AvatarUrl: u.AvatarLink(),
 		Email:     u.Email,
+		AvatarUrl: u.AvatarLink(),
 	}
 }
 

文件差异内容过多而无法显示
+ 0 - 0
pkg/bindata/bindata.go


+ 2 - 2
pkg/context/user.go

@@ -7,8 +7,8 @@ package context
 import (
 	"gopkg.in/macaron.v1"
 
-	"github.com/gogs/gogs/models"
-	"github.com/gogs/gogs/models/errors"
+	"github.com/G-Node/gogs/models"
+	"github.com/G-Node/gogs/models/errors"
 )
 
 // ParamsUser is the wrapper type of the target user defined by URL parameter, namely ':username'.

+ 25 - 18
pkg/template/template.go

@@ -14,7 +14,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/json-iterator/go"
+	jsoniter "github.com/json-iterator/go"
 	"github.com/microcosm-cc/bluemonday"
 	"golang.org/x/net/html/charset"
 	"golang.org/x/text/transform"
@@ -22,9 +22,9 @@ import (
 	"gopkg.in/editorconfig/editorconfig-core-go.v1"
 
 	"github.com/G-Node/gogs/models"
-	"github.com/G-Node/gogs/pkg/tool"
 	"github.com/G-Node/gogs/pkg/markup"
 	"github.com/G-Node/gogs/pkg/setting"
+	"github.com/G-Node/gogs/pkg/tool"
 )
 
 // TODO: only initialize map once and save to a local variable to reduce copies.
@@ -60,15 +60,17 @@ func NewFuncMap() []template.FuncMap {
 		"LoadTimes": func(startTime time.Time) string {
 			return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
 		},
-		"AvatarLink":   tool.AvatarLink,
-		"Safe":         Safe,
-		"Sanitize":     bluemonday.UGCPolicy().Sanitize,
-		"Str2html":     Str2html,
-		"Str2JS":       Str2JS,
-		"TimeSince":    tool.TimeSince,
-		"RawTimeSince": tool.RawTimeSince,
-		"FileSize":     tool.FileSize,
-		"Subtract":     tool.Subtract,
+		"AvatarLink":       tool.AvatarLink,
+		"AppendAvatarSize": tool.AppendAvatarSize,
+		"Safe":             Safe,
+		"Sanitize":         bluemonday.UGCPolicy().Sanitize,
+		"Str2HTML":         Str2HTML,
+		"Str2JS":           Str2JS,
+		"NewLine2br":       NewLine2br,
+		"TimeSince":        tool.TimeSince,
+		"RawTimeSince":     tool.RawTimeSince,
+		"FileSize":         tool.FileSize,
+		"Subtract":         tool.Subtract,
 		"Add": func(a, b int) int {
 			return a + b
 		},
@@ -93,13 +95,13 @@ func NewFuncMap() []template.FuncMap {
 			}
 			return str[start:end]
 		},
-		"Join":              strings.Join,
-		"EllipsisString":    tool.EllipsisString,
-		"DiffTypeToStr":     DiffTypeToStr,
-		"DiffLineTypeToStr": DiffLineTypeToStr,
-		"Sha1":              Sha1,
-		"ShortSHA1":         tool.ShortSHA1,
-		"MD5":               tool.MD5,
+		"Join":                  strings.Join,
+		"EllipsisString":        tool.EllipsisString,
+		"DiffTypeToStr":         DiffTypeToStr,
+		"DiffLineTypeToStr":     DiffLineTypeToStr,
+		"Sha1":                  Sha1,
+		"ShortSHA1":             tool.ShortSHA1,
+		"MD5":                   tool.MD5,
 		"ActionContent2Commits": ActionContent2Commits,
 		"EscapePound":           EscapePound,
 		"RenderCommitMessage":   RenderCommitMessage,
@@ -130,6 +132,11 @@ func Str2HTML(raw string) template.HTML {
 	return template.HTML(markup.Sanitize(raw))
 }
 
+// NewLine2br simply replaces "\n" to "<br>".
+func NewLine2br(raw string) string {
+	return strings.Replace(raw, "\n", "<br>", -1)
+}
+
 func Str2JS(raw string) template.JS {
 	return template.JS(raw)
 }

+ 48 - 3
public/js/gogs.js

@@ -509,14 +509,21 @@ function initRepository() {
     if ($('.repository.compare.pull').length > 0) {
         initFilterSearchDropdown('.choose.branch .dropdown');
     }
-
+    if ($('.repository.view.pull').length > 0) {
+        $('.comment.merge.box input[name=merge_style]').change(function () {
+            if ($(this).val() === 'create_merge_commit') {
+                $('.commit.description.field').show();
+            } else {
+                $('.commit.description.field').hide();
+            }
+        })
+    }
     if ($('#download-repo-button')) {
         $('#download-repo-button').click(function () {
             $('#download_modal')
                 .modal('show');
-        });
+        })
     }
-    ;
 }
 
 function initWikiForm() {
@@ -1567,6 +1574,44 @@ $(function () {
     $('form').areYouSure();
 });
 
+// getByteLen counts bytes in a string's UTF-8 representation.
+function getByteLen(normalVal) {
+    // Force string type
+    normalVal = String(normalVal);
+
+    var byteLen = 0;
+    for (var i = 0; i < normalVal.length; i++) {
+        var c = normalVal.charCodeAt(i);
+        byteLen += c < (1 << 7) ? 1 :
+            c < (1 << 11) ? 2 :
+                c < (1 << 16) ? 3 :
+                    c < (1 << 21) ? 4 :
+                        c < (1 << 26) ? 5 :
+                            c < (1 << 31) ? 6 : Number.NaN;
+    }
+    return byteLen;
+}
+
+function showMessageMaxLength(maxLen, textElemId, counterId) {
+    var $msg = $('#' + textElemId);
+    $('#' + counterId).html(maxLen - getByteLen($msg.val()));
+
+    var onMessageKey = function (e) {
+        var $msg = $(this);
+        var text = $msg.val();
+        var len = getByteLen(text);
+        var remainder = maxLen - len;
+
+        if (len >= maxLen) {
+            $msg.val($msg.val().substr(0, maxLen));
+            remainder = 0;
+        }
+
+        $('#' + counterId).html(remainder);
+    };
+
+    $msg.keyup(onMessageKey).keydown(onMessageKey);
+}
 
 function OdmlEditor() {
 	var docSpec = {

+ 4 - 2
routes/api/v1/api.go

@@ -11,7 +11,7 @@ import (
 	"github.com/go-macaron/binding"
 	"gopkg.in/macaron.v1"
 
-	api "github.com/gogits/go-gogs-client"
+	api "github.com/gogs/go-gogs-client"
 
 	"github.com/G-Node/gogs/models"
 	"github.com/G-Node/gogs/models/errors"
@@ -21,8 +21,8 @@ import (
 	"github.com/G-Node/gogs/routes/api/v1/misc"
 	"github.com/G-Node/gogs/routes/api/v1/org"
 	"github.com/G-Node/gogs/routes/api/v1/repo"
-	"github.com/G-Node/gogs/routes/api/v1/user"
 	"github.com/G-Node/gogs/routes/api/v1/search"
+	"github.com/G-Node/gogs/routes/api/v1/user"
 )
 
 func repoAssignment() macaron.Handler {
@@ -226,6 +226,8 @@ func RegisterRoutes(m *macaron.Macaron) {
 
 		m.Group("/repos", func() {
 			m.Get("/search", repo.Search)
+
+			m.Get("/:username/:reponame", repoAssignment(), repo.Get)
 			m.Get("/suggest/:querry", search.Suggest)
 		})
 

+ 4 - 4
routes/api/v1/repo/commits.go

@@ -12,10 +12,10 @@ import (
 	"github.com/gogs/git-module"
 	api "github.com/gogs/go-gogs-client"
 
-	"github.com/gogs/gogs/models"
-	"github.com/gogs/gogs/models/errors"
-	"github.com/gogs/gogs/pkg/context"
-	"github.com/gogs/gogs/pkg/setting"
+	"github.com/G-Node/gogs/models"
+	"github.com/G-Node/gogs/models/errors"
+	"github.com/G-Node/gogs/pkg/context"
+	"github.com/G-Node/gogs/pkg/setting"
 )
 
 func GetSingleCommit(c *context.APIContext) {

+ 5 - 5
routes/repo/editor.go

@@ -13,16 +13,18 @@ import (
 
 	log "gopkg.in/clog.v1"
 
+	"path/filepath"
+
 	"github.com/G-Node/git-module"
 	"github.com/G-Node/gogs/models"
+	"github.com/G-Node/gogs/models/errors"
+	"github.com/G-Node/gogs/pkg/bindata"
 	"github.com/G-Node/gogs/pkg/context"
 	"github.com/G-Node/gogs/pkg/form"
+	"github.com/G-Node/gogs/pkg/markup"
 	"github.com/G-Node/gogs/pkg/setting"
 	"github.com/G-Node/gogs/pkg/template"
 	"github.com/G-Node/gogs/pkg/tool"
-	"github.com/G-Node/gogs/pkg/markup"
-	"github.com/G-Node/gogs/pkg/bindata"
-	"path/filepath"
 )
 
 const (
@@ -80,7 +82,6 @@ func editFile(c *context.Context, isNewFile bool) {
 		c.Data["IsJSON"] = markup.IsJSON(blob.Name())
 		c.Data["IsYAML"] = markup.IsYAML(blob.Name())
 
-
 		buf := make([]byte, 1024)
 		n, _ := dataRc.Read(buf)
 		buf = buf[:n]
@@ -124,7 +125,6 @@ func editFile(c *context.Context, isNewFile bool) {
 	c.Success(EDIT_FILE)
 }
 
-
 func EditFile(c *context.Context) {
 	editFile(c, false)
 }

+ 0 - 1
routes/repo/setting.go

@@ -11,7 +11,6 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
-	"github.com/gogs/git-module"
 	log "gopkg.in/clog.v1"
 
 	"github.com/G-Node/git-module"

+ 5 - 1
routes/repo/view.go

@@ -18,7 +18,7 @@ import (
 	"strings"
 
 	"github.com/G-Node/git-module"
-	"github.com/G-Node/go-annex"
+	gannex "github.com/G-Node/go-annex"
 	"github.com/G-Node/godML/odml"
 	"github.com/G-Node/gogs/models"
 	"github.com/G-Node/gogs/pkg/context"
@@ -312,6 +312,10 @@ func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink stri
 			}
 			var output bytes.Buffer
 			lines := strings.Split(fileContent, "\n")
+			// Remove blank line at the end of file
+			if len(lines) > 0 && len(lines[len(lines)-1]) == 0 {
+				lines = lines[:len(lines)-1]
+			}
 			if len(lines) > setting.UI.MaxLineHighlight {
 				c.Data["HighlightClass"] = "nohighlight"
 			}

+ 1 - 1
templates/explore/blob_list.tmpl

@@ -24,7 +24,7 @@
 		<div class="ui divided list">
 			{{range .Highlight.Content}}
 			<div class="item">
-				{{. | Str2html}}
+				{{. | Str2HTML}}
 			</div>
 			{{end}}
 			{{end}}

+ 1 - 1
templates/repo/bare.tmpl

@@ -20,7 +20,7 @@
 							</div>
 						</div>
 						<div class="item">
-							<h3>Or  {{.i18n.Tr "repo.clone_this_repo"}} <small>{{.i18n.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2html}}</small></h3>
+							<h3>Or  {{.i18n.Tr "repo.clone_this_repo"}} <small>{{.i18n.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository" | Str2HTML}}</small></h3>
 							<div class="ui action small input">
 								{{if not $.DisableHTTP}}
 									<button class="ui basic clone button" id="repo-clone-https" data-link="{{.CloneLink.HTTPS}}">

+ 14 - 13
templates/repo/create.tmpl

@@ -24,10 +24,10 @@
 									{{.LoggedUser.ShortName 20}}
 								</div>
 								{{range .Orgs}}
-								<div class="item" data-value="{{.ID}}">
-									<img class="ui mini image" src="{{.RelAvatarLink}}">
-									{{.ShortName 20}}
-								</div>
+									<div class="item" data-value="{{.ID}}">
+										<img class="ui mini image" src="{{.RelAvatarLink}}">
+										{{.ShortName 20}}
+									</div>
 								{{end}}
 							</div>
 						</div>
@@ -42,17 +42,17 @@
 						<label>{{.i18n.Tr "repo.visibility"}}</label>
 						<div class="ui checkbox">
 							{{if .IsForcedPrivate}}
-							<input name="private" type="checkbox" checked readonly>
-							<label>{{.i18n.Tr "repo.visiblity_helper_forced" | Safe}}</label>
+								<input name="private" type="checkbox" checked readonly>
+								<label>{{.i18n.Tr "repo.visiblity_helper_forced" | Safe}}</label>
 							{{else}}
-							<input name="private" type="checkbox" {{if .private}}checked{{end}}>
-							<label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label>
+								<input name="private" type="checkbox" {{if .private}}checked{{end}}>
+								<label>{{.i18n.Tr "repo.visiblity_helper" | Safe}}</label>
 							{{end}}
 						</div>
 					</div>
 					<div class="inline field {{if .Err_Description}}error{{end}}">
 						<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label>
-						<textarea id="description" name="description">{{.description}}</textarea>
+						<textarea class="autosize" id="description" name="description" rows="3">{{.description}}</textarea>
 						<span class="help">{{.i18n.Tr "repo.repo_desc_helper" | Safe}}</span>
 
 					</div>
@@ -69,7 +69,7 @@
 							<div class="default text">{{.i18n.Tr "repo.repo_gitignore_helper"}}</div>
 							<div class="menu">
 								{{range .Gitignores}}
-								<div class="item" data-value="{{.}}">{{.}}</div>
+									<div class="item" data-value="{{.}}">{{.}}</div>
 								{{end}}
 							</div>
 						</div>
@@ -85,7 +85,7 @@
 							<div class="default text">{{.i18n.Tr "repo.license_helper"}}</div>
 							<div class="menu">
 								{{range .Licenses}}
-								<div class="item" data-value="{{.}}">{{.}}</div>
+									<div class="item" data-value="{{.}}">{{.}}</div>
 								{{end}}
 								<div class="item" data-value="">None</div>
 							</div>
@@ -99,7 +99,7 @@
 							<div class="default text">{{.i18n.Tr "repo.readme_helper"}}</div>
 							<div class="menu">
 								{{range .Readmes}}
-								<div class="item" data-value="{{.}}">{{.}}</div>
+									<div class="item" data-value="{{.}}">{{.}}</div>
 								{{end}}
 							</div>
 						</div>
@@ -123,4 +123,5 @@
 		</div>
 	</div>
 </div>
-	{{template "base/footer" .}}
+
+{{template "base/footer" .}}

+ 1 - 1
templates/repo/view_file.tmpl

@@ -44,7 +44,7 @@
 	<div class="{{if or .IsJSON (or .IsYAML .IsOdML)}}ui bottom attached tab {{if .IsOdML}} active{{end}} segment" data-tab="view{{else}}ui attached table segment{{end}}">
 		<div id="{{if not (or .IsJSON .IsYAML)}}{{if .IsIPythonNotebook}}ipython-notebook{{end}}" class="file-view {{if .IsMarkdown}}markdown{{else if .IsIPythonNotebook}}ipython-notebook{{else if .IsIPythonNotebook}}ipython-notebook{{else if .ReadmeInList}}plain-text{{else if and .IsTextFile}}code-view{{end}} has-emoji{{end}}">
 			{{if .IsMarkdown}}
-				{{if .FileContent}}{{.FileContent | Str2html}}{{end}}
+				{{if .FileContent}}{{.FileContent | Str2HTML}}{{end}}
 			{{else if .IsOdML}}
 			<div class="ui fluid input">
 				<input class="search-input form-control" placeholder="Search"></input>

+ 1 - 1
templates/repo/wiki/view.tmpl

@@ -51,7 +51,7 @@
 		</div>
 	<div class="ui dividing header"></div>
 		<div class="markdown">
-			{{.content | Str2html}}
+			{{.content | Str2HTML}}
 		</div>
 	<div class="ui dividing header"></div>
 	<div class="ui dividing header">

部分文件因为文件数量过多而无法显示