diff options
author | Emrah URHAN <raxetul@gmail.com> | 2015-11-22 19:40:18 +0200 |
---|---|---|
committer | Emrah URHAN <raxetul@gmail.com> | 2015-11-22 19:40:18 +0200 |
commit | 737da1a3748d7c82af771d3ba4aa4c76ba219eee (patch) | |
tree | b59104944ba28771752adcc1231a847b6704ac4d /models | |
parent | f63a468dfce812423b78a47cfa2583c5ad2faa49 (diff) | |
parent | efaf60ba5a4a7c0954dbaf57203859db3258281f (diff) |
Latest develop updates is merged with my RaspberryPi Dockerfile version.
Merge branch 'develop' of https://github.com/gogits/gogs into develop
Diffstat (limited to 'models')
-rw-r--r-- | models/access.go | 48 | ||||
-rw-r--r-- | models/action.go | 85 | ||||
-rw-r--r-- | models/error.go | 112 | ||||
-rw-r--r-- | models/git_diff.go | 42 | ||||
-rw-r--r-- | models/issue.go | 22 | ||||
-rw-r--r-- | models/login.go | 7 | ||||
-rw-r--r-- | models/migrations/migrations.go | 53 | ||||
-rw-r--r-- | models/models.go | 2 | ||||
-rw-r--r-- | models/publickey.go | 141 | ||||
-rw-r--r-- | models/pull.go | 66 | ||||
-rw-r--r-- | models/release.go | 83 | ||||
-rw-r--r-- | models/repo.go | 197 | ||||
-rw-r--r-- | models/update.go | 40 | ||||
-rw-r--r-- | models/user.go | 56 | ||||
-rw-r--r-- | models/webhook.go | 4 |
15 files changed, 685 insertions, 273 deletions
diff --git a/models/access.go b/models/access.go index fe8bf2c1..5eef3281 100644 --- a/models/access.go +++ b/models/access.go @@ -36,19 +36,19 @@ func accessLevel(e Engine, u *User, repo *Repository) (AccessMode, error) { mode = ACCESS_MODE_READ } - if u != nil { - if u.Id == repo.OwnerID { - return ACCESS_MODE_OWNER, nil - } + if u == nil { + return mode, nil + } - a := &Access{UserID: u.Id, RepoID: repo.ID} - if has, err := e.Get(a); !has || err != nil { - return mode, err - } - return a.Mode, nil + if u.Id == repo.OwnerID { + return ACCESS_MODE_OWNER, nil } - return mode, nil + a := &Access{UserID: u.Id, RepoID: repo.ID} + if has, err := e.Get(a); !has || err != nil { + return mode, err + } + return a.Mode, nil } // AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the @@ -67,9 +67,8 @@ func HasAccess(u *User, repo *Repository, testMode AccessMode) (bool, error) { return hasAccess(x, u, repo, testMode) } -// GetAccessibleRepositories finds all repositories where a user has access to, -// besides he/she owns. -func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { +// GetRepositoryAccesses finds all repositories with their access mode where a user has access but does not own. +func (u *User) GetRepositoryAccesses() (map[*Repository]AccessMode, error) { accesses := make([]*Access, 0, 10) if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil { return nil, err @@ -80,7 +79,7 @@ func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { repo, err := GetRepositoryByID(access.RepoID) if err != nil { if IsErrRepoNotExist(err) { - log.Error(4, "%v", err) + log.Error(4, "GetRepositoryByID: %v", err) continue } return nil, err @@ -92,11 +91,28 @@ func (u *User) GetAccessibleRepositories() (map[*Repository]AccessMode, error) { } repos[repo] = access.Mode } - - // FIXME: should we generate an ordered list here? Random looks weird. return repos, nil } +// GetAccessibleRepositories finds all repositories where a user has access but does not own. +func (u *User) GetAccessibleRepositories() ([]*Repository, error) { + accesses := make([]*Access, 0, 10) + if err := x.Find(&accesses, &Access{UserID: u.Id}); err != nil { + return nil, err + } + + if len(accesses) == 0 { + return []*Repository{}, nil + } + + repoIDs := make([]int64, 0, len(accesses)) + for _, access := range accesses { + repoIDs = append(repoIDs, access.RepoID) + } + repos := make([]*Repository, 0, len(repoIDs)) + return repos, x.Where("owner_id != ?", u.Id).In("id", repoIDs).Desc("updated").Find(&repos) +} + func maxAccessMode(modes ...AccessMode) AccessMode { max := ACCESS_MODE_NONE for _, mode := range modes { diff --git a/models/action.go b/models/action.go index e38cf593..8dd80074 100644 --- a/models/action.go +++ b/models/action.go @@ -14,6 +14,7 @@ import ( "time" "unicode" + "github.com/Unknwon/com" "github.com/go-xorm/xorm" api "github.com/gogits/go-gogs-client" @@ -136,6 +137,26 @@ func (a Action) GetIssueInfos() []string { return strings.SplitN(a.Content, "|", 2) } +func (a Action) GetIssueTitle() string { + index := com.StrTo(a.GetIssueInfos()[0]).MustInt64() + issue, err := GetIssueByIndex(a.RepoID, index) + if err != nil { + log.Error(4, "GetIssueByIndex: %v", err) + return "500 when get issue" + } + return issue.Name +} + +func (a Action) GetIssueContent() string { + index := com.StrTo(a.GetIssueInfos()[0]).MustInt64() + issue, err := GetIssueByIndex(a.RepoID, index) + if err != nil { + log.Error(4, "GetIssueByIndex: %v", err) + return "500 when get issue" + } + return issue.Content +} + func newRepoAction(e Engine, u *User, repo *Repository) (err error) { if err = notifyWatchers(e, &Action{ ActUserID: u.Id, @@ -147,7 +168,7 @@ func newRepoAction(e Engine, u *User, repo *Repository) (err error) { RepoName: repo.Name, IsPrivate: repo.IsPrivate, }); err != nil { - return fmt.Errorf("notify watchers '%d/%s': %v", u.Id, repo.ID, err) + return fmt.Errorf("notify watchers '%d/%d': %v", u.Id, repo.ID, err) } log.Trace("action.newRepoAction: %s/%s", u.Name, repo.Name) @@ -187,8 +208,48 @@ func issueIndexTrimRight(c rune) bool { return !unicode.IsDigit(c) } +type PushCommit struct { + Sha1 string + Message string + AuthorEmail string + AuthorName string +} + +type PushCommits struct { + Len int + Commits []*PushCommit + CompareUrl string + + avatars map[string]string +} + +func NewPushCommits() *PushCommits { + return &PushCommits{ + avatars: make(map[string]string), + } +} + +// AvatarLink tries to match user in database with e-mail +// in order to show custom avatar, and falls back to general avatar link. +func (push *PushCommits) AvatarLink(email string) string { + _, ok := push.avatars[email] + if !ok { + u, err := GetUserByEmail(email) + if err != nil { + push.avatars[email] = base.AvatarLink(email) + if !IsErrUserNotExist(err) { + log.Error(4, "GetUserByEmail: %v", err) + } + } else { + push.avatars[email] = u.AvatarLink() + } + } + + return push.avatars[email] +} + // updateIssuesCommit checks if issues are manipulated by commit message. -func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string, commits []*base.PushCommit) error { +func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string, commits []*PushCommit) error { // Commits are appended in the reverse order. for i := len(commits) - 1; i >= 0; i-- { c := commits[i] @@ -322,7 +383,7 @@ func CommitRepoAction( repoID int64, repoUserName, repoName string, refFullName string, - commit *base.PushCommits, + commit *PushCommits, oldCommitID string, newCommitID string) error { u, err := GetUserByID(userID) @@ -337,12 +398,18 @@ func CommitRepoAction( return fmt.Errorf("GetOwner: %v", err) } + // Change repository bare status and update last updated time. + repo.IsBare = false + if err = UpdateRepository(repo, false); err != nil { + return fmt.Errorf("UpdateRepository: %v", err) + } + isNewBranch := false opType := COMMIT_REPO // Check it's tag push or branch. if strings.HasPrefix(refFullName, "refs/tags/") { opType = PUSH_TAG - commit = &base.PushCommits{} + commit = &PushCommits{} } else { // if not the first commit, set the compareUrl if !strings.HasPrefix(oldCommitID, "0000000") { @@ -351,12 +418,10 @@ func CommitRepoAction( isNewBranch = true } - // Change repository bare status and update last updated time. - repo.IsBare = false - if err = UpdateRepository(repo, false); err != nil { - return fmt.Errorf("UpdateRepository: %v", err) + // NOTE: limit to detect latest 100 commits. + if len(commit.Commits) > 100 { + commit.Commits = commit.Commits[len(commit.Commits)-100:] } - if err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits); err != nil { log.Error(4, "updateIssuesCommit: %v", err) } @@ -488,7 +553,7 @@ func transferRepoAction(e Engine, actUser, oldOwner, newOwner *User, repo *Repos IsPrivate: repo.IsPrivate, Content: path.Join(oldOwner.LowerName, repo.LowerName), }); err != nil { - return fmt.Errorf("notify watchers '%d/%s': %v", actUser.Id, repo.ID, err) + return fmt.Errorf("notify watchers '%d/%d': %v", actUser.Id, repo.ID, err) } // Remove watch for organization. diff --git a/models/error.go b/models/error.go index f6973258..069346be 100644 --- a/models/error.go +++ b/models/error.go @@ -18,7 +18,7 @@ func IsErrNameReserved(err error) bool { } func (err ErrNameReserved) Error() string { - return fmt.Sprintf("name is reserved: [name: %s]", err.Name) + return fmt.Sprintf("name is reserved [name: %s]", err.Name) } type ErrNamePatternNotAllowed struct { @@ -31,7 +31,7 @@ func IsErrNamePatternNotAllowed(err error) bool { } func (err ErrNamePatternNotAllowed) Error() string { - return fmt.Sprintf("name pattern is not allowed: [pattern: %s]", err.Pattern) + return fmt.Sprintf("name pattern is not allowed [pattern: %s]", err.Pattern) } // ____ ___ @@ -51,7 +51,7 @@ func IsErrUserAlreadyExist(err error) bool { } func (err ErrUserAlreadyExist) Error() string { - return fmt.Sprintf("user already exists: [name: %s]", err.Name) + return fmt.Sprintf("user already exists [name: %s]", err.Name) } type ErrUserNotExist struct { @@ -65,7 +65,7 @@ func IsErrUserNotExist(err error) bool { } func (err ErrUserNotExist) Error() string { - return fmt.Sprintf("user does not exist: [uid: %d, name: %s]", err.UID, err.Name) + return fmt.Sprintf("user does not exist [uid: %d, name: %s]", err.UID, err.Name) } type ErrEmailAlreadyUsed struct { @@ -78,7 +78,7 @@ func IsErrEmailAlreadyUsed(err error) bool { } func (err ErrEmailAlreadyUsed) Error() string { - return fmt.Sprintf("e-mail has been used: [email: %s]", err.Email) + return fmt.Sprintf("e-mail has been used [email: %s]", err.Email) } type ErrUserOwnRepos struct { @@ -91,7 +91,7 @@ func IsErrUserOwnRepos(err error) bool { } func (err ErrUserOwnRepos) Error() string { - return fmt.Sprintf("user still has ownership of repositories: [uid: %d]", err.UID) + return fmt.Sprintf("user still has ownership of repositories [uid: %d]", err.UID) } type ErrUserHasOrgs struct { @@ -104,7 +104,7 @@ func IsErrUserHasOrgs(err error) bool { } func (err ErrUserHasOrgs) Error() string { - return fmt.Sprintf("user still has membership of organizations: [uid: %d]", err.UID) + return fmt.Sprintf("user still has membership of organizations [uid: %d]", err.UID) } // __________ ___. .__ .__ ____ __. @@ -114,6 +114,19 @@ func (err ErrUserHasOrgs) Error() string { // |____| |____/|___ /____/__|\___ > |____|__ \___ > ____| // \/ \/ \/ \/\/ +type ErrKeyUnableVerify struct { + Result string +} + +func IsErrKeyUnableVerify(err error) bool { + _, ok := err.(ErrKeyUnableVerify) + return ok +} + +func (err ErrKeyUnableVerify) Error() string { + return fmt.Sprintf("Unable to verify key content [result: %s]", err.Result) +} + type ErrKeyNotExist struct { ID int64 } @@ -124,7 +137,7 @@ func IsErrKeyNotExist(err error) bool { } func (err ErrKeyNotExist) Error() string { - return fmt.Sprintf("public key does not exist: [id: %d]", err.ID) + return fmt.Sprintf("public key does not exist [id: %d]", err.ID) } type ErrKeyAlreadyExist struct { @@ -138,7 +151,7 @@ func IsErrKeyAlreadyExist(err error) bool { } func (err ErrKeyAlreadyExist) Error() string { - return fmt.Sprintf("public key already exists: [owner_id: %d, content: %s]", err.OwnerID, err.Content) + return fmt.Sprintf("public key already exists [owner_id: %d, content: %s]", err.OwnerID, err.Content) } type ErrKeyNameAlreadyUsed struct { @@ -152,7 +165,22 @@ func IsErrKeyNameAlreadyUsed(err error) bool { } func (err ErrKeyNameAlreadyUsed) Error() string { - return fmt.Sprintf("public key already exists: [owner_id: %d, name: %s]", err.OwnerID, err.Name) + return fmt.Sprintf("public key already exists [owner_id: %d, name: %s]", err.OwnerID, err.Name) +} + +type ErrDeployKeyNotExist struct { + ID int64 + KeyID int64 + RepoID int64 +} + +func IsErrDeployKeyNotExist(err error) bool { + _, ok := err.(ErrDeployKeyNotExist) + return ok +} + +func (err ErrDeployKeyNotExist) Error() string { + return fmt.Sprintf("Deploy key does not exist [id: %d, key_id: %d, repo_id: %d]", err.ID, err.KeyID, err.RepoID) } type ErrDeployKeyAlreadyExist struct { @@ -166,7 +194,7 @@ func IsErrDeployKeyAlreadyExist(err error) bool { } func (err ErrDeployKeyAlreadyExist) Error() string { - return fmt.Sprintf("public key already exists: [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID) + return fmt.Sprintf("public key already exists [key_id: %d, repo_id: %d]", err.KeyID, err.RepoID) } type ErrDeployKeyNameAlreadyUsed struct { @@ -180,7 +208,7 @@ func IsErrDeployKeyNameAlreadyUsed(err error) bool { } func (err ErrDeployKeyNameAlreadyUsed) Error() string { - return fmt.Sprintf("public key already exists: [repo_id: %d, name: %s]", err.RepoID, err.Name) + return fmt.Sprintf("public key already exists [repo_id: %d, name: %s]", err.RepoID, err.Name) } // _____ ___________ __ @@ -200,7 +228,7 @@ func IsErrAccessTokenNotExist(err error) bool { } func (err ErrAccessTokenNotExist) Error() string { - return fmt.Sprintf("access token does not exist: [sha: %s]", err.SHA) + return fmt.Sprintf("access token does not exist [sha: %s]", err.SHA) } // ________ .__ __ .__ @@ -220,7 +248,7 @@ func IsErrLastOrgOwner(err error) bool { } func (err ErrLastOrgOwner) Error() string { - return fmt.Sprintf("user is the last member of owner team: [uid: %d]", err.UID) + return fmt.Sprintf("user is the last member of owner team [uid: %d]", err.UID) } // __________ .__ __ @@ -259,6 +287,62 @@ func (err ErrRepoAlreadyExist) Error() string { return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name) } +type ErrInvalidCloneAddr struct { + IsURLError bool + IsInvalidPath bool + IsPermissionDenied bool +} + +func IsErrInvalidCloneAddr(err error) bool { + _, ok := err.(ErrInvalidCloneAddr) + return ok +} + +func (err ErrInvalidCloneAddr) Error() string { + return fmt.Sprintf("invalid clone address [is_url_error: %v, is_invalid_path: %v, is_permission_denied: %v]", + err.IsURLError, err.IsInvalidPath, err.IsPermissionDenied) +} + +type ErrUpdateTaskNotExist struct { + UUID string +} + +func IsErrUpdateTaskNotExist(err error) bool { + _, ok := err.(ErrUpdateTaskNotExist) + return ok +} + +func (err ErrUpdateTaskNotExist) Error() string { + return fmt.Sprintf("update task does not exist [uuid: %s]", err.UUID) +} + +type ErrReleaseAlreadyExist struct { + TagName string +} + +func IsErrReleaseAlreadyExist(err error) bool { + _, ok := err.(ErrReleaseAlreadyExist) + return ok +} + +func (err ErrReleaseAlreadyExist) Error() string { + return fmt.Sprintf("Release tag already exist [tag_name: %s]", err.TagName) +} + +type ErrReleaseNotExist struct { + ID int64 + TagName string +} + +func IsErrReleaseNotExist(err error) bool { + _, ok := err.(ErrReleaseNotExist) + return ok +} + +func (err ErrReleaseNotExist) Error() string { + return fmt.Sprintf("Release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName) +} + // __ __ ___. .__ __ // / \ / \ ____\_ |__ | |__ ____ ____ | | __ // \ \/\/ // __ \| __ \| | \ / _ \ / _ \| |/ / diff --git a/models/git_diff.go b/models/git_diff.go index 2335e468..4b1ec09e 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -37,6 +37,7 @@ const ( DIFF_FILE_ADD = iota + 1 DIFF_FILE_CHANGE DIFF_FILE_DEL + DIFF_FILE_RENAME ) type DiffLine struct { @@ -57,12 +58,14 @@ type DiffSection struct { type DiffFile struct { Name string + OldName string Index int Addition, Deletion int Type int IsCreated bool IsDeleted bool IsBin bool + IsRenamed bool Sections []*DiffSection } @@ -94,7 +97,7 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff var i int for scanner.Scan() { line := scanner.Text() - // fmt.Println(i, line) + if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") { continue } @@ -158,17 +161,27 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff // Get new file. if strings.HasPrefix(line, DIFF_HEAD) { - beg := len(DIFF_HEAD) - a := line[beg : (len(line)-beg)/2+beg] + middle := -1 + + // Note: In case file name is surrounded by double quotes (it happens only in git-shell). + // e.g. diff --git "a/xxx" "b/xxx" + hasQuote := line[len(DIFF_HEAD)] == '"' + if hasQuote { + middle = strings.Index(line, ` "b/`) + } else { + middle = strings.Index(line, " b/") + } - // In case file name is surrounded by double quotes(it happens only in git-shell). - if a[0] == '"' { - a = a[1 : len(a)-1] - a = strings.Replace(a, `\"`, `"`, -1) + beg := len(DIFF_HEAD) + a := line[beg+2 : middle] + b := line[middle+3:] + if hasQuote { + a = string(git.UnescapeChars([]byte(a[1 : len(a)-1]))) + b = string(git.UnescapeChars([]byte(b[1 : len(b)-1]))) } curFile = &DiffFile{ - Name: a[strings.Index(a, "/")+1:], + Name: a, Index: len(diff.Files) + 1, Type: DIFF_FILE_CHANGE, Sections: make([]*DiffSection, 0, 10), @@ -180,16 +193,17 @@ func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff switch { case strings.HasPrefix(scanner.Text(), "new file"): curFile.Type = DIFF_FILE_ADD - curFile.IsDeleted = false curFile.IsCreated = true case strings.HasPrefix(scanner.Text(), "deleted"): curFile.Type = DIFF_FILE_DEL - curFile.IsCreated = false curFile.IsDeleted = true case strings.HasPrefix(scanner.Text(), "index"): curFile.Type = DIFF_FILE_CHANGE - curFile.IsCreated = false - curFile.IsDeleted = false + case strings.HasPrefix(scanner.Text(), "similarity index 100%"): + curFile.Type = DIFF_FILE_RENAME + curFile.IsRenamed = true + curFile.OldName = curFile.Name + curFile.Name = b } if curFile.Type > 0 { break @@ -244,10 +258,10 @@ func GetDiffRange(repoPath, beforeCommitId string, afterCommitId string, maxline cmd = exec.Command("git", "show", afterCommitId) } else { c, _ := commit.Parent(0) - cmd = exec.Command("git", "diff", c.Id.String(), afterCommitId) + cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitId) } } else { - cmd = exec.Command("git", "diff", beforeCommitId, afterCommitId) + cmd = exec.Command("git", "diff", "-M", beforeCommitId, afterCommitId) } cmd.Dir = repoPath cmd.Stdout = wr diff --git a/models/issue.go b/models/issue.go index 077e945c..cee8c36a 100644 --- a/models/issue.go +++ b/models/issue.go @@ -718,32 +718,28 @@ func GetIssueStats(opts *IssueStatsOptions) *IssueStats { if opts.AssigneeID > 0 { baseCond += " AND assignee_id=" + com.ToStr(opts.AssigneeID) } - if opts.IsPull { - baseCond += " AND issue.is_pull=1" - } else { - baseCond += " AND issue.is_pull=0" - } + baseCond += " AND issue.is_pull=?" switch opts.FilterMode { case FM_ALL, FM_ASSIGN: - results, _ := x.Query(queryStr+baseCond, false) + results, _ := x.Query(queryStr+baseCond, false, opts.IsPull) stats.OpenCount = parseCountResult(results) - results, _ = x.Query(queryStr+baseCond, true) + results, _ = x.Query(queryStr+baseCond, true, opts.IsPull) stats.ClosedCount = parseCountResult(results) case FM_CREATE: baseCond += " AND poster_id=?" - results, _ := x.Query(queryStr+baseCond, false, opts.UserID) + results, _ := x.Query(queryStr+baseCond, false, opts.IsPull, opts.UserID) stats.OpenCount = parseCountResult(results) - results, _ = x.Query(queryStr+baseCond, true, opts.UserID) + results, _ = x.Query(queryStr+baseCond, true, opts.IsPull, opts.UserID) stats.ClosedCount = parseCountResult(results) case FM_MENTION: queryStr += " INNER JOIN `issue_user` ON `issue`.id=`issue_user`.issue_id" baseCond += " AND `issue_user`.uid=? AND `issue_user`.is_mentioned=?" - results, _ := x.Query(queryStr+baseCond, false, opts.UserID, true) + results, _ := x.Query(queryStr+baseCond, false, opts.IsPull, opts.UserID, true) stats.OpenCount = parseCountResult(results) - results, _ = x.Query(queryStr+baseCond, true, opts.UserID, true) + results, _ = x.Query(queryStr+baseCond, true, opts.IsPull, opts.UserID, true) stats.ClosedCount = parseCountResult(results) } return stats @@ -1375,8 +1371,8 @@ func ChangeMilestoneAssign(oldMid int64, issue *Issue) (err error) { } // DeleteMilestoneByID deletes a milestone by given ID. -func DeleteMilestoneByID(mid int64) error { - m, err := GetMilestoneByID(mid) +func DeleteMilestoneByID(id int64) error { + m, err := GetMilestoneByID(id) if err != nil { if IsErrMilestoneNotExist(err) { return nil diff --git a/models/login.go b/models/login.go index 79a262c5..011d946a 100644 --- a/models/login.go +++ b/models/login.go @@ -225,10 +225,9 @@ func DeleteSource(source *LoginSource) error { // |_______ \/_______ /\____|__ /____| // \/ \/ \/ -// Query if name/passwd can login against the LDAP directory pool -// Create a local user if success -// Return the same LoginUserPlain semantic -// FIXME: https://github.com/gogits/gogs/issues/672 +// LoginUserLDAPSource queries if name/passwd can login against the LDAP directory pool, +// and create a local user if success when enabled. +// It returns the same LoginUserPlain semantic. func LoginUserLDAPSource(u *User, name, passwd string, source *LoginSource, autoRegister bool) (*User, error) { cfg := source.Cfg.(*LDAPConfig) directBind := (source.Type == DLDAP) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index c3f7a59b..0d17cf26 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "os" "path" + "path/filepath" "strings" "time" @@ -66,6 +67,7 @@ var migrations = []Migration{ NewMigration("generate issue-label from issue", issueToIssueLabel), // V6 -> V7:v0.6.4 NewMigration("refactor attachment table", attachmentRefactor), // V7 -> V8:v0.6.4 NewMigration("rename pull request fields", renamePullRequestFields), // V8 -> V9:v0.6.16 + NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo), // V9 -> V10:v0.6.20 } // Migrate database to current version @@ -454,7 +456,7 @@ func trimCommitActionAppUrlPrefix(x *xorm.Engine) error { pushCommits = new(PushCommits) if err = json.Unmarshal(action["content"], pushCommits); err != nil { - return fmt.Errorf("unmarshal action content[%s]: %v", actID, err) + return fmt.Errorf("unmarshal action content[%d]: %v", actID, err) } infos := strings.Split(pushCommits.CompareUrl, "/") @@ -465,7 +467,7 @@ func trimCommitActionAppUrlPrefix(x *xorm.Engine) error { p, err := json.Marshal(pushCommits) if err != nil { - return fmt.Errorf("marshal action content[%s]: %v", actID, err) + return fmt.Errorf("marshal action content[%d]: %v", actID, err) } if _, err = sess.Id(actID).Update(&Action{ @@ -653,3 +655,50 @@ func renamePullRequestFields(x *xorm.Engine) (err error) { return sess.Commit() } + +func cleanUpMigrateRepoInfo(x *xorm.Engine) (err error) { + type ( + User struct { + ID int64 `xorm:"pk autoincr"` + LowerName string + } + Repository struct { + ID int64 `xorm:"pk autoincr"` + OwnerID int64 + LowerName string + } + ) + + repos := make([]*Repository, 0, 25) + if err = x.Where("is_mirror=?", false).Find(&repos); err != nil { + return fmt.Errorf("select all non-mirror repositories: %v", err) + } + var user *User + for _, repo := range repos { + user = &User{ID: repo.OwnerID} + has, err := x.Get(user) + if err != nil { + return fmt.Errorf("get owner of repository[%d - %d]: %v", repo.ID, repo.OwnerID, err) + } else if !has { + continue + } + + configPath := filepath.Join(setting.RepoRootPath, user.LowerName, repo.LowerName+".git/config") + + // In case repository file is somehow missing. + if !com.IsFile(configPath) { + continue + } + + cfg, err := ini.Load(configPath) + if err != nil { + return fmt.Errorf("open config file: %v", err) + } + cfg.DeleteSection("remote \"origin\"") + if err = cfg.SaveToIndent(configPath, "\t"); err != nil { + return fmt.Errorf("save config file: %v", err) + } + } + + return nil +} diff --git a/models/models.go b/models/models.go index 802bc942..2249fee4 100644 --- a/models/models.go +++ b/models/models.go @@ -90,7 +90,7 @@ func init() { new(Team), new(OrgUser), new(TeamUser), new(TeamRepo), new(Notice), new(EmailAddress)) - gonicNames := []string{"UID", "SSL"} + gonicNames := []string{"SSL"} for _, name := range gonicNames { core.LintGonicMapper[name] = true } diff --git a/models/publickey.go b/models/publickey.go index 6c0ffc0c..b5646a55 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -13,7 +13,6 @@ import ( "io" "io/ioutil" "os" - "os/exec" "path" "path/filepath" "strings" @@ -33,25 +32,8 @@ const ( _TPL_PUBLICK_KEY = `command="%s serv key-%d --config='%s'",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n" ) -var ( - ErrKeyUnableVerify = errors.New("Unable to verify public key") -) - var sshOpLocker = sync.Mutex{} - -var ( - SSHPath string // SSH directory. - appPath string // Execution(binary) path. -) - -// exePath returns the executable path. -func exePath() (string, error) { - file, err := exec.LookPath(os.Args[0]) - if err != nil { - return "", err - } - return filepath.Abs(file) -} +var SSHPath string // SSH directory. // homeDir returns the home directory of current user. func homeDir() string { @@ -63,16 +45,9 @@ func homeDir() string { } func init() { - var err error - - if appPath, err = exePath(); err != nil { - log.Fatal(4, "fail to get app path: %v\n", err) - } - appPath = strings.Replace(appPath, "\\", "/", -1) - // Determine and create .ssh path. SSHPath = filepath.Join(homeDir(), ".ssh") - if err = os.MkdirAll(SSHPath, 0700); err != nil { + if err := os.MkdirAll(SSHPath, 0700); err != nil { log.Fatal(4, "fail to create '%s': %v", SSHPath, err) } } @@ -114,17 +89,7 @@ func (k *PublicKey) OmitEmail() string { // GetAuthorizedString generates and returns formatted public key string for authorized_keys file. func (key *PublicKey) GetAuthorizedString() string { - return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.ID, setting.CustomConf, key.Content) -} - -var minimumKeySizes = map[string]int{ - "(ED25519)": 256, - "(ECDSA)": 256, - "(NTRU)": 1087, - "(MCE)": 1702, - "(McE)": 1702, - "(RSA)": 1024, - "(DSA)": 1024, + return fmt.Sprintf(_TPL_PUBLICK_KEY, setting.AppPath, key.ID, setting.CustomConf, key.Content) } func extractTypeFromBase64Key(key string) (string, error) { @@ -228,9 +193,9 @@ func CheckPublicKeyString(content string) (_ string, err error) { tmpFile.Close() // Check if ssh-keygen recognizes its contents. - stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-l", "-f", tmpPath) + stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-lf", tmpPath) if err != nil { - return "", errors.New("ssh-keygen -l -f: " + stderr) + return "", errors.New("ssh-keygen -lf: " + stderr) } else if len(stdout) < 2 { return "", errors.New("ssh-keygen returned not enough output to evaluate the key: " + stdout) } @@ -242,7 +207,7 @@ func CheckPublicKeyString(content string) (_ string, err error) { sshKeygenOutput := strings.Split(stdout, " ") if len(sshKeygenOutput) < 4 { - return content, ErrKeyUnableVerify + return content, ErrKeyUnableVerify{stdout} } // Check if key type and key size match. @@ -251,9 +216,10 @@ func CheckPublicKeyString(content string) (_ string, err error) { if keySize == 0 { return "", errors.New("cannot get key size of the given key") } - keyType := strings.TrimSpace(sshKeygenOutput[len(sshKeygenOutput)-1]) - if minimumKeySize := minimumKeySizes[keyType]; minimumKeySize == 0 { - return "", errors.New("sorry, unrecognized public key type") + + keyType := strings.Trim(sshKeygenOutput[len(sshKeygenOutput)-1], " ()\n") + if minimumKeySize := setting.Service.MinimumKeySizes[keyType]; minimumKeySize == 0 { + return "", fmt.Errorf("unrecognized public key type: %s", keyType) } else if keySize < minimumKeySize { return "", fmt.Errorf("the minimum accepted size of a public key %s is %d", keyType, minimumKeySize) } @@ -321,9 +287,9 @@ func addKey(e Engine, key *PublicKey) (err error) { if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil { return err } - stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-l", "-f", tmpPath) + stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath) if err != nil { - return errors.New("ssh-keygen -l -f: " + stderr) + return errors.New("ssh-keygen -lf: " + stderr) } else if len(stdout) < 2 { return errors.New("not enough output for calculating fingerprint: " + stdout) } @@ -382,6 +348,19 @@ func GetPublicKeyByID(keyID int64) (*PublicKey, error) { return key, nil } +// SearchPublicKeyByContent searches content as prefix (leak e-mail part) +// and returns public key found. +func SearchPublicKeyByContent(content string) (*PublicKey, error) { + key := new(PublicKey) + has, err := x.Where("content like ?", content+"%").Get(key) + if err != nil { + return nil, err + } else if !has { + return nil, ErrKeyNotExist{} + } + return key, nil +} + // ListPublicKeys returns a list of public keys belongs to given user. func ListPublicKeys(uid int64) ([]*PublicKey, error) { keys := make([]*PublicKey, 0, 5) @@ -540,6 +519,7 @@ type DeployKey struct { RepoID int64 `xorm:"UNIQUE(s) INDEX"` Name string Fingerprint string + Content string `xorm:"-"` Created time.Time `xorm:"CREATED"` Updated time.Time // Note: Updated must below Created for AfterSet. HasRecentActivity bool `xorm:"-"` @@ -554,6 +534,16 @@ func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) { } } +// GetContent gets associated public key content. +func (k *DeployKey) GetContent() error { + pkey, err := GetPublicKeyByID(k.KeyID) + if err != nil { + return err + } + k.Content = pkey.Content + return nil +} + func checkDeployKey(e Engine, keyID, repoID int64, name string) error { // Note: We want error detail, not just true or false here. has, err := e.Where("key_id=? AND repo_id=?", keyID, repoID).Get(new(DeployKey)) @@ -574,18 +564,19 @@ func checkDeployKey(e Engine, keyID, repoID int64, name string) error { } // addDeployKey adds new key-repo relation. -func addDeployKey(e *xorm.Session, keyID, repoID int64, name, fingerprint string) (err error) { - if err = checkDeployKey(e, keyID, repoID, name); err != nil { - return err +func addDeployKey(e *xorm.Session, keyID, repoID int64, name, fingerprint string) (*DeployKey, error) { + if err := checkDeployKey(e, keyID, repoID, name); err != nil { + return nil, err } - _, err = e.Insert(&DeployKey{ + key := &DeployKey{ KeyID: keyID, RepoID: repoID, Name: name, Fingerprint: fingerprint, - }) - return err + } + _, err := e.Insert(key) + return key, err } // HasDeployKey returns true if public key is a deploy key of given repository. @@ -595,39 +586,52 @@ func HasDeployKey(keyID, repoID int64) bool { } // AddDeployKey add new deploy key to database and authorized_keys file. -func AddDeployKey(repoID int64, name, content string) (err error) { - if err = checkKeyContent(content); err != nil { - return err +func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) { + if err := checkKeyContent(content); err != nil { + return nil, err } - key := &PublicKey{ + pkey := &PublicKey{ Content: content, Mode: ACCESS_MODE_READ, Type: KEY_TYPE_DEPLOY, } - has, err := x.Get(key) + has, err := x.Get(pkey) if err != nil { - return err + return nil, err } sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { - return err + return nil, err } // First time use this deploy key. if !has { - if err = addKey(sess, key); err != nil { - return nil + if err = addKey(sess, pkey); err != nil { + return nil, fmt.Errorf("addKey: %v", err) } } - if err = addDeployKey(sess, key.ID, repoID, name, key.Fingerprint); err != nil { - return err + key, err := addDeployKey(sess, pkey.ID, repoID, name, pkey.Fingerprint) + if err != nil { + return nil, fmt.Errorf("addDeployKey: %v", err) } - return sess.Commit() + return key, sess.Commit() +} + +// GetDeployKeyByID returns deploy key by given ID. +func GetDeployKeyByID(id int64) (*DeployKey, error) { + key := new(DeployKey) + has, err := x.Id(id).Get(key) + if err != nil { + return nil, err + } else if !has { + return nil, ErrDeployKeyNotExist{id, 0, 0} + } + return key, nil } // GetDeployKeyByRepo returns deploy key by given public key ID and repository ID. @@ -636,8 +640,13 @@ func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) { KeyID: keyID, RepoID: repoID, } - _, err := x.Get(key) - return key, err + has, err := x.Get(key) + if err != nil { + return nil, err + } else if !has { + return nil, ErrDeployKeyNotExist{0, keyID, repoID} + } + return key, nil } // UpdateDeployKey updates deploy key information. diff --git a/models/pull.go b/models/pull.go index 0300c083..dfd80635 100644 --- a/models/pull.go +++ b/models/pull.go @@ -166,43 +166,49 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository) (err error var stderr string if _, stderr, err = process.ExecTimeout(5*time.Minute, - fmt.Sprintf("PullRequest.Merge(git clone): %s", tmpBasePath), + fmt.Sprintf("PullRequest.Merge (git clone): %s", tmpBasePath), "git", "clone", baseGitRepo.Path, tmpBasePath); err != nil { return fmt.Errorf("git clone: %s", stderr) } // Check out base branch. if _, stderr, err = process.ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge(git checkout): %s", tmpBasePath), + fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath), "git", "checkout", pr.BaseBranch); err != nil { return fmt.Errorf("git checkout: %s", stderr) } // Add head repo remote. if _, stderr, err = process.ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge(git remote add): %s", tmpBasePath), + fmt.Sprintf("PullRequest.Merge (git remote add): %s", tmpBasePath), "git", "remote", "add", "head_repo", headRepoPath); err != nil { - return fmt.Errorf("git remote add[%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + return fmt.Errorf("git remote add [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) } // Merge commits. if _, stderr, err = process.ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge(git fetch): %s", tmpBasePath), + fmt.Sprintf("PullRequest.Merge (git fetch): %s", tmpBasePath), "git", "fetch", "head_repo"); err != nil { - return fmt.Errorf("git fetch[%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) + return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) } if _, stderr, err = process.ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge(git merge): %s", tmpBasePath), - "git", "merge", "--no-ff", "-m", - fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch), - "head_repo/"+pr.HeadBranch); err != nil { - return fmt.Errorf("git merge[%s]: %s", tmpBasePath, stderr) + fmt.Sprintf("PullRequest.Merge (git merge --no-ff --no-commit): %s", tmpBasePath), + "git", "merge", "--no-ff", "--no-commit", "head_repo/"+pr.HeadBranch); err != nil { + return fmt.Errorf("git merge --no-ff --no-commit [%s]: %v - %s", tmpBasePath, err, stderr) + } + + sig := doer.NewGitSig() + if _, stderr, err = process.ExecDir(-1, tmpBasePath, + fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath), + "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), + "-m", fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch)); err != nil { + return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr) } // Push back to upstream. if _, stderr, err = process.ExecDir(-1, tmpBasePath, - fmt.Sprintf("PullRequest.Merge(git push): %s", tmpBasePath), + fmt.Sprintf("PullRequest.Merge (git push): %s", tmpBasePath), "git", "push", baseGitRepo.Path, pr.BaseBranch); err != nil { return fmt.Errorf("git push: %s", stderr) } @@ -218,6 +224,7 @@ var patchConflicts = []string{ } // testPatch checks if patch can be merged to base repository without conflit. +// FIXME: make a mechanism to clean up stable local copies. func (pr *PullRequest) testPatch() (err error) { if pr.BaseRepo == nil { pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID) @@ -243,14 +250,23 @@ func (pr *PullRequest) testPatch() (err error) { return fmt.Errorf("UpdateLocalCopy: %v", err) } - pr.Status = PULL_REQUEST_STATUS_CHECKING + // Checkout base branch. _, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(), + fmt.Sprintf("PullRequest.Merge(git checkout): %s", pr.BaseRepo.ID), + "git", "checkout", pr.BaseBranch) + if err != nil { + return fmt.Errorf("git checkout: %s", stderr) + } + + pr.Status = PULL_REQUEST_STATUS_CHECKING + _, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(), fmt.Sprintf("testPatch(git apply --check): %d", pr.BaseRepo.ID), "git", "apply", "--check", patchPath) if err != nil { for i := range patchConflicts { if strings.Contains(stderr, patchConflicts[i]) { log.Trace("PullRequest[%d].testPatch(apply): has conflit", pr.ID) + fmt.Println(stderr) pr.Status = PULL_REQUEST_STATUS_CONFLICT return nil } @@ -385,16 +401,18 @@ func (pr *PullRequest) UpdateCols(cols ...string) error { var PullRequestQueue = NewUniqueQueue(setting.Repository.PullRequestQueueLength) // UpdatePatch generates and saves a new patch. -func (pr *PullRequest) UpdatePatch() error { - if err := pr.GetHeadRepo(); err != nil { +func (pr *PullRequest) UpdatePatch() (err error) { + if err = pr.GetHeadRepo(); err != nil { return fmt.Errorf("GetHeadRepo: %v", err) } else if pr.HeadRepo == nil { log.Trace("PullRequest[%d].UpdatePatch: ignored cruppted data", pr.ID) return nil } - if err := pr.GetBaseRepo(); err != nil { + if err = pr.GetBaseRepo(); err != nil { return fmt.Errorf("GetBaseRepo: %v", err) + } else if err = pr.BaseRepo.GetOwner(); err != nil { + return fmt.Errorf("GetOwner: %v", err) } headRepoPath, err := pr.HeadRepo.RepoPath() @@ -407,6 +425,22 @@ func (pr *PullRequest) UpdatePatch() error { return fmt.Errorf("OpenRepository: %v", err) } + // Add a temporary remote. + tmpRemote := com.ToStr(time.Now().UnixNano()) + if err = headGitRepo.AddRemote(tmpRemote, RepoPath(pr.BaseRepo.Owner.Name, pr.BaseRepo.Name)); err != nil { + return fmt.Errorf("AddRemote: %v", err) + } + defer func() { + headGitRepo.RemoveRemote(tmpRemote) + }() + remoteBranch := "remotes/" + tmpRemote + "/" + pr.BaseBranch + pr.MergeBase, err = headGitRepo.GetMergeBase(remoteBranch, pr.HeadBranch) + if err != nil { + return fmt.Errorf("GetMergeBase: %v", err) + } else if err = pr.Update(); err != nil { + return fmt.Errorf("Update: %v", err) + } + patch, err := headGitRepo.GetPatch(pr.MergeBase, pr.HeadBranch) if err != nil { return fmt.Errorf("GetPatch: %v", err) diff --git a/models/release.go b/models/release.go index 027491d9..ef1d640d 100644 --- a/models/release.go +++ b/models/release.go @@ -5,7 +5,7 @@ package models import ( - "errors" + "fmt" "sort" "strings" "time" @@ -13,18 +13,14 @@ import ( "github.com/go-xorm/xorm" "github.com/gogits/gogs/modules/git" -) - -var ( - ErrReleaseAlreadyExist = errors.New("Release already exist") - ErrReleaseNotExist = errors.New("Release does not exist") + "github.com/gogits/gogs/modules/process" ) // Release represents a release of repository. type Release struct { - Id int64 - RepoId int64 - PublisherId int64 + ID int64 `xorm:"pk autoincr"` + RepoID int64 + PublisherID int64 Publisher *User `xorm:"-"` TagName string LowerTagName string @@ -47,12 +43,12 @@ func (r *Release) AfterSet(colName string, _ xorm.Cell) { } // IsReleaseExist returns true if release with given tag name already exists. -func IsReleaseExist(repoId int64, tagName string) (bool, error) { +func IsReleaseExist(repoID int64, tagName string) (bool, error) { if len(tagName) == 0 { return false, nil } - return x.Get(&Release{RepoId: repoId, LowerTagName: strings.ToLower(tagName)}) + return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}) } func createTag(gitRepo *git.Repository, rel *Release) error { @@ -64,7 +60,7 @@ func createTag(gitRepo *git.Repository, rel *Release) error { return err } - if err = gitRepo.CreateTag(rel.TagName, commit.Id.String()); err != nil { + if err = gitRepo.CreateTag(rel.TagName, commit.ID.String()); err != nil { return err } } else { @@ -84,11 +80,11 @@ func createTag(gitRepo *git.Repository, rel *Release) error { // CreateRelease creates a new release of repository. func CreateRelease(gitRepo *git.Repository, rel *Release) error { - isExist, err := IsReleaseExist(rel.RepoId, rel.TagName) + isExist, err := IsReleaseExist(rel.RepoID, rel.TagName) if err != nil { return err } else if isExist { - return ErrReleaseAlreadyExist + return ErrReleaseAlreadyExist{rel.TagName} } if err = createTag(gitRepo, rel); err != nil { @@ -100,22 +96,35 @@ func CreateRelease(gitRepo *git.Repository, rel *Release) error { } // GetRelease returns release by given ID. -func GetRelease(repoId int64, tagName string) (*Release, error) { - isExist, err := IsReleaseExist(repoId, tagName) +func GetRelease(repoID int64, tagName string) (*Release, error) { + isExist, err := IsReleaseExist(repoID, tagName) if err != nil { return nil, err } else if !isExist { - return nil, ErrReleaseNotExist + return nil, ErrReleaseNotExist{0, tagName} } - rel := &Release{RepoId: repoId, LowerTagName: strings.ToLower(tagName)} + rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)} _, err = x.Get(rel) return rel, err } -// GetReleasesByRepoId returns a list of releases of repository. -func GetReleasesByRepoId(repoId int64) (rels []*Release, err error) { - err = x.Desc("created").Find(&rels, Release{RepoId: repoId}) +// GetReleaseByID returns release with given ID. +func GetReleaseByID(id int64) (*Release, error) { + rel := new(Release) + has, err := x.Id(id).Get(rel) + if err != nil { + return nil, err + } else if !has { + return nil, ErrReleaseNotExist{id, ""} + } + + return rel, nil +} + +// GetReleasesByRepoID returns a list of releases of repository. +func GetReleasesByRepoID(repoID int64) (rels []*Release, err error) { + err = x.Desc("created").Find(&rels, Release{RepoID: repoID}) return rels, err } @@ -150,6 +159,36 @@ func UpdateRelease(gitRepo *git.Repository, rel *Release) (err error) { if err = createTag(gitRepo, rel); err != nil { return err } - _, err = x.Id(rel.Id).AllCols().Update(rel) + _, err = x.Id(rel.ID).AllCols().Update(rel) return err } + +// DeleteReleaseByID deletes a release and corresponding Git tag by given ID. +func DeleteReleaseByID(id int64) error { + rel, err := GetReleaseByID(id) + if err != nil { + return fmt.Errorf("GetReleaseByID: %v", err) + } + + repo, err := GetRepositoryByID(rel.RepoID) + if err != nil { + return fmt.Errorf("GetRepositoryByID: %v", err) + } + + repoPath, err := repo.RepoPath() + if err != nil { + return fmt.Errorf("RepoPath: %v", err) + } + + _, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID), + "git", "tag", "-d", rel.TagName) + if err != nil && !strings.Contains(stderr, "not found") { + return fmt.Errorf("git tag -d: %v - %s", err, stderr) + } + + if _, err = x.Id(rel.ID).Delete(new(Release)); err != nil { + return fmt.Errorf("Delete: %v", err) + } + + return nil +} diff --git a/models/repo.go b/models/repo.go index 197415c6..b628e752 100644 --- a/models/repo.go +++ b/models/repo.go @@ -17,12 +17,14 @@ import ( "regexp" "sort" "strings" + "sync" "time" "unicode/utf8" "github.com/Unknwon/cae/zip" "github.com/Unknwon/com" "github.com/go-xorm/xorm" + "gopkg.in/ini.v1" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/bindata" @@ -48,7 +50,7 @@ var ( Gitignores, Licenses, Readmes []string // Maximum items per page in forks, watchers and stars of a repo - ItemsPerPage = 54 + ItemsPerPage = 40 ) func LoadRepoConfig() { @@ -319,7 +321,7 @@ func (repo *Repository) UpdateLocalCopy() error { } } else { _, stderr, err := process.ExecDir(-1, localPath, - fmt.Sprintf("UpdateLocalCopy(git pull): %s", repoPath), "git", "pull") + fmt.Sprintf("UpdateLocalCopy(git pull --all): %s", repoPath), "git", "pull", "--all") if err != nil { return fmt.Errorf("git pull: %v - %s", err, stderr) } @@ -379,11 +381,11 @@ func (repo *Repository) CloneLink() (cl CloneLink, err error) { } if setting.SSHPort != 22 { - cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.SSHDomain, setting.SSHPort, repo.Owner.LowerName, repo.LowerName) + cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", setting.RunUser, setting.SSHDomain, setting.SSHPort, repo.Owner.Name, repo.Name) } else { - cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.SSHDomain, repo.Owner.LowerName, repo.LowerName) + cl.SSH = fmt.Sprintf("%s@%s:%s/%s.git", setting.RunUser, setting.SSHDomain, repo.Owner.Name, repo.Name) } - cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.LowerName, repo.LowerName) + cl.HTTPS = fmt.Sprintf("%s%s/%s.git", setting.AppUrl, repo.Owner.Name, repo.Name) return cl, nil } @@ -537,6 +539,17 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { return repo, fmt.Errorf("create update hook: %v", err) } + // Clean up mirror info which prevents "push --all". + configPath := filepath.Join(repoPath, "/config") + cfg, err := ini.Load(configPath) + if err != nil { + return repo, fmt.Errorf("open config file: %v", err) + } + cfg.DeleteSection("remote \"origin\"") + if err = cfg.SaveToIndent(configPath, "\t"); err != nil { + return repo, fmt.Errorf("save config file: %v", err) + } + // Check if repository is empty. _, stderr, err = com.ExecCmdDir(repoPath, "git", "log", "-1") if err != nil { @@ -563,20 +576,20 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { var stderr string if _, stderr, err = process.ExecDir(-1, - tmpPath, fmt.Sprintf("initRepoCommit(git add): %s", tmpPath), + tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath), "git", "add", "--all"); err != nil { return fmt.Errorf("git add: %s", stderr) } if _, stderr, err = process.ExecDir(-1, - tmpPath, fmt.Sprintf("initRepoCommit(git commit): %s", tmpPath), + tmpPath, fmt.Sprintf("initRepoCommit (git commit): %s", tmpPath), "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", "initial commit"); err != nil { return fmt.Errorf("git commit: %s", stderr) } if _, stderr, err = process.ExecDir(-1, - tmpPath, fmt.Sprintf("initRepoCommit(git push): %s", tmpPath), + tmpPath, fmt.Sprintf("initRepoCommit (git push): %s", tmpPath), "git", "push", "origin", "master"); err != nil { return fmt.Errorf("git push: %s", stderr) } @@ -587,7 +600,7 @@ func createUpdateHook(repoPath string) error { hookPath := path.Join(repoPath, "hooks/update") os.MkdirAll(path.Dir(hookPath), os.ModePerm) return ioutil.WriteFile(hookPath, - []byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+appPath+"\"", setting.CustomConf)), 0777) + []byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)), 0777) } type CreateRepoOptions struct { @@ -687,7 +700,7 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C // Init bare new repository. os.MkdirAll(repoPath, os.ModePerm) _, stderr, err := process.ExecDir(-1, repoPath, - fmt.Sprintf("initRepository(git init --bare): %s", repoPath), "git", "init", "--bare") + fmt.Sprintf("initRepository (git init --bare): %s", repoPath), "git", "init", "--bare") if err != nil { return fmt.Errorf("git init --bare: %v - %s", err, stderr) } @@ -898,9 +911,9 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { } // Remove redundant collaborators. - collaborators, err := repo.GetCollaborators() + collaborators, err := repo.getCollaborators(sess) if err != nil { - return fmt.Errorf("GetCollaborators: %v", err) + return fmt.Errorf("getCollaborators: %v", err) } // Dummy object. @@ -936,9 +949,9 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { } if newOwner.IsOrganization() { - t, err := newOwner.GetOwnerTeam() + t, err := newOwner.getOwnerTeam(sess) if err != nil { - return fmt.Errorf("GetOwnerTeam: %v", err) + return fmt.Errorf("getOwnerTeam: %v", err) } else if err = t.addRepository(sess, repo); err != nil { return fmt.Errorf("add to owner team: %v", err) } @@ -1104,7 +1117,7 @@ func DeleteRepository(uid, repoID int64) error { return err } else if _, err = sess.Delete(&Milestone{RepoID: repoID}); err != nil { return err - } else if _, err = sess.Delete(&Release{RepoId: repoID}); err != nil { + } else if _, err = sess.Delete(&Release{RepoID: repoID}); err != nil { return err } else if _, err = sess.Delete(&Collaboration{RepoID: repoID}); err != nil { return err @@ -1304,7 +1317,7 @@ func DeleteRepositoryArchives() error { repo := bean.(*Repository) repoPath, err := repo.RepoPath() if err != nil { - if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives[%d]: %v", repo.ID, err)); err2 != nil { + if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil { log.Error(4, "CreateRepositoryNotice: %v", err2) } return nil @@ -1313,32 +1326,110 @@ func DeleteRepositoryArchives() error { }) } +// DeleteMissingRepositories deletes all repository records that lost Git files. +func DeleteMissingRepositories() error { + repos := make([]*Repository, 0, 5) + if err := x.Where("id > 0").Iterate(new(Repository), + func(idx int, bean interface{}) error { + repo := bean.(*Repository) + repoPath, err := repo.RepoPath() + if err != nil { + if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil { + log.Error(4, "CreateRepositoryNotice: %v", err2) + } + return nil + } + + if !com.IsDir(repoPath) { + repos = append(repos, repo) + } + return nil + }); err != nil { + if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteMissingRepositories: %v", err)); err2 != nil { + log.Error(4, "CreateRepositoryNotice: %v", err2) + } + return nil + } + + if len(repos) == 0 { + return nil + } + + for _, repo := range repos { + log.Trace("Deleting %d/%d...", repo.OwnerID, repo.ID) + if err := DeleteRepository(repo.OwnerID, repo.ID); err != nil { + if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepository [%d]: %v", repo.ID, err)); err2 != nil { + log.Error(4, "CreateRepositoryNotice: %v", err2) + } + } + } + return nil +} + // RewriteRepositoryUpdateHook rewrites all repositories' update hook. func RewriteRepositoryUpdateHook() error { return x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) - if err := repo.GetOwner(); err != nil { - return err + repoPath, err := repo.RepoPath() + if err != nil { + if err2 := CreateRepositoryNotice(fmt.Sprintf("RewriteRepositoryUpdateHook[%d]: %v", repo.ID, err)); err2 != nil { + log.Error(4, "CreateRepositoryNotice: %v", err2) + } + return nil } - return createUpdateHook(RepoPath(repo.Owner.Name, repo.Name)) + return createUpdateHook(repoPath) }) } -var ( - // Prevent duplicate running tasks. - isMirrorUpdating = false - isGitFscking = false - isCheckingRepos = false +// statusPool represents a pool of status with true/false. +type statusPool struct { + lock sync.RWMutex + pool map[string]bool +} + +// Start sets value of given name to true in the pool. +func (p *statusPool) Start(name string) { + p.lock.Lock() + defer p.lock.Unlock() + + p.pool[name] = true +} + +// Stop sets value of given name to false in the pool. +func (p *statusPool) Stop(name string) { + p.lock.Lock() + defer p.lock.Unlock() + + p.pool[name] = false +} + +// IsRunning checks if value of given name is set to true in the pool. +func (p *statusPool) IsRunning(name string) bool { + p.lock.RLock() + defer p.lock.RUnlock() + + return p.pool[name] +} + +// Prevent duplicate running tasks. +var taskStatusPool = &statusPool{ + pool: make(map[string]bool), +} + +const ( + _MIRROR_UPDATE = "mirror_update" + _GIT_FSCK = "git_fsck" + _CHECK_REPOs = "check_repos" ) // MirrorUpdate checks and updates mirror repositories. func MirrorUpdate() { - if isMirrorUpdating { + if taskStatusPool.IsRunning(_MIRROR_UPDATE) { return } - isMirrorUpdating = true - defer func() { isMirrorUpdating = false }() + taskStatusPool.Start(_MIRROR_UPDATE) + defer taskStatusPool.Stop(_MIRROR_UPDATE) log.Trace("Doing: MirrorUpdate") @@ -1386,11 +1477,11 @@ func MirrorUpdate() { // GitFsck calls 'git fsck' to check repository health. func GitFsck() { - if isGitFscking { + if taskStatusPool.IsRunning(_GIT_FSCK) { return } - isGitFscking = true - defer func() { isGitFscking = false }() + taskStatusPool.Start(_GIT_FSCK) + defer taskStatusPool.Stop(_GIT_FSCK) log.Trace("Doing: GitFsck") @@ -1455,11 +1546,11 @@ func repoStatsCheck(checker *repoChecker) { } func CheckRepoStats() { - if isCheckingRepos { + if taskStatusPool.IsRunning(_CHECK_REPOs) { return } - isCheckingRepos = true - defer func() { isCheckingRepos = false }() + taskStatusPool.Start(_CHECK_REPOs) + defer taskStatusPool.Stop(_CHECK_REPOs) log.Trace("Doing: CheckRepoStats") @@ -1680,25 +1771,21 @@ func WatchRepo(uid, repoId int64, watch bool) (err error) { return watchRepo(x, uid, repoId, watch) } -func getWatchers(e Engine, rid int64) ([]*Watch, error) { +func getWatchers(e Engine, repoID int64) ([]*Watch, error) { watches := make([]*Watch, 0, 10) - err := e.Find(&watches, &Watch{RepoID: rid}) - return watches, err + return watches, e.Find(&watches, &Watch{RepoID: repoID}) } // GetWatchers returns all watchers of given repository. -func GetWatchers(rid int64) ([]*Watch, error) { - return getWatchers(x, rid) +func GetWatchers(repoID int64) ([]*Watch, error) { + return getWatchers(x, repoID) } -// Repository.GetWatchers returns all users watching given repository. -func (repo *Repository) GetWatchers(offset int) ([]*User, error) { - users := make([]*User, 0, 10) - offset = (offset - 1) * ItemsPerPage - - err := x.Limit(ItemsPerPage, offset).Where("repo_id=?", repo.ID).Join("LEFT", "watch", "user.id=watch.user_id").Find(&users) - - return users, err +// Repository.GetWatchers returns range of users watching given repository. +func (repo *Repository) GetWatchers(page int) ([]*User, error) { + users := make([]*User, 0, ItemsPerPage) + return users, x.Limit(ItemsPerPage, (page-1)*ItemsPerPage). + Where("repo_id=?", repo.ID).Join("LEFT", "watch", "user.id=watch.user_id").Find(&users) } func notifyWatchers(e Engine, act *Action) error { @@ -1778,13 +1865,10 @@ func IsStaring(uid, repoId int64) bool { return has } -func (repo *Repository) GetStars(offset int) ([]*User, error) { - users := make([]*User, 0, 10) - offset = (offset - 1) * ItemsPerPage - - err := x.Limit(ItemsPerPage, offset).Where("repo_id=?", repo.ID).Join("LEFT", "star", "user.id=star.uid").Find(&users) - - return users, err +func (repo *Repository) GetStargazers(page int) ([]*User, error) { + users := make([]*User, 0, ItemsPerPage) + return users, x.Limit(ItemsPerPage, (page-1)*ItemsPerPage). + Where("repo_id=?", repo.ID).Join("LEFT", "star", "user.id=star.uid").Find(&users) } // ___________ __ @@ -1856,9 +1940,6 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit } func (repo *Repository) GetForks() ([]*Repository, error) { - forks := make([]*Repository, 0, 10) - - err := x.Find(&forks, &Repository{ForkID: repo.ID}) - - return forks, err + forks := make([]*Repository, 0, repo.NumForks) + return forks, x.Find(&forks, &Repository{ForkID: repo.ID}) } diff --git a/models/update.go b/models/update.go index 0cf62db4..14e56ce8 100644 --- a/models/update.go +++ b/models/update.go @@ -10,7 +10,6 @@ import ( "os/exec" "strings" - "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/git" "github.com/gogits/gogs/modules/log" ) @@ -28,6 +27,7 @@ func AddUpdateTask(task *UpdateTask) error { return err } +// GetUpdateTaskByUUID returns update task by given UUID. func GetUpdateTaskByUUID(uuid string) (*UpdateTask, error) { task := &UpdateTask{ UUID: uuid, @@ -36,7 +36,7 @@ func GetUpdateTaskByUUID(uuid string) (*UpdateTask, error) { if err != nil { return nil, err } else if !has { - return nil, fmt.Errorf("task does not exist: %s", uuid) + return nil, ErrUpdateTaskNotExist{uuid} } return task, nil } @@ -46,10 +46,10 @@ func DeleteUpdateTaskByUUID(uuid string) error { return err } -func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) error { - isNew := strings.HasPrefix(oldCommitId, "0000000") +func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName string, userID int64) error { + isNew := strings.HasPrefix(oldCommitID, "0000000") if isNew && - strings.HasPrefix(newCommitId, "0000000") { + strings.HasPrefix(newCommitID, "0000000") { return fmt.Errorf("old rev and new rev both 000000") } @@ -59,23 +59,23 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName gitUpdate.Dir = f gitUpdate.Run() - isDel := strings.HasPrefix(newCommitId, "0000000") + isDel := strings.HasPrefix(newCommitID, "0000000") if isDel { - log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userId) + log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userID) return nil } - repo, err := git.OpenRepository(f) + gitRepo, err := git.OpenRepository(f) if err != nil { return fmt.Errorf("runUpdate.Open repoId: %v", err) } - ru, err := GetUserByName(repoUserName) + user, err := GetUserByName(repoUserName) if err != nil { return fmt.Errorf("runUpdate.GetUserByName: %v", err) } - repos, err := GetRepositoryByName(ru.Id, repoName) + repo, err := GetRepositoryByName(user.Id, repoName) if err != nil { return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err) } @@ -83,7 +83,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName // Push tags. if strings.HasPrefix(refName, "refs/tags/") { tagName := git.RefEndName(refName) - tag, err := repo.GetTag(tagName) + tag, err := gitRepo.GetTag(tagName) if err != nil { log.GitLogger.Fatal(4, "runUpdate.GetTag: %v", err) } @@ -99,16 +99,16 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName actEmail = cmt.Committer.Email } - commit := &base.PushCommits{} + commit := &PushCommits{} - if err = CommitRepoAction(userId, ru.Id, userName, actEmail, - repos.ID, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil { + if err = CommitRepoAction(userID, user.Id, userName, actEmail, + repo.ID, repoUserName, repoName, refName, commit, oldCommitID, newCommitID); err != nil { log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return err } - newCommit, err := repo.GetCommit(newCommitId) + newCommit, err := gitRepo.GetCommit(newCommitID) if err != nil { return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err) } @@ -121,7 +121,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName return fmt.Errorf("CommitsBefore: %v", err) } } else { - l, err = newCommit.CommitsBeforeUntil(oldCommitId) + l, err = newCommit.CommitsBeforeUntil(oldCommitID) if err != nil { return fmt.Errorf("CommitsBeforeUntil: %v", err) } @@ -132,7 +132,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName } // Push commits. - commits := make([]*base.PushCommit, 0) + commits := make([]*PushCommit, 0) var actEmail string for e := l.Front(); e != nil; e = e.Next() { commit := e.Value.(*git.Commit) @@ -140,15 +140,15 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName actEmail = commit.Committer.Email } commits = append(commits, - &base.PushCommit{commit.Id.String(), + &PushCommit{commit.ID.String(), commit.Message(), commit.Author.Email, commit.Author.Name, }) } - if err = CommitRepoAction(userId, ru.Id, userName, actEmail, - repos.ID, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitId, newCommitId); err != nil { + if err = CommitRepoAction(userID, user.Id, userName, actEmail, + repo.ID, repoUserName, repoName, refName, &PushCommits{l.Len(), commits, "", nil}, oldCommitID, newCommitID); err != nil { return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } return nil diff --git a/models/user.go b/models/user.go index 4109f4d9..750f59e5 100644 --- a/models/user.go +++ b/models/user.go @@ -14,6 +14,7 @@ import ( "image" "image/jpeg" _ "image/jpeg" + "image/png" "os" "path" "path/filepath" @@ -75,9 +76,10 @@ type User struct { LastRepoVisibility bool // Permissions. - IsActive bool - IsAdmin bool - AllowGitHook bool + IsActive bool + IsAdmin bool + AllowGitHook bool + AllowImportLocal bool // Allow migrate repository by local path // Avatar. Avatar string `xorm:"VARCHAR(2048) NOT NULL"` @@ -107,6 +109,22 @@ func (u *User) AfterSet(colName string, _ xorm.Cell) { } } +// HasForkedRepo checks if user has already forked a repository with given ID. +func (u *User) HasForkedRepo(repoID int64) bool { + _, has := HasForkedRepo(u.Id, repoID) + return has +} + +// CanEditGitHook returns true if user can edit Git hooks. +func (u *User) CanEditGitHook() bool { + return u.IsAdmin || u.AllowGitHook +} + +// CanImportLocal returns true if user can migrate repository by local path. +func (u *User) CanImportLocal() bool { + return u.IsAdmin || u.AllowImportLocal +} + // EmailAdresses is the list of all email addresses of a user. Can contain the // primary email address, but is not obligatory type EmailAddress struct { @@ -242,14 +260,12 @@ func (u *User) ValidatePassword(passwd string) bool { // UploadAvatar saves custom avatar for user. // FIXME: split uploads to different subdirs in case we have massive users. func (u *User) UploadAvatar(data []byte) error { - u.UseCustomAvatar = true - img, _, err := image.Decode(bytes.NewReader(data)) if err != nil { - return err + return fmt.Errorf("Decode: %v", err) } - m := resize.Resize(234, 234, img, resize.NearestNeighbor) + m := resize.Resize(290, 290, img, resize.NearestNeighbor) sess := x.NewSession() defer sessionRelease(sess) @@ -257,19 +273,20 @@ func (u *User) UploadAvatar(data []byte) error { return err } - if _, err = sess.Id(u.Id).AllCols().Update(u); err != nil { - return err + u.UseCustomAvatar = true + if err = updateUser(sess, u); err != nil { + return fmt.Errorf("updateUser: %v", err) } os.MkdirAll(setting.AvatarUploadPath, os.ModePerm) fw, err := os.Create(u.CustomAvatarPath()) if err != nil { - return err + return fmt.Errorf("Create: %v", err) } defer fw.Close() - if err = jpeg.Encode(fw, m, nil); err != nil { - return err + if err = png.Encode(fw, m); err != nil { + return fmt.Errorf("Encode: %v", err) } return sess.Commit() @@ -356,6 +373,15 @@ func (u *User) DisplayName() string { return u.Name } +// ShortName returns shorted user name with given maximum length, +// it adds "..." at the end if user name has more length than maximum. +func (u *User) ShortName(length int) string { + if len(u.Name) < length { + return u.Name + } + return u.Name[:length] + "..." +} + // IsUserExist checks if given user name exist, // the user name should be noncased unique. // If uid is presented, then check will rule out that one, @@ -717,9 +743,9 @@ func UserPath(userName string) string { return filepath.Join(setting.RepoRootPath, strings.ToLower(userName)) } -func GetUserByKeyId(keyId int64) (*User, error) { +func GetUserByKeyID(keyID int64) (*User, error) { user := new(User) - has, err := x.Sql("SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?", keyId).Get(user) + has, err := x.Sql("SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?", keyID).Get(user) if err != nil { return nil, err } else if !has { @@ -980,7 +1006,7 @@ func GetUserByEmail(email string) (*User, error) { return GetUserByID(emailAddress.UID) } - return nil, ErrUserNotExist{0, "email"} + return nil, ErrUserNotExist{0, email} } // SearchUserByName returns given number of users whose name contains keyword. diff --git a/models/webhook.go b/models/webhook.go index b4d7dc9c..cbc874a9 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -178,8 +178,8 @@ func GetActiveWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) { return ws, err } -// GetWebhooksByRepoId returns all webhooks of repository. -func GetWebhooksByRepoId(repoID int64) (ws []*Webhook, err error) { +// GetWebhooksByRepoID returns all webhooks of repository. +func GetWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) { err = x.Find(&ws, &Webhook{RepoID: repoID}) return ws, err } |