diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/action.go | 25 | ||||
-rw-r--r-- | models/admin.go | 24 | ||||
-rw-r--r-- | models/error.go | 20 | ||||
-rw-r--r-- | models/git_diff.go | 9 | ||||
-rw-r--r-- | models/git_diff_test.go | 100 | ||||
-rw-r--r-- | models/issue.go | 1 | ||||
-rw-r--r-- | models/models.go | 7 | ||||
-rw-r--r-- | models/org.go | 82 | ||||
-rw-r--r-- | models/pull.go | 9 | ||||
-rw-r--r-- | models/repo.go | 114 | ||||
-rw-r--r-- | models/repo_branch.go | 57 | ||||
-rw-r--r-- | models/ssh_key.go | 8 | ||||
-rw-r--r-- | models/update.go | 90 | ||||
-rw-r--r-- | models/user.go | 21 | ||||
-rw-r--r-- | models/webhook.go | 7 |
15 files changed, 426 insertions, 148 deletions
diff --git a/models/action.go b/models/action.go index 33d5246e..3bcf999d 100644 --- a/models/action.go +++ b/models/action.go @@ -498,7 +498,7 @@ func CommitRepoAction( payloadSender := &api.PayloadUser{ UserName: pusher.Name, ID: pusher.Id, - AvatarUrl: setting.AppUrl + pusher.RelAvatarLink(), + AvatarUrl: pusher.AvatarLink(), } switch opType { @@ -593,12 +593,29 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error } // GetFeeds returns action list of given user in given context. -func GetFeeds(uid, offset int64, isProfile bool) ([]*Action, error) { +// userID is the user who's requesting, ctxUserID is the user/org that is requested. +// userID can be -1, if isProfile is true or in order to skip the permission check. +func GetFeeds(ctxUserID, userID, offset int64, isProfile bool) ([]*Action, error) { actions := make([]*Action, 0, 20) - sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", uid) + sess := x.Limit(20, int(offset)).Desc("id").Where("user_id=?", ctxUserID) if isProfile { - sess.And("is_private=?", false).And("act_user_id=?", uid) + sess.And("is_private=?", false).And("act_user_id=?", ctxUserID) + } else if ctxUserID != -1 { + ctxUser := &User{Id: ctxUserID} + if err := ctxUser.GetUserRepositories(userID); err != nil { + return nil, err + } + + var repoIDs []int64 + for _, repo := range ctxUser.Repos { + repoIDs = append(repoIDs, repo.ID) + } + + if len(repoIDs) > 0 { + sess.In("repo_id", repoIDs) + } } + err := sess.Find(&actions) return actions, err } diff --git a/models/admin.go b/models/admin.go index 1d6bf629..7756cd6a 100644 --- a/models/admin.go +++ b/models/admin.go @@ -5,12 +5,17 @@ package models import ( + "fmt" + "os" + "os/exec" "strings" "time" "github.com/Unknwon/com" "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/setting" ) type NoticeType int @@ -47,6 +52,25 @@ func CreateRepositoryNotice(desc string) error { return CreateNotice(NOTICE_REPOSITORY, desc) } +// RemoveAllWithNotice removes all directories in given path and +// creates a system notice when error occurs. +func RemoveAllWithNotice(title, path string) { + var err error + if setting.IsWindows { + err = exec.Command("cmd", "/C", "rmdir", "/S", "/Q", path).Run() + } else { + err = os.RemoveAll(path) + } + + if err != nil { + desc := fmt.Sprintf("%s [%s]: %v", title, path, err) + log.Warn(desc) + if err = CreateRepositoryNotice(desc); err != nil { + log.Error(4, "CreateRepositoryNotice: %v", err) + } + } +} + // CountNotices returns number of notices. func CountNotices() int64 { count, _ := x.Count(new(Notice)) diff --git a/models/error.go b/models/error.go index 8e2048de..cd7fa35d 100644 --- a/models/error.go +++ b/models/error.go @@ -392,6 +392,26 @@ func (err ErrReleaseNotExist) Error() string { return fmt.Sprintf("Release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName) } +// __________ .__ +// \______ \____________ ____ ____ | |__ +// | | _/\_ __ \__ \ / \_/ ___\| | \ +// | | \ | | \// __ \| | \ \___| Y \ +// |______ / |__| (____ /___| /\___ >___| / +// \/ \/ \/ \/ \/ + +type ErrBranchNotExist struct { + Name string +} + +func IsErrBranchNotExist(err error) bool { + _, ok := err.(ErrBranchNotExist) + return ok +} + +func (err ErrBranchNotExist) Error() string { + return fmt.Sprintf("Branch does not exist [name: %s]", err.Name) +} + // __ __ ___. .__ __ // / \ / \ ____\_ |__ | |__ ____ ____ | | __ // \ \/\/ // __ \| __ \| | \ / _ \ / _ \| |/ / diff --git a/models/git_diff.go b/models/git_diff.go index e8bfe610..9796ef59 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -26,6 +26,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/process" + "github.com/gogits/gogs/modules/template/highlight" ) type DiffLineType uint8 @@ -160,12 +161,20 @@ type DiffFile struct { IsBin bool IsRenamed bool Sections []*DiffSection + HighlightClass string } func (diffFile *DiffFile) GetType() int { return int(diffFile.Type) } +func (diffFile *DiffFile) GetHighlightClass() string { + if diffFile.HighlightClass == "" { + diffFile.HighlightClass = highlight.FileNameToHighlightClass(diffFile.Name) + } + return diffFile.HighlightClass +} + type Diff struct { TotalAddition, TotalDeletion int Files []*DiffFile diff --git a/models/git_diff_test.go b/models/git_diff_test.go index 4084814e..3a1312ca 100644 --- a/models/git_diff_test.go +++ b/models/git_diff_test.go @@ -1,70 +1,70 @@ package models import ( - dmp "github.com/sergi/go-diff/diffmatchpatch" - "html/template" - "testing" + dmp "github.com/sergi/go-diff/diffmatchpatch" + "html/template" + "testing" ) func assertEqual(t *testing.T, s1 string, s2 template.HTML) { - if s1 != string(s2) { - t.Errorf("%s should be equal %s", s2, s1) - } + if s1 != string(s2) { + t.Errorf("%s should be equal %s", s2, s1) + } } func assertLineEqual(t *testing.T, d1 *DiffLine, d2 *DiffLine) { - if d1 != d2 { - t.Errorf("%v should be equal %v", d1, d2) - } + if d1 != d2 { + t.Errorf("%v should be equal %v", d1, d2) + } } func TestDiffToHTML(t *testing.T) { - assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{ - dmp.Diff{dmp.DiffEqual, "foo "}, - dmp.Diff{dmp.DiffInsert, "bar"}, - dmp.Diff{dmp.DiffDelete, " baz"}, - dmp.Diff{dmp.DiffEqual, " biz"}, - }, DIFF_LINE_ADD)) + assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML([]dmp.Diff{ + dmp.Diff{dmp.DiffEqual, "foo "}, + dmp.Diff{dmp.DiffInsert, "bar"}, + dmp.Diff{dmp.DiffDelete, " baz"}, + dmp.Diff{dmp.DiffEqual, " biz"}, + }, DIFF_LINE_ADD)) - assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{ - dmp.Diff{dmp.DiffEqual, "foo "}, - dmp.Diff{dmp.DiffDelete, "bar"}, - dmp.Diff{dmp.DiffInsert, " baz"}, - dmp.Diff{dmp.DiffEqual, " biz"}, - }, DIFF_LINE_DEL)) + assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML([]dmp.Diff{ + dmp.Diff{dmp.DiffEqual, "foo "}, + dmp.Diff{dmp.DiffDelete, "bar"}, + dmp.Diff{dmp.DiffInsert, " baz"}, + dmp.Diff{dmp.DiffEqual, " biz"}, + }, DIFF_LINE_DEL)) } // test if GetLine is return the correct lines func TestGetLine(t *testing.T) { - ds := DiffSection{Lines: []*DiffLine{ - &DiffLine{LeftIdx: 28, RightIdx: 28, Type: DIFF_LINE_PLAIN}, - &DiffLine{LeftIdx: 29, RightIdx: 29, Type: DIFF_LINE_PLAIN}, - &DiffLine{LeftIdx: 30, RightIdx: 30, Type: DIFF_LINE_PLAIN}, - &DiffLine{LeftIdx: 31, RightIdx: 0, Type: DIFF_LINE_DEL}, - &DiffLine{LeftIdx: 0, RightIdx: 31, Type: DIFF_LINE_ADD}, - &DiffLine{LeftIdx: 0, RightIdx: 32, Type: DIFF_LINE_ADD}, - &DiffLine{LeftIdx: 32, RightIdx: 33, Type: DIFF_LINE_PLAIN}, - &DiffLine{LeftIdx: 33, RightIdx: 0, Type: DIFF_LINE_DEL}, - &DiffLine{LeftIdx: 34, RightIdx: 0, Type: DIFF_LINE_DEL}, - &DiffLine{LeftIdx: 35, RightIdx: 0, Type: DIFF_LINE_DEL}, - &DiffLine{LeftIdx: 36, RightIdx: 0, Type: DIFF_LINE_DEL}, - &DiffLine{LeftIdx: 0, RightIdx: 34, Type: DIFF_LINE_ADD}, - &DiffLine{LeftIdx: 0, RightIdx: 35, Type: DIFF_LINE_ADD}, - &DiffLine{LeftIdx: 0, RightIdx: 36, Type: DIFF_LINE_ADD}, - &DiffLine{LeftIdx: 0, RightIdx: 37, Type: DIFF_LINE_ADD}, - &DiffLine{LeftIdx: 37, RightIdx: 38, Type: DIFF_LINE_PLAIN}, - &DiffLine{LeftIdx: 38, RightIdx: 39, Type: DIFF_LINE_PLAIN}, - }} + ds := DiffSection{Lines: []*DiffLine{ + &DiffLine{LeftIdx: 28, RightIdx: 28, Type: DIFF_LINE_PLAIN}, + &DiffLine{LeftIdx: 29, RightIdx: 29, Type: DIFF_LINE_PLAIN}, + &DiffLine{LeftIdx: 30, RightIdx: 30, Type: DIFF_LINE_PLAIN}, + &DiffLine{LeftIdx: 31, RightIdx: 0, Type: DIFF_LINE_DEL}, + &DiffLine{LeftIdx: 0, RightIdx: 31, Type: DIFF_LINE_ADD}, + &DiffLine{LeftIdx: 0, RightIdx: 32, Type: DIFF_LINE_ADD}, + &DiffLine{LeftIdx: 32, RightIdx: 33, Type: DIFF_LINE_PLAIN}, + &DiffLine{LeftIdx: 33, RightIdx: 0, Type: DIFF_LINE_DEL}, + &DiffLine{LeftIdx: 34, RightIdx: 0, Type: DIFF_LINE_DEL}, + &DiffLine{LeftIdx: 35, RightIdx: 0, Type: DIFF_LINE_DEL}, + &DiffLine{LeftIdx: 36, RightIdx: 0, Type: DIFF_LINE_DEL}, + &DiffLine{LeftIdx: 0, RightIdx: 34, Type: DIFF_LINE_ADD}, + &DiffLine{LeftIdx: 0, RightIdx: 35, Type: DIFF_LINE_ADD}, + &DiffLine{LeftIdx: 0, RightIdx: 36, Type: DIFF_LINE_ADD}, + &DiffLine{LeftIdx: 0, RightIdx: 37, Type: DIFF_LINE_ADD}, + &DiffLine{LeftIdx: 37, RightIdx: 38, Type: DIFF_LINE_PLAIN}, + &DiffLine{LeftIdx: 38, RightIdx: 39, Type: DIFF_LINE_PLAIN}, + }} - assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 31), ds.Lines[4]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 31), ds.Lines[3]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 31), ds.Lines[4]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 31), ds.Lines[3]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 33), ds.Lines[11]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 34), ds.Lines[12]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 35), ds.Lines[13]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 36), ds.Lines[14]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 34), ds.Lines[7]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 35), ds.Lines[8]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 36), ds.Lines[9]) - assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 37), ds.Lines[10]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 33), ds.Lines[11]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 34), ds.Lines[12]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 35), ds.Lines[13]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 36), ds.Lines[14]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 34), ds.Lines[7]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 35), ds.Lines[8]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 36), ds.Lines[9]) + assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 37), ds.Lines[10]) } diff --git a/models/issue.go b/models/issue.go index 6188da5c..32645463 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1179,6 +1179,7 @@ func (m *Milestone) AfterSet(colName string, _ xorm.Cell) { if m.Deadline.Year() == 9999 { return } + m.Deadline = regulateTimeZone(m.Deadline) m.DeadlineString = m.Deadline.Format("2006-01-02") if time.Now().After(m.Deadline) { diff --git a/models/models.go b/models/models.go index 2249fee4..2e91f716 100644 --- a/models/models.go +++ b/models/models.go @@ -191,12 +191,7 @@ func SetEngine() (err error) { return fmt.Errorf("Fail to create xorm.log: %v", err) } x.SetLogger(xorm.NewSimpleLogger(f)) - - x.ShowSQL = true - x.ShowInfo = true - x.ShowDebug = true - x.ShowErr = true - x.ShowWarn = true + x.ShowSQL(true) return nil } diff --git a/models/org.go b/models/org.go index b8836c34..9d86df10 100644 --- a/models/org.go +++ b/models/org.go @@ -10,6 +10,7 @@ import ( "os" "strings" + "github.com/Unknwon/com" "github.com/go-xorm/xorm" ) @@ -253,6 +254,27 @@ func IsPublicMembership(orgId, uid int64) bool { return has } +func getOrgsByUserID(sess *xorm.Session, userID int64, showAll bool) ([]*User, error) { + orgs := make([]*User, 0, 10) + if !showAll { + sess.And("`org_user`.is_public=?", true) + } + return orgs, sess.And("`org_user`.uid=?", userID). + Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs) +} + +// GetOrgsByUserID returns a list of organizations that the given user ID +// has joined. +func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) { + return getOrgsByUserID(x.NewSession(), userID, showAll) +} + +// GetOrgsByUserIDDesc returns a list of organizations that the given user ID +// has joined, ordered descending by the given condition. +func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, error) { + return getOrgsByUserID(x.NewSession().Desc(desc), userID, showAll) +} + func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) { orgs := make([]*User, 0, 10) return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true). @@ -266,7 +288,7 @@ func GetOwnedOrgsByUserID(userID int64) ([]*User, error) { } // GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by -// given user ID and descring order by given condition. +// given user ID, ordered descending by the given condition. func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) { sess := x.NewSession() return getOwnedOrgsByUserID(sess.Desc(desc), userID) @@ -1028,3 +1050,61 @@ func removeOrgRepo(e Engine, orgID, repoID int64) error { func RemoveOrgRepo(orgID, repoID int64) error { return removeOrgRepo(x, orgID, repoID) } + +// GetUserRepositories gets all repositories of an organization, +// that the user with the given userID has access to. +func (org *User) GetUserRepositories(userID int64) (err error) { + teams := make([]*Team, 0, 10) + if err = x.Cols("`team`.id"). + Where("`team_user`.org_id=?", org.Id). + And("`team_user`.uid=?", userID). + Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id"). + Find(&teams); err != nil { + return fmt.Errorf("GetUserRepositories: get teams: %v", err) + } + + teamIDs := make([]string, len(teams)) + for i := range teams { + teamIDs[i] = com.ToStr(teams[i].ID) + } + if len(teamIDs) == 0 { + // user has no team but "IN ()" is invalid SQL + teamIDs = append(teamIDs, "-1") // there is no repo with id=-1 + } + + // Due to a bug in xorm using IN() together with OR() is impossible. + // As a workaround, we have to build the IN statement on our own, until this is fixed. + // https://github.com/go-xorm/xorm/issues/342 + + if err = x.Cols("`repository`.*"). + Join("INNER", "`team_repo`", "`team_repo`.repo_id=`repository`.id"). + Where("`repository`.owner_id=?", org.Id). + And("`repository`.is_private=?", false). + Or("`team_repo`.team_id=(?)", strings.Join(teamIDs, ",")). + GroupBy("`repository`.id"). + Find(&org.Repos); err != nil { + return fmt.Errorf("GetUserRepositories: get repositories: %v", err) + } + + // FIXME: should I change this value inside method, + // or only in location of caller where it's really needed? + org.NumRepos = len(org.Repos) + return nil +} + +// GetTeams returns all teams that belong to organization, +// and that the user has joined. +func (org *User) GetUserTeams(userID int64) error { + if err := x.Cols("`team`.*"). + Where("`team_user`.org_id=?", org.Id). + And("`team_user`.uid=?", userID). + Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id"). + Find(&org.Teams); err != nil { + return fmt.Errorf("GetUserTeams: %v", err) + } + + // FIXME: should I change this value inside method, + // or only in location of caller where it's really needed? + org.NumTeams = len(org.Teams) + return nil +} diff --git a/models/pull.go b/models/pull.go index c52c871c..67f103e8 100644 --- a/models/pull.go +++ b/models/pull.go @@ -257,6 +257,7 @@ var patchConflicts = []string{ "patch does not apply", "already exists in working directory", "unrecognized input", + "error:", } // testPatch checks if patch can be merged to base repository without conflit. @@ -280,7 +281,7 @@ func (pr *PullRequest) testPatch() (err error) { return nil } - log.Trace("PullRequest[%d].testPatch(patchPath): %s", pr.ID, patchPath) + log.Trace("PullRequest[%d].testPatch (patchPath): %s", pr.ID, patchPath) if err := pr.BaseRepo.UpdateLocalCopy(); err != nil { return fmt.Errorf("UpdateLocalCopy: %v", err) @@ -288,7 +289,7 @@ func (pr *PullRequest) testPatch() (err error) { // Checkout base branch. _, stderr, err := process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(), - fmt.Sprintf("PullRequest.Merge(git checkout): %v", pr.BaseRepo.ID), + fmt.Sprintf("PullRequest.Merge (git checkout): %v", pr.BaseRepo.ID), "git", "checkout", pr.BaseBranch) if err != nil { return fmt.Errorf("git checkout: %s", stderr) @@ -296,12 +297,12 @@ func (pr *PullRequest) testPatch() (err error) { pr.Status = PULL_REQUEST_STATUS_CHECKING _, stderr, err = process.ExecDir(-1, pr.BaseRepo.LocalCopyPath(), - fmt.Sprintf("testPatch(git apply --check): %d", pr.BaseRepo.ID), + 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) + log.Trace("PullRequest[%d].testPatch (apply): has conflit", pr.ID) fmt.Println(stderr) pr.Status = PULL_REQUEST_STATUS_CONFLICT return nil diff --git a/models/repo.go b/models/repo.go index 8ce1f719..98bb1107 100644 --- a/models/repo.go +++ b/models/repo.go @@ -332,7 +332,17 @@ func (repo *Repository) IsOwnedBy(userID int64) bool { // CanBeForked returns true if repository meets the requirements of being forked. func (repo *Repository) CanBeForked() bool { - return !repo.IsBare && !repo.IsMirror + return !repo.IsBare +} + +// CanEnablePulls returns true if repository meets the requirements of accepting pulls. +func (repo *Repository) CanEnablePulls() bool { + return !repo.IsMirror +} + +// AllowPulls returns true if repository meets the requirements of accepting pulls and has them enabled. +func (repo *Repository) AllowsPulls() bool { + return repo.CanEnablePulls() && repo.EnablePulls; } func (repo *Repository) NextIssueIndex() int64 { @@ -414,7 +424,8 @@ func (repo *Repository) ComposePayload() *api.PayloadRepo { Email: repo.MustOwner().Email, UserName: repo.MustOwner().Name, }, - Private: repo.IsPrivate, + Private: repo.IsPrivate, + DefaultBranch: repo.DefaultBranch, } } @@ -591,6 +602,11 @@ func UpdateMirror(m *Mirror) error { return updateMirror(x, m) } +func DeleteMirrorByRepoID(repoID int64) error { + _, err := x.Delete(&Mirror{RepoID: repoID}) + return err +} + func createUpdateHook(repoPath string) error { return git.SetUpdateHook(repoPath, fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)) @@ -654,7 +670,12 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) { return repo, UpdateRepository(repo, false) } - if err = createUpdateHook(repoPath); err != nil { + return CleanUpMigrateInfo(repo, repoPath) +} + +// Finish migrating repository with things that don't need to be done for mirrors. +func CleanUpMigrateInfo(repo *Repository, repoPath string) (*Repository, error) { + if err := createUpdateHook(repoPath); err != nil { return repo, fmt.Errorf("createUpdateHook: %v", err) } @@ -957,10 +978,13 @@ func countRepositories(showPrivate bool) int64 { sess := x.NewSession() if !showPrivate { - sess.Where("is_private=", false) + sess.Where("is_private=?", false) } - count, _ := sess.Count(new(Repository)) + count, err := sess.Count(new(Repository)) + if err != nil { + log.Error(4, "countRepositories: %v", err) + } return count } @@ -1093,13 +1117,16 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { return fmt.Errorf("transferRepoAction: %v", err) } - // Change repository directory name. + // Rename remote repository to new path and delete local copy. if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename repository directory: %v", err) } + RemoveAllWithNotice("Delete repository local copy", repo.LocalCopyPath()) + // Rename remote wiki repository to new path and delete local copy. wikiPath := WikiPath(owner.Name, repo.Name) if com.IsExist(wikiPath) { + RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) if err = os.Rename(wikiPath, WikiPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename repository wiki: %v", err) } @@ -1123,16 +1150,22 @@ func ChangeRepositoryName(u *User, oldRepoName, newRepoName string) (err error) return ErrRepoAlreadyExist{u.Name, newRepoName} } + repo, err := GetRepositoryByName(u.Id, oldRepoName) + if err != nil { + return fmt.Errorf("GetRepositoryByName: %v", err) + } + // Change repository directory name. - if err = os.Rename(RepoPath(u.Name, oldRepoName), RepoPath(u.Name, newRepoName)); err != nil { + if err = os.Rename(repo.RepoPath(), RepoPath(u.Name, newRepoName)); err != nil { return fmt.Errorf("rename repository directory: %v", err) } - wikiPath := WikiPath(u.Name, oldRepoName) + wikiPath := repo.WikiPath() if com.IsExist(wikiPath) { if err = os.Rename(wikiPath, WikiPath(u.Name, newRepoName)); err != nil { return fmt.Errorf("rename repository wiki: %v", err) } + RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) } return nil @@ -1295,30 +1328,16 @@ func DeleteRepository(uid, repoID int64) error { // Remove repository files. repoPath := repo.repoPath(sess) - if err = os.RemoveAll(repoPath); err != nil { - desc := fmt.Sprintf("delete repository files [%s]: %v", repoPath, err) - log.Warn(desc) - if err = CreateRepositoryNotice(desc); err != nil { - log.Error(4, "CreateRepositoryNotice: %v", err) - } - } + RemoveAllWithNotice("Delete repository files", repoPath) wikiPaths := []string{repo.WikiPath(), repo.LocalWikiPath()} for _, wikiPath := range wikiPaths { - if err = os.RemoveAll(wikiPath); err != nil { - desc := fmt.Sprintf("delete repository wiki [%s]: %v", wikiPath, err) - log.Warn(desc) - if err = CreateRepositoryNotice(desc); err != nil { - log.Error(4, "CreateRepositoryNotice: %v", err) - } - } + RemoveAllWithNotice("Delete repository wiki", wikiPath) } // Remove attachment files. for i := range attachmentPaths { - if err = os.Remove(attachmentPaths[i]); err != nil { - log.Warn("delete attachment: %v", err) - } + RemoveAllWithNotice("Delete attachment", attachmentPaths[i]) } if err = sess.Commit(); err != nil { @@ -1333,7 +1352,7 @@ func DeleteRepository(uid, repoID int64) error { } for i := range forkRepos { if err = DeleteRepository(forkRepos[i].OwnerID, forkRepos[i].ID); err != nil { - log.Error(4, "updateRepository[%d]: %v", forkRepos[i].ID, err) + log.Error(4, "DeleteRepository [%d]: %v", forkRepos[i].ID, err) } } } else { @@ -1457,9 +1476,8 @@ func DeleteRepositoryArchives() error { }) } -// DeleteMissingRepositories deletes all repository records that lost Git files. -func DeleteMissingRepositories() error { - repos := make([]*Repository, 0, 5) +func gatherMissingRepoRecords() ([]*Repository, error) { + repos := make([]*Repository, 0, 10) if err := x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) @@ -1468,10 +1486,18 @@ func DeleteMissingRepositories() error { } return nil }); err != nil { - if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteMissingRepositories: %v", err)); err2 != nil { - log.Error(4, "CreateRepositoryNotice: %v", err2) + if err2 := CreateRepositoryNotice(fmt.Sprintf("gatherMissingRepoRecords: %v", err)); err2 != nil { + return nil, fmt.Errorf("CreateRepositoryNotice: %v", err) } - return nil + } + return repos, nil +} + +// DeleteMissingRepositories deletes all repository records that lost Git files. +func DeleteMissingRepositories() error { + repos, err := gatherMissingRepoRecords() + if err != nil { + return fmt.Errorf("gatherMissingRepoRecords: %v", err) } if len(repos) == 0 { @@ -1482,7 +1508,29 @@ func DeleteMissingRepositories() error { 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 fmt.Errorf("CreateRepositoryNotice: %v", err) + } + } + } + return nil +} + +// ReinitMissingRepositories reinitializes all repository records that lost Git files. +func ReinitMissingRepositories() error { + repos, err := gatherMissingRepoRecords() + if err != nil { + return fmt.Errorf("gatherMissingRepoRecords: %v", err) + } + + if len(repos) == 0 { + return nil + } + + for _, repo := range repos { + log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID) + if err := git.InitRepository(repo.RepoPath(), true); err != nil { + if err2 := CreateRepositoryNotice(fmt.Sprintf("InitRepository [%d]: %v", repo.ID, err)); err2 != nil { + return fmt.Errorf("CreateRepositoryNotice: %v", err) } } } diff --git a/models/repo_branch.go b/models/repo_branch.go new file mode 100644 index 00000000..9cf2e9c4 --- /dev/null +++ b/models/repo_branch.go @@ -0,0 +1,57 @@ +// Copyright 2016 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "github.com/gogits/git-module" +) + +type Branch struct { + Path string + Name string +} + +func GetBranchesByPath(path string) ([]*Branch, error) { + gitRepo, err := git.OpenRepository(path) + if err != nil { + return nil, err + } + + brs, err := gitRepo.GetBranches() + if err != nil { + return nil, err + } + + branches := make([]*Branch, len(brs)) + for i := range brs { + branches[i] = &Branch{ + Path: path, + Name: brs[i], + } + } + return branches, nil +} + +func (repo *Repository) GetBranch(br string) (*Branch, error) { + if !git.IsBranchExist(repo.RepoPath(), br) { + return nil, &ErrBranchNotExist{br} + } + return &Branch{ + Path: repo.RepoPath(), + Name: br, + }, nil +} + +func (repo *Repository) GetBranches() ([]*Branch, error) { + return GetBranchesByPath(repo.RepoPath()) +} + +func (br *Branch) GetCommit() (*git.Commit, error) { + gitRepo, err := git.OpenRepository(br.Path) + if err != nil { + return nil, err + } + return gitRepo.GetBranchCommit(br.Name) +} diff --git a/models/ssh_key.go b/models/ssh_key.go index a7b1680f..325a40a4 100644 --- a/models/ssh_key.go +++ b/models/ssh_key.go @@ -165,6 +165,9 @@ func CheckPublicKeyString(content string) (_ string, err error) { return "", errors.New("only a single line with a single key please") } + // remove any unnecessary whitespace now + content = strings.TrimSpace(content) + fields := strings.Fields(content) if len(fields) < 2 { return "", errors.New("too less fields") @@ -374,6 +377,11 @@ func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { break } } + + if !isFound { + log.Warn("SSH key %d not found in authorized_keys file for deletion", key.ID) + } + return nil } diff --git a/models/update.go b/models/update.go index 5c6ea7f6..66775ea9 100644 --- a/models/update.go +++ b/models/update.go @@ -10,7 +10,7 @@ import ( "os/exec" "strings" - "github.com/gogits/git-module" + git "github.com/gogits/git-module" "github.com/gogits/gogs/modules/log" ) @@ -65,94 +65,104 @@ func ListToPushCommits(l *list.List) *PushCommits { return &PushCommits{l.Len(), commits, "", nil} } -func Update(refName, oldCommitID, newCommitID, userName, repoUserName, repoName string, userID int64) error { - isNew := strings.HasPrefix(oldCommitID, "0000000") - if isNew && - strings.HasPrefix(newCommitID, "0000000") { - return fmt.Errorf("old rev and new rev both 000000") +type PushUpdateOptions struct { + RefName string + OldCommitID string + NewCommitID string + PusherID int64 + PusherName string + RepoUserName string + RepoName string +} + +// PushUpdate must be called for any push actions in order to +// generates necessary push action history feeds. +func PushUpdate(opts PushUpdateOptions) (err error) { + isNewRef := strings.HasPrefix(opts.OldCommitID, "0000000") + isDelRef := strings.HasPrefix(opts.NewCommitID, "0000000") + if isNewRef && isDelRef { + return fmt.Errorf("Old and new revisions both start with 000000") } - f := RepoPath(repoUserName, repoName) + repoPath := RepoPath(opts.RepoUserName, opts.RepoName) gitUpdate := exec.Command("git", "update-server-info") - gitUpdate.Dir = f - gitUpdate.Run() + gitUpdate.Dir = repoPath + if err = gitUpdate.Run(); err != nil { + return fmt.Errorf("Fail to call 'git update-server-info': %v", err) + } - isDel := strings.HasPrefix(newCommitID, "0000000") - if isDel { - log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userID) + if isDelRef { + log.GitLogger.Info("Reference '%s' has been deleted from '%s/%s' by %d", + opts.RefName, opts.RepoUserName, opts.RepoName, opts.PusherName) return nil } - gitRepo, err := git.OpenRepository(f) + gitRepo, err := git.OpenRepository(repoPath) if err != nil { - return fmt.Errorf("runUpdate.Open repoId: %v", err) + return fmt.Errorf("OpenRepository: %v", err) } - user, err := GetUserByName(repoUserName) + repoUser, err := GetUserByName(opts.RepoUserName) if err != nil { - return fmt.Errorf("runUpdate.GetUserByName: %v", err) + return fmt.Errorf("GetUserByName: %v", err) } - repo, err := GetRepositoryByName(user.Id, repoName) + repo, err := GetRepositoryByName(repoUser.Id, opts.RepoName) if err != nil { - return fmt.Errorf("runUpdate.GetRepositoryByName userId: %v", err) + return fmt.Errorf("GetRepositoryByName: %v", err) } // Push tags. - if strings.HasPrefix(refName, "refs/tags/") { - tagName := git.RefEndName(refName) - tag, err := gitRepo.GetTag(tagName) + if strings.HasPrefix(opts.RefName, "refs/tags/") { + tag, err := gitRepo.GetTag(git.RefEndName(opts.RefName)) if err != nil { - log.GitLogger.Fatal(4, "runUpdate.GetTag: %v", err) + return fmt.Errorf("gitRepo.GetTag: %v", err) } + // When tagger isn't available, fall back to get committer email. var actEmail string if tag.Tagger != nil { actEmail = tag.Tagger.Email } else { cmt, err := tag.Commit() if err != nil { - log.GitLogger.Fatal(4, "runUpdate.GetTag Commit: %v", err) + return fmt.Errorf("tag.Commit: %v", err) } actEmail = cmt.Committer.Email } commit := &PushCommits{} - - 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) + if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, actEmail, + repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, commit, opts.OldCommitID, opts.NewCommitID); err != nil { + return fmt.Errorf("CommitRepoAction (tag): %v", err) } return err } - newCommit, err := gitRepo.GetCommit(newCommitID) + newCommit, err := gitRepo.GetCommit(opts.NewCommitID) if err != nil { - return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err) + return fmt.Errorf("gitRepo.GetCommit: %v", err) } // Push new branch. var l *list.List - if isNew { + if isNewRef { l, err = newCommit.CommitsBeforeLimit(10) if err != nil { - return fmt.Errorf("CommitsBefore: %v", err) + return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err) } } else { - l, err = newCommit.CommitsBeforeUntil(oldCommitID) + l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID) if err != nil { - return fmt.Errorf("CommitsBeforeUntil: %v", err) + return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err) } } - if err != nil { - return fmt.Errorf("runUpdate.Commit repoId: %v", err) - } - - if err = CommitRepoAction(userID, user.Id, userName, user.Email, - repo.ID, repoUserName, repoName, refName, ListToPushCommits(l), oldCommitID, newCommitID); err != nil { - return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) + if err = CommitRepoAction(opts.PusherID, repoUser.Id, opts.PusherName, repoUser.Email, + repo.ID, opts.RepoUserName, opts.RepoName, opts.RefName, ListToPushCommits(l), + opts.OldCommitID, opts.NewCommitID); err != nil { + return fmt.Errorf("CommitRepoAction (branch): %v", err) } return nil } diff --git a/models/user.go b/models/user.go index 31ac1e22..7a881759 100644 --- a/models/user.go +++ b/models/user.go @@ -16,7 +16,6 @@ import ( _ "image/jpeg" "image/png" "os" - "path" "path/filepath" "strings" "time" @@ -211,7 +210,7 @@ func (u *User) GenerateRandomAvatar() error { if err != nil { return fmt.Errorf("RandomImage: %v", err) } - if err = os.MkdirAll(path.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil { + if err = os.MkdirAll(filepath.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil { return fmt.Errorf("MkdirAll: %v", err) } fw, err := os.Create(u.CustomAvatarPath()) @@ -248,8 +247,6 @@ func (u *User) RelAvatarLink() string { } return "/avatars/" + com.ToStr(u.Id) - case setting.Service.EnableCacheAvatar: - return "/avatar/" + u.Avatar } return setting.GravatarSource + u.Avatar } @@ -494,7 +491,7 @@ func CreateUser(u *User) (err error) { u.LowerName = strings.ToLower(u.Name) u.AvatarEmail = u.Email - u.Avatar = avatar.HashEmail(u.AvatarEmail) + u.Avatar = base.HashEmail(u.AvatarEmail) u.Rands = GetUserSalt() u.Salt = GetUserSalt() u.EncodePasswd() @@ -599,11 +596,19 @@ func ChangeUserName(u *User, newUserName string) (err error) { return ErrUserAlreadyExist{newUserName} } - err = ChangeUsernameInPullRequests(u.Name, newUserName) - if err != nil { + if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil { return fmt.Errorf("ChangeUsernameInPullRequests: %v", err) } + // Delete all local copies of repository wiki that user owns. + if err = x.Where("owner_id=?", u.Id).Iterate(new(Repository), func(idx int, bean interface{}) error { + repo := bean.(*Repository) + RemoveAllWithNotice("Delete repository wiki local copy", repo.LocalWikiPath()) + return nil + }); err != nil { + return fmt.Errorf("Delete repository wiki local copy: %v", err) + } + return os.Rename(UserPath(u.Name), UserPath(newUserName)) } @@ -621,7 +626,7 @@ func updateUser(e Engine, u *User) error { if len(u.AvatarEmail) == 0 { u.AvatarEmail = u.Email } - u.Avatar = avatar.HashEmail(u.AvatarEmail) + u.Avatar = base.HashEmail(u.AvatarEmail) } u.LowerName = strings.ToLower(u.Name) diff --git a/models/webhook.go b/models/webhook.go index 27ac75fe..bdfb62d8 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -398,6 +398,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err return nil } + var payloader api.Payloader for _, w := range ws { switch event { case HOOK_EVENT_CREATE: @@ -410,14 +411,16 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err } } + // Use separate objects so modifcations won't be made on payload on non-Gogs type hooks. switch w.HookTaskType { case SLACK: - p, err = GetSlackPayload(p, event, w.Meta) + payloader, err = GetSlackPayload(p, event, w.Meta) if err != nil { return fmt.Errorf("GetSlackPayload: %v", err) } default: p.SetSecret(w.Secret) + payloader = p } if err = CreateHookTask(&HookTask{ @@ -425,7 +428,7 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err HookID: w.ID, Type: w.HookTaskType, URL: w.URL, - Payloader: p, + Payloader: payloader, ContentType: w.ContentType, EventType: HOOK_EVENT_PUSH, IsSSL: w.IsSSL, |