mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-03 21:08:25 +00:00 
			
		
		
		
	Backport #31207 by @lunny Fix #31134 Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
		@@ -26,7 +26,7 @@
 | 
				
			|||||||
  fork_id: 0
 | 
					  fork_id: 0
 | 
				
			||||||
  is_template: false
 | 
					  is_template: false
 | 
				
			||||||
  template_id: 0
 | 
					  template_id: 0
 | 
				
			||||||
  size: 7320
 | 
					  size: 7597
 | 
				
			||||||
  is_fsck_enabled: true
 | 
					  is_fsck_enabled: true
 | 
				
			||||||
  close_issues_via_commit_in_any_branch: false
 | 
					  close_issues_via_commit_in_any_branch: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -245,11 +245,23 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
 | 
				
			|||||||
		defer headGitRepo.Close()
 | 
							defer headGitRepo.Close()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch pr.Flow {
 | 
				
			||||||
 | 
						case issues_model.PullRequestFlowGithub:
 | 
				
			||||||
		headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch)
 | 
							headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch)
 | 
				
			||||||
		if pr.HeadRepo == nil || !headBranchExist {
 | 
							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)
 | 
								log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch)
 | 
				
			||||||
			return
 | 
								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
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check if all checks succeeded
 | 
						// Check if all checks succeeded
 | 
				
			||||||
	pass, err := pull_service.IsPullCommitStatusPass(ctx, pr)
 | 
						pass, err := pull_service.IsPullCommitStatusPass(ctx, pr)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive
									
									
									
									
									
										Executable file
									
								
							@@ -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
 | 
				
			||||||
							
								
								
									
										2
									
								
								tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive.d/gitea
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								tests/gitea-repositories-meta/user2/repo1.git/hooks/proc-receive.d/gitea
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" proc-receive
 | 
				
			||||||
@@ -31,6 +31,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/git"
 | 
						"code.gitea.io/gitea/modules/git"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/gitrepo"
 | 
						"code.gitea.io/gitea/modules/gitrepo"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/queue"
 | 
						"code.gitea.io/gitea/modules/queue"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/test"
 | 
						"code.gitea.io/gitea/modules/test"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/translation"
 | 
						"code.gitea.io/gitea/modules/translation"
 | 
				
			||||||
@@ -846,3 +847,132 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) {
 | 
				
			|||||||
		unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID})
 | 
							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})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user