]> source.dussan.org Git - gitea.git/commitdiff
Fix agit automerge (#31207)
authorLunny Xiao <xiaolunwen@gmail.com>
Tue, 20 Aug 2024 06:17:21 +0000 (14:17 +0800)
committerGitHub <noreply@github.com>
Tue, 20 Aug 2024 06:17:21 +0000 (14:17 +0800)
models/fixtures/repository.yml
services/automerge/automerge.go
tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive [new file with mode: 0755]
tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive.d/gitea [new file with mode: 0755]
tests/integration/pull_merge_test.go

index e1f1dd73679b5b9a016e68e844221305a1e0e432..9adc6c855b1e531ad6366fa97ef746ee2c3c27f4 100644 (file)
@@ -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
 
index 10f3c28d56be4a4a9274f766076cff6fae6efd26..ed7a0141b9f3d4edf91ba895ac22f67a23b65f93 100644 (file)
@@ -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
        }
 
diff --git a/tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive b/tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive
new file mode 100755 (executable)
index 0000000..af2808b
--- /dev/null
@@ -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
diff --git a/tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive.d/gitea b/tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive.d/gitea
new file mode 100755 (executable)
index 0000000..97521c6
--- /dev/null
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" proc-receive
index 3e7054c7e83d2f3f1ae45917fa0f4841f43cd6ce..9a412329a1c0d4727ff2e6add8768673b18e96fb 100644 (file)
@@ -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"
@@ -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: "user2@example.com",
+                               Name:  "user2",
+                               When:  time.Now(),
+                       },
+                       Author: &git.Signature{
+                               Email: "user2@example.com",
+                               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})
+       })
+}