Skip to content

Commit

Permalink
Fix agit automerge (#31207) (#31881)
Browse files Browse the repository at this point in the history
Backport #31207 by @lunny

Fix #31134

Co-authored-by: Lunny Xiao <[email protected]>
  • Loading branch information
GiteaBot and lunny authored Aug 20, 2024
1 parent 0affb5c commit a0d1630
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 4 deletions.
2 changes: 1 addition & 1 deletion models/fixtures/repository.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
fork_id: 0
is_template: false
template_id: 0
size: 7320
size: 7597
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false

Expand Down
18 changes: 15 additions & 3 deletions services/automerge/automerge.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,21 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
defer headGitRepo.Close()
}

headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch)
if pr.HeadRepo == nil || !headBranchExist {
log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch)
switch pr.Flow {
case issues_model.PullRequestFlowGithub:
headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch)
if pr.HeadRepo == nil || !headBranchExist {
log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch)
return
}
case issues_model.PullRequestFlowAGit:
headBranchExist := git.IsReferenceExist(ctx, baseGitRepo.Path, pr.GetGitRefName())
if !headBranchExist {
log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch(Agit): %s]", pr, pr.HeadRepoID, pr.HeadBranch)
return
}
default:
log.Error("wrong flow type %d", pr.Flow)
return
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
ORI_DIR=`pwd`
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
cd "$ORI_DIR"
for i in `ls "$SHELL_FOLDER/proc-receive.d"`; do
sh "$SHELL_FOLDER/proc-receive.d/$i"
done
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" proc-receive
130 changes: 130 additions & 0 deletions tests/integration/pull_merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/queue"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/translation"
Expand Down Expand Up @@ -846,3 +847,132 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
})
}

func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
// create a pull request
baseAPITestContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)

dstPath := t.TempDir()

u.Path = baseAPITestContext.GitPath()
u.User = url.UserPassword("user2", userPassword)

t.Run("Clone", doGitClone(dstPath, u))

err := os.WriteFile(path.Join(dstPath, "test_file"), []byte("## test content"), 0o666)
assert.NoError(t, err)

err = git.AddChanges(dstPath, true)
assert.NoError(t, err)

err = git.CommitChanges(dstPath, git.CommitChangesOptions{
Committer: &git.Signature{
Email: "[email protected]",
Name: "user2",
When: time.Now(),
},
Author: &git.Signature{
Email: "[email protected]",
Name: "user2",
When: time.Now(),
},
Message: "Testing commit 1",
})
assert.NoError(t, err)

stderrBuf := &bytes.Buffer{}

err = git.NewCommand(git.DefaultContext, "push", "origin", "HEAD:refs/for/master", "-o").
AddDynamicArguments(`topic=test/head2`).
AddArguments("-o").
AddDynamicArguments(`title="create a test pull request with agit"`).
AddArguments("-o").
AddDynamicArguments(`description="This PR is a test pull request which created with agit"`).
Run(&git.RunOpts{Dir: dstPath, Stderr: stderrBuf})
assert.NoError(t, err)

assert.Contains(t, stderrBuf.String(), setting.AppURL+"user2/repo1/pulls/6")

baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
Flow: issues_model.PullRequestFlowAGit,
BaseRepoID: baseRepo.ID,
BaseBranch: "master",
HeadRepoID: baseRepo.ID,
HeadBranch: "user2/test/head2",
})

session := loginUser(t, "user1")
// add protected branch for commit status
csrf := GetCSRF(t, session, "/user2/repo1/settings/branches")
// Change master branch to protected
req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{
"_csrf": csrf,
"rule_name": "master",
"enable_push": "true",
"enable_status_check": "true",
"status_check_contexts": "gitea/actions",
"required_approvals": "1",
})
session.MakeRequest(t, req, http.StatusSeeOther)

user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
// first time insert automerge record, return true
scheduled, err := automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
assert.NoError(t, err)
assert.True(t, scheduled)

// second time insert automerge record, return false because it does exist
scheduled, err = automerge.ScheduleAutoMerge(db.DefaultContext, user1, pr, repo_model.MergeStyleMerge, "auto merge test")
assert.Error(t, err)
assert.False(t, scheduled)

// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.False(t, pr.HasMerged)
assert.Empty(t, pr.MergedCommitID)

// update commit status to success, then it should be merged automatically
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
assert.NoError(t, err)
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
assert.NoError(t, err)
masterCommitID, err := baseGitRepo.GetBranchCommitID("master")
assert.NoError(t, err)
baseGitRepo.Close()
defer func() {
testResetRepo(t, baseRepo.RepoPath(), "master", masterCommitID)
}()

err = commitstatus_service.CreateCommitStatus(db.DefaultContext, baseRepo, user1, sha, &git_model.CommitStatus{
State: api.CommitStatusSuccess,
TargetURL: "https://gitea.com",
Context: "gitea/actions",
})
assert.NoError(t, err)

time.Sleep(2 * time.Second)

// reload pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.False(t, pr.HasMerged)
assert.Empty(t, pr.MergedCommitID)

// approve the PR from non-author
approveSession := loginUser(t, "user1")
req = NewRequest(t, "GET", fmt.Sprintf("/user2/repo1/pulls/%d", pr.Index))
resp := approveSession.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
testSubmitReview(t, approveSession, htmlDoc.GetCSRF(), "user2", "repo1", strconv.Itoa(int(pr.Index)), sha, "approve", http.StatusOK)

time.Sleep(2 * time.Second)

// realod pr again
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID})
assert.True(t, pr.HasMerged)
assert.NotEmpty(t, pr.MergedCommitID)

unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
})
}

0 comments on commit a0d1630

Please sign in to comment.