@@ -6,13 +6,16 @@ package integration
66import (
77 "fmt"
88 "net/url"
9+ "strings"
910 "testing"
1011 "time"
1112
1213 auth_model "code.gitea.io/gitea/models/auth"
1314 issues_model "code.gitea.io/gitea/models/issues"
15+ repo_model "code.gitea.io/gitea/models/repo"
1416 "code.gitea.io/gitea/models/unittest"
1517 user_model "code.gitea.io/gitea/models/user"
18+ "code.gitea.io/gitea/modules/git/gitcmd"
1619 "code.gitea.io/gitea/modules/setting"
1720 api "code.gitea.io/gitea/modules/structs"
1821
@@ -26,7 +29,6 @@ func TestManualMergeAutodetect(t *testing.T) {
2629 // user1 is the pusher/merger
2730 user1 := unittest .AssertExistsAndLoadBean (t , & user_model.User {ID : 1 })
2831 user2 := unittest .AssertExistsAndLoadBean (t , & user_model.User {ID : 2 })
29- session2 := loginUser (t , user2 .Name )
3032
3133 // Create a repo owned by user2
3234 repoName := "manual-merge-autodetect"
@@ -41,35 +43,62 @@ func TestManualMergeAutodetect(t *testing.T) {
4143 AutodetectManualMerge : new (true ),
4244 })(t )
4345
44- // Create a PR from a branch
45- branchName := "feature"
46- testEditFileToNewBranch (t , session2 , user2 .Name , repoName , defaultBranch , branchName , "README.md" , "Manual Merge Test" )
46+ repo := unittest .AssertExistsAndLoadBean (t , & repo_model.Repository {Name : repoName })
47+ user1Ctx := NewAPITestContext (t , user1 .Name , repoName , auth_model .AccessTokenScopeWriteRepository )
4748
48- apiPull , err := doAPICreatePullRequest (NewAPITestContext (t , user1 .Name , repoName , auth_model .AccessTokenScopeWriteRepository ), user2 .Name , repoName , defaultBranch , branchName )(t )
49- assert .NoError (t , err )
49+ // multiple PRs should be able to be closed together if a push contains their branch commits.
50+ branchNames := []string {"fix-1" , "fix-2" }
51+ apiPulls := make ([]api.PullRequest , len (branchNames ))
52+ for i , branchName := range branchNames {
53+ _ , err := createFileInBranch (user2 , repo ,
54+ createFileInBranchOptions {OldBranch : defaultBranch , NewBranch : branchName },
55+ map [string ]string {"test-file-" + branchName : "dummy" },
56+ )
57+ require .NoError (t , err )
58+ apiPulls [i ], err = doAPICreatePullRequest (user1Ctx , user2 .Name , repoName , defaultBranch , branchName )(t )
59+ require .NoError (t , err )
60+ }
5061
51- // user1 clones and pushes the branch to master (fast-forward)
62+ // user1 clones, then merges every branch sequentially, then pushes once.
63+ // The first merge fast-forwards; the rest produce real merge commits,
64+ // which generates multiple commits for "git rev-list --ancestry-path --merges ...".
5265 dstPath := t .TempDir ()
5366 u , _ := url .Parse (giteaURL .String ())
5467 u .Path = fmt .Sprintf ("%s/%s.git" , user2 .Name , repoName )
5568 u .User = url .UserPassword (user1 .Name , userPassword )
5669
5770 doGitClone (dstPath , u )(t )
58- doGitMerge (dstPath , "origin/" + branchName )(t )
71+
72+ // Capture each branch's expected merge commit hash from the local clone,
73+ // so we can assert that Gitea recorded the correct merge commit per PR
74+ // (and not just "some merge commit" — see the regression where every PR
75+ // was attributed to the last merge in the push).
76+ expectedMergeCommits := make ([]string , len (branchNames ))
77+ for i , branchName := range branchNames {
78+ doGitMerge (dstPath , "--no-ff" , "-m" , "merge " + branchName , "origin/" + branchName )(t )
79+ head , _ , cmdErr := gitcmd .NewCommand ("rev-parse" , "HEAD" ).WithDir (dstPath ).RunStdString (t .Context ())
80+ require .NoError (t , cmdErr )
81+ expectedMergeCommits [i ] = strings .TrimSpace (head )
82+ }
5983 doGitPushTestRepository (dstPath , "origin" , defaultBranch )(t )
6084
61- // Wait for the PR to be marked as merged by the background task
62- var pr * issues_model.PullRequest
85+ // Every PR should be detected as manually merged by the background task, not just the last one.
6386 require .Eventually (t , func () bool {
64- pr = unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
65- return pr .HasMerged
87+ for _ , apiPull := range apiPulls {
88+ pr := unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
89+ if ! pr .HasMerged {
90+ return false
91+ }
92+ }
93+ return true
6694 }, 10 * time .Second , 100 * time .Millisecond )
6795
68- // Check if the PR is merged and who is the merger
69- pr = unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
70- assert .True (t , pr .HasMerged )
71- assert .Equal (t , issues_model .PullRequestStatusManuallyMerged , pr .Status )
72- // Merger should be user1 (the pusher), not the commit author (user2) or repo owner (user2)
73- assert .Equal (t , user1 .ID , pr .MergerID )
96+ for i , apiPull := range apiPulls {
97+ pr := unittest .AssertExistsAndLoadBean (t , & issues_model.PullRequest {ID : apiPull .ID })
98+ assert .Truef (t , pr .HasMerged , "PR %d (%s) should be marked as merged" , i + 1 , branchNames [i ])
99+ assert .Equalf (t , issues_model .PullRequestStatusManuallyMerged , pr .Status , "PR %d (%s) should have ManuallyMerged status" , i + 1 , branchNames [i ])
100+ assert .Equalf (t , user1 .ID , pr .MergerID , "PR %d (%s) merger should be the pusher" , i + 1 , branchNames [i ])
101+ 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 ])
102+ }
74103 })
75104}
0 commit comments