Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug on pull requests when transfer head repository #8564

Merged
merged 4 commits into from
Oct 18, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions models/fixtures/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
index: 2
head_repo_id: 1
base_repo_id: 1
head_user_name: user1
head_branch: branch1
base_branch: master
merge_base: 1234567890abcdef
Expand All @@ -21,7 +20,6 @@
index: 3
head_repo_id: 1
base_repo_id: 1
head_user_name: user1
head_branch: branch2
base_branch: master
merge_base: fedcba9876543210
Expand All @@ -35,7 +33,6 @@
index: 1
head_repo_id: 11
base_repo_id: 10
head_user_name: user13
head_branch: branch2
base_branch: master
merge_base: 0abcb056019adb83
Expand Down
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ var migrations = []Migration{
NewMigration("update migration repositories' service type", updateMigrationServiceTypes),
// v101 -> v102
NewMigration("change length of some external login users columns", changeSomeColumnsLengthOfExternalLoginUser),
// v102 -> v103
NewMigration("update migration repositories' service type", dropColumnHeadUserNameOnPullRequest),
}

// Migrate database to current version
Expand Down
15 changes: 15 additions & 0 deletions models/migrations/v102.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2019 The Gitea 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 migrations

import (
"xorm.io/xorm"
)

func dropColumnHeadUserNameOnPullRequest(x *xorm.Engine) error {
sess := x.NewSession()
defer sess.Close()
return dropTableColumns(sess, "pull_request", "head_user_name")
}
46 changes: 32 additions & 14 deletions models/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ type PullRequest struct {
HeadRepo *Repository `xorm:"-"`
BaseRepoID int64 `xorm:"INDEX"`
BaseRepo *Repository `xorm:"-"`
HeadUserName string
HeadBranch string
BaseBranch string
ProtectedBranch *ProtectedBranch `xorm:"-"`
Expand All @@ -79,6 +78,15 @@ type PullRequest struct {
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
}

// MustHeadUserName returns the HeadRepo's username if failed return blank
func (pr *PullRequest) MustHeadUserName() string {
if err := pr.LoadHeadRepo(); err != nil {
log.Error("LoadHeadRepo: %v", err)
return ""
}
return pr.HeadRepo.MustOwnerName()
}

// Note: don't try to get Issue because will end up recursive querying.
func (pr *PullRequest) loadAttributes(e Engine) (err error) {
if pr.HasMerged && pr.Merger == nil {
Expand All @@ -102,6 +110,10 @@ func (pr *PullRequest) LoadAttributes() error {
// LoadBaseRepo loads pull request base repository from database
func (pr *PullRequest) LoadBaseRepo() error {
if pr.BaseRepo == nil {
if pr.HeadRepoID == pr.BaseRepoID && pr.HeadRepo != nil {
pr.BaseRepo = pr.HeadRepo
return nil
}
var repo Repository
if has, err := x.ID(pr.BaseRepoID).Get(&repo); err != nil {
return err
Expand All @@ -113,6 +125,24 @@ func (pr *PullRequest) LoadBaseRepo() error {
return nil
}

// LoadHeadRepo loads pull request head repository from database
func (pr *PullRequest) LoadHeadRepo() error {
if pr.HeadRepo == nil {
if pr.HeadRepoID == pr.BaseRepoID && pr.BaseRepo != nil {
pr.HeadRepo = pr.BaseRepo
return nil
}
var repo Repository
if has, err := x.ID(pr.HeadRepoID).Get(&repo); err != nil {
return err
} else if !has {
return ErrRepoNotExist{ID: pr.BaseRepoID}
}
pr.HeadRepo = &repo
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add

Suggested change
pr.HeadRepo = &repo
pr.HeadRepo = &repo
if pr.HeadRepoID == pr.BaseRepoID {
pr.BaseRepo = pr.HeadRepo
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Not here but in LoadBaseRepo.

}
return nil
}

// LoadIssue loads issue information from database
func (pr *PullRequest) LoadIssue() (err error) {
return pr.loadIssue(x)
Expand Down Expand Up @@ -152,7 +182,7 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
return ""
}
}
return fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.HeadUserName, pr.HeadRepo.Name, pr.BaseBranch)
return fmt.Sprintf("Merge branch '%s' of %s/%s into %s", pr.HeadBranch, pr.MustHeadUserName(), pr.HeadRepo.Name, pr.BaseBranch)
}

// GetDefaultSquashMessage returns default message used when squash and merging pull request
Expand Down Expand Up @@ -1072,18 +1102,6 @@ func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Reposito
return prs.invalidateCodeComments(x, doer, repo, branch)
}

// ChangeUsernameInPullRequests changes the name of head_user_name
func ChangeUsernameInPullRequests(oldUserName, newUserName string) error {
pr := PullRequest{
HeadUserName: strings.ToLower(newUserName),
}
_, err := x.
Cols("head_user_name").
Where("head_user_name = ?", strings.ToLower(oldUserName)).
Update(pr)
return err
}

// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
func (pr *PullRequest) checkAndUpdateStatus() {
Expand Down
14 changes: 0 additions & 14 deletions models/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,6 @@ func TestPullRequestList_LoadAttributes(t *testing.T) {

// TODO TestAddTestPullRequestTask

func TestChangeUsernameInPullRequests(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
const newUsername = "newusername"
assert.NoError(t, ChangeUsernameInPullRequests("user1", newUsername))

prs := make([]*PullRequest, 0, 10)
assert.NoError(t, x.Where("head_user_name = ?", newUsername).Find(&prs))
assert.Len(t, prs, 2)
for _, pr := range prs {
assert.Equal(t, newUsername, pr.HeadUserName)
}
CheckConsistencyFor(t, &PullRequest{})
}

func TestPullRequest_IsWorkInProgress(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())

Expand Down
4 changes: 0 additions & 4 deletions models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -994,10 +994,6 @@ func ChangeUserName(u *User, newUserName string) (err error) {
return ErrUserAlreadyExist{newUserName}
}

if err = ChangeUsernameInPullRequests(u.Name, newUserName); err != nil {
return fmt.Errorf("ChangeUsernameInPullRequests: %v", err)
}

// Do not fail if directory does not exist
if err = os.Rename(UserPath(u.Name), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("Rename user directory: %v", err)
Expand Down
15 changes: 7 additions & 8 deletions modules/migrations/gitea.go
Original file line number Diff line number Diff line change
Expand Up @@ -579,14 +579,13 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
}

var pullRequest = models.PullRequest{
HeadRepoID: g.repo.ID,
HeadBranch: head,
HeadUserName: g.repoOwner,
BaseRepoID: g.repo.ID,
BaseBranch: pr.Base.Ref,
MergeBase: pr.Base.SHA,
Index: pr.Number,
HasMerged: pr.Merged,
HeadRepoID: g.repo.ID,
HeadBranch: head,
BaseRepoID: g.repo.ID,
BaseBranch: pr.Base.Ref,
MergeBase: pr.Base.SHA,
Index: pr.Number,
HasMerged: pr.Merged,

Issue: &issue,
}
Expand Down
19 changes: 9 additions & 10 deletions routers/api/v1/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
)

// Get repo/branch information
headUser, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form)
_, headRepo, headGitRepo, compareInfo, baseBranch, headBranch := parseCompareInfo(ctx, form)
if ctx.Written() {
return
}
Expand Down Expand Up @@ -265,15 +265,14 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
DeadlineUnix: deadlineUnix,
}
pr := &models.PullRequest{
HeadRepoID: headRepo.ID,
BaseRepoID: repo.ID,
HeadUserName: headUser.Name,
HeadBranch: headBranch,
BaseBranch: baseBranch,
HeadRepo: headRepo,
BaseRepo: repo,
MergeBase: compareInfo.MergeBase,
Type: models.PullRequestGitea,
HeadRepoID: headRepo.ID,
BaseRepoID: repo.ID,
HeadBranch: headBranch,
BaseBranch: baseBranch,
HeadRepo: headRepo,
BaseRepo: repo,
MergeBase: compareInfo.MergeBase,
Type: models.PullRequestGitea,
}

// Get all assignee IDs
Expand Down
31 changes: 15 additions & 16 deletions routers/repo/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,12 @@ func checkPullInfo(ctx *context.Context) *models.Issue {
}

func setMergeTarget(ctx *context.Context, pull *models.PullRequest) {
if ctx.Repo.Owner.Name == pull.HeadUserName {
if ctx.Repo.Owner.Name == pull.MustHeadUserName() {
ctx.Data["HeadTarget"] = pull.HeadBranch
} else if pull.HeadRepo == nil {
ctx.Data["HeadTarget"] = pull.HeadUserName + ":" + pull.HeadBranch
ctx.Data["HeadTarget"] = pull.MustHeadUserName() + ":" + pull.HeadBranch
} else {
ctx.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch
ctx.Data["HeadTarget"] = pull.MustHeadUserName() + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch
}
ctx.Data["BaseTarget"] = pull.BaseBranch
}
Expand Down Expand Up @@ -440,7 +440,7 @@ func ViewPullCommits(ctx *context.Context) {
ctx.NotFound("ViewPullCommits", nil)
return
}
ctx.Data["Username"] = pull.HeadUserName
ctx.Data["Username"] = pull.MustHeadUserName()
ctx.Data["Reponame"] = pull.HeadRepo.Name
commits = prInfo.Commits
}
Expand Down Expand Up @@ -512,7 +512,7 @@ func ViewPullFiles(ctx *context.Context) {
return
}

headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name)
headRepoPath := pull.HeadRepo.RepoPath()

headGitRepo, err := git.OpenRepository(headRepoPath)
if err != nil {
Expand All @@ -531,8 +531,8 @@ func ViewPullFiles(ctx *context.Context) {
endCommitID = headCommitID
gitRepo = headGitRepo

headTarget = path.Join(pull.HeadUserName, pull.HeadRepo.Name)
ctx.Data["Username"] = pull.HeadUserName
headTarget = path.Join(pull.MustHeadUserName(), pull.HeadRepo.Name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pull.HeadRepo.RepoPath() ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guillep2k No. pull.HeadRepo.RepoPath() will return repo's location on file system. But here we need a headTarget.

ctx.Data["Username"] = pull.MustHeadUserName()
ctx.Data["Reponame"] = pull.HeadRepo.Name
}

Expand Down Expand Up @@ -754,15 +754,14 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
Content: form.Content,
}
pullRequest := &models.PullRequest{
HeadRepoID: headRepo.ID,
BaseRepoID: repo.ID,
HeadUserName: headUser.Name,
HeadBranch: headBranch,
BaseBranch: baseBranch,
HeadRepo: headRepo,
BaseRepo: repo,
MergeBase: prInfo.MergeBase,
Type: models.PullRequestGitea,
HeadRepoID: headRepo.ID,
BaseRepoID: repo.ID,
HeadBranch: headBranch,
BaseBranch: baseBranch,
HeadRepo: headRepo,
BaseRepo: repo,
MergeBase: prInfo.MergeBase,
Type: models.PullRequestGitea,
}
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
// instead of 500.
Expand Down
11 changes: 7 additions & 4 deletions services/pull/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
}
}()

headRepoPath := models.RepoPath(pr.HeadUserName, pr.HeadRepo.Name)
headRepoPath := pr.HeadRepo.RepoPath()

if err := git.InitRepository(tmpBasePath, false); err != nil {
return fmt.Errorf("git init: %v", err)
Expand Down Expand Up @@ -306,14 +306,17 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
}
}

headUser, err := models.GetUserByName(pr.HeadUserName)
var headUser *models.User
err = pr.HeadRepo.GetOwner()
if err != nil {
if !models.IsErrUserNotExist(err) {
log.Error("Can't find user: %s for head repository - %v", pr.HeadUserName, err)
log.Error("Can't find user: %d for head repository - %v", pr.HeadRepo.OwnerID, err)
return err
}
log.Error("Can't find user: %s for head repository - defaulting to doer: %s - %v", pr.HeadUserName, doer.Name, err)
log.Error("Can't find user: %d for head repository - defaulting to doer: %s - %v", pr.HeadRepo.OwnerID, doer.Name, err)
headUser = doer
} else {
headUser = pr.HeadRepo.Owner
}

env = models.FullPushingEnvironment(
Expand Down