@@ -12,6 +12,7 @@ import (
1212
1313 auth_model "code.gitea.io/gitea/models/auth"
1414 issues_model "code.gitea.io/gitea/models/issues"
15+ repo_model "code.gitea.io/gitea/models/repo"
1516 "code.gitea.io/gitea/models/unittest"
1617 user_model "code.gitea.io/gitea/models/user"
1718 "code.gitea.io/gitea/modules/git/gitcmd"
@@ -28,9 +29,7 @@ func TestManualMergeAutodetect(t *testing.T) {
2829 // user1 is the pusher/merger
2930 user1 := unittest .AssertExistsAndLoadBean (t , & user_model.User {ID : 1 })
3031 user2 := unittest .AssertExistsAndLoadBean (t , & user_model.User {ID : 2 })
31- session2 := loginUser (t , user2 .Name )
3232
33- // Create a repo owned by user2
3433 repoName := "manual-merge-autodetect"
3534 defaultBranch := setting .Repository .DefaultBranch
3635 user2Ctx := NewAPITestContext (t , user2 .Name , repoName , auth_model .AccessTokenScopeWriteRepository , auth_model .AccessTokenScopeWriteUser )
@@ -43,104 +42,31 @@ func TestManualMergeAutodetect(t *testing.T) {
4342 AutodetectManualMerge : new (true ),
4443 })(t )
4544
46- // Create a PR from a branch
47- branchName := "feature"
48- testEditFileToNewBranch (t , session2 , user2 .Name , repoName , defaultBranch , branchName , "README.md" , "Manual Merge Test" )
45+ repo := unittest .AssertExistsAndLoadBean (t , & repo_model.Repository {Name : repoName })
46+ user1Ctx := NewAPITestContext (t , user1 .Name , repoName , auth_model .AccessTokenScopeWriteRepository )
4947
50- apiPull , err := doAPICreatePullRequest (NewAPITestContext (t , user1 .Name , repoName , auth_model .AccessTokenScopeWriteRepository ), user2 .Name , repoName , defaultBranch , branchName )(t )
51- assert .NoError (t , err )
52-
53- // user1 clones and pushes the branch to master (fast-forward)
54- dstPath := t .TempDir ()
55- u , _ := url .Parse (giteaURL .String ())
56- u .Path = fmt .Sprintf ("%s/%s.git" , user2 .Name , repoName )
57- u .User = url .UserPassword (user1 .Name , userPassword )
58-
59- doGitClone (dstPath , u )(t )
60- doGitMerge (dstPath , "origin/" + branchName )(t )
61- doGitPushTestRepository (dstPath , "origin" , defaultBranch )(t )
62-
63- // Wait for the PR to be marked as merged by the background task
64- var pr * issues_model.PullRequest
65- require .Eventually (t , func () bool {
66- pr = unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
67- return pr .HasMerged
68- }, 10 * time .Second , 100 * time .Millisecond )
69-
70- // Check if the PR is merged and who is the merger
71- pr = unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
72- assert .True (t , pr .HasMerged )
73- assert .Equal (t , issues_model .PullRequestStatusManuallyMerged , pr .Status )
74- // Merger should be user1 (the pusher), not the commit author (user2) or repo owner (user2)
75- assert .Equal (t , user1 .ID , pr .MergerID )
76- })
77- }
78-
79- // TestManualMergeAutodetectMultiplePRs covers the case where several PRs targeting
80- // the same base branch are merged locally in sequence and pushed in a single push.
81- //
82- // Reproduces the regression where only the last PR's merge commit is detected.
83- // The "git rev-list --ancestry-path --merges --reverse <prHead>..<base>" output
84- // in services/pull/check.go:getMergeCommit returns multiple lines for any PR that
85- // is not the most recent merge, and the multi-line value is forwarded to
86- // gitRepo.GetCommit, which (since Gitea moved to "git cat-file --batch-command"
87- // in #35775) kills the repository's cached cat-file process and breaks the
88- // follow-up commit lookup.
89- func TestManualMergeAutodetectMultiplePRs (t * testing.T ) {
90- onGiteaRun (t , func (t * testing.T , giteaURL * url.URL ) {
91- // user2 is the repo owner
92- // user1 is the pusher/merger
93- user1 := unittest .AssertExistsAndLoadBean (t , & user_model.User {ID : 1 })
94- user2 := unittest .AssertExistsAndLoadBean (t , & user_model.User {ID : 2 })
95- session2 := loginUser (t , user2 .Name )
96-
97- // Create a repo owned by user2
98- repoName := "manual-merge-autodetect-multi"
99- defaultBranch := setting .Repository .DefaultBranch
100- user2Ctx := NewAPITestContext (t , user2 .Name , repoName , auth_model .AccessTokenScopeWriteRepository , auth_model .AccessTokenScopeWriteUser )
101- doAPICreateRepository (user2Ctx , false )(t )
102-
103- // Enable autodetect manual merge
104- doAPIEditRepository (user2Ctx , & api.EditRepoOption {
105- HasPullRequests : new (true ),
106- AllowManualMerge : new (true ),
107- AutodetectManualMerge : new (true ),
108- })(t )
109-
110- // Create three branches from the default branch, each adding its own file,
111- // and open a PR for each of them targeting the default branch. Each branch
112- // touches a distinct file so the sequential merges don't conflict.
113- branchNames := []string {"fix-1" , "fix-2" , "fix-3" }
48+ // multiple PRs should be able to be closed together if a commit contains their branch commits.
49+ branchNames := []string {"fix-1" , "fix-2" }
11450 apiPulls := make ([]api.PullRequest , len (branchNames ))
11551 for i , branchName := range branchNames {
116- testCreateFile (t , session2 , user2 .Name , repoName , defaultBranch , branchName ,
117- fmt .Sprintf ("file-%d.txt" , i + 1 ), fmt .Sprintf ("manual merge multi-PR test %d" , i + 1 ))
118-
119- pr , err := doAPICreatePullRequest (
120- NewAPITestContext (t , user1 .Name , repoName , auth_model .AccessTokenScopeWriteRepository ),
121- user2 .Name , repoName , defaultBranch , branchName ,
122- )(t )
52+ _ , err := createFileInBranch (user2 , repo ,
53+ createFileInBranchOptions {OldBranch : defaultBranch , NewBranch : branchName },
54+ map [string ]string {"test-file-" + branchName : "dummy" },
55+ )
56+ require .NoError (t , err )
57+ apiPulls [i ], err = doAPICreatePullRequest (user1Ctx , user2 .Name , repoName , defaultBranch , branchName )(t )
12358 require .NoError (t , err )
124- apiPulls [i ] = pr
12559 }
12660
12761 // user1 clones, then merges every branch sequentially, then pushes once.
128- // The first merge fast-forwards; the rest produce real merge commits, which
129- // is exactly the situation that breaks " ancestry-path --merges --reverse".
62+ // The first merge fast-forwards; the rest produce real merge commits,
63+ // which generates multiple commits for "git ancestry-path --merges --reverse".
13064 dstPath := t .TempDir ()
13165 u , _ := url .Parse (giteaURL .String ())
13266 u .Path = fmt .Sprintf ("%s/%s.git" , user2 .Name , repoName )
13367 u .User = url .UserPassword (user1 .Name , userPassword )
13468
13569 doGitClone (dstPath , u )(t )
136- // Set a committer/author on the local clone so "git merge" can create merge
137- // commits without falling back to a global identity.
138- _ , _ , err := gitcmd .NewCommand ("config" , "user.email" ).AddDynamicArguments (user1 .Email ).
139- WithDir (dstPath ).RunStdString (t .Context ())
140- require .NoError (t , err )
141- _ , _ , err = gitcmd .NewCommand ("config" , "user.name" ).AddDynamicArguments (user1 .Name ).
142- WithDir (dstPath ).RunStdString (t .Context ())
143- require .NoError (t , err )
14470
14571 // Capture each branch's expected merge commit hash from the local clone,
14672 // so we can assert that Gitea recorded the correct merge commit per PR
@@ -149,15 +75,13 @@ func TestManualMergeAutodetectMultiplePRs(t *testing.T) {
14975 expectedMergeCommits := make ([]string , len (branchNames ))
15076 for i , branchName := range branchNames {
15177 doGitMerge (dstPath , "--no-ff" , "-m" , "merge " + branchName , "origin/" + branchName )(t )
152- head , _ , cmdErr := gitcmd .NewCommand ("rev-parse" , "HEAD" ).
153- WithDir (dstPath ).RunStdString (t .Context ())
78+ head , _ , cmdErr := gitcmd .NewCommand ("rev-parse" , "HEAD" ).WithDir (dstPath ).RunStdString (t .Context ())
15479 require .NoError (t , cmdErr )
15580 expectedMergeCommits [i ] = strings .TrimSpace (head )
15681 }
15782 doGitPushTestRepository (dstPath , "origin" , defaultBranch )(t )
15883
159- // Every PR should be detected as manually merged by the background task,
160- // not just the last one.
84+ // Every PR should be detected as manually merged by the background task, not just the last one.
16185 require .Eventually (t , func () bool {
16286 for _ , apiPull := range apiPulls {
16387 pr := unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
@@ -166,17 +90,14 @@ func TestManualMergeAutodetectMultiplePRs(t *testing.T) {
16690 }
16791 }
16892 return true
169- }, 15 * time .Second , 200 * time .Millisecond )
93+ }, 10 * time .Second , 100 * time .Millisecond )
17094
17195 for i , apiPull := range apiPulls {
17296 pr := unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
17397 assert .Truef (t , pr .HasMerged , "PR %d (%s) should be marked as merged" , i + 1 , branchNames [i ])
174- assert .Equalf (t , issues_model .PullRequestStatusManuallyMerged , pr .Status ,
175- "PR %d (%s) should have ManuallyMerged status" , i + 1 , branchNames [i ])
176- assert .Equalf (t , user1 .ID , pr .MergerID ,
177- "PR %d (%s) merger should be the pusher" , i + 1 , branchNames [i ])
178- assert .Equalf (t , expectedMergeCommits [i ], pr .MergedCommitID ,
179- "PR %d (%s) should be attributed to its own merge commit, not another PR's" , i + 1 , branchNames [i ])
98+ assert .Equalf (t , issues_model .PullRequestStatusManuallyMerged , pr .Status , "PR %d (%s) should have ManuallyMerged status" , i + 1 , branchNames [i ])
99+ assert .Equalf (t , user1 .ID , pr .MergerID , "PR %d (%s) merger should be the pusher" , i + 1 , branchNames [i ])
100+ assert .Equalf (t , expectedMergeCommits [i ], pr .MergedCommitID , "PR %d (%s) should be attributed to its own merge commit, not another PR's" , i + 1 , branchNames [i ])
180101 }
181102 })
182103}
0 commit comments