@@ -22,6 +22,7 @@ import (
2222 "code.gitea.io/gitea/modules/log"
2323 "code.gitea.io/gitea/modules/process"
2424 "code.gitea.io/gitea/modules/queue"
25+ notify_service "code.gitea.io/gitea/services/notify"
2526 pull_service "code.gitea.io/gitea/services/pull"
2627)
2728
@@ -30,6 +31,8 @@ var prAutoMergeQueue *queue.WorkerPoolQueue[string]
3031
3132// Init runs the task queue to that handles auto merges
3233func Init () error {
34+ notify_service .RegisterNotifier (NewNotifier ())
35+
3336 prAutoMergeQueue = queue .CreateUniqueQueue (graceful .GetManager ().ShutdownContext (), "pr_auto_merge" , handler )
3437 if prAutoMergeQueue == nil {
3538 return fmt .Errorf ("unable to create pr_auto_merge queue" )
@@ -47,7 +50,7 @@ func handler(items ...string) []string {
4750 log .Error ("could not parse data from pr_auto_merge queue (%v): %v" , s , err )
4851 continue
4952 }
50- handlePull (id , sha )
53+ handlePullRequestAutoMerge (id , sha )
5154 }
5255 return nil
5356}
@@ -62,16 +65,6 @@ func addToQueue(pr *issues_model.PullRequest, sha string) {
6265// ScheduleAutoMerge if schedule is false and no error, pull can be merged directly
6366func ScheduleAutoMerge (ctx context.Context , doer * user_model.User , pull * issues_model.PullRequest , style repo_model.MergeStyle , message string ) (scheduled bool , err error ) {
6467 err = db .WithTx (ctx , func (ctx context.Context ) error {
65- lastCommitStatus , err := pull_service .GetPullRequestCommitStatusState (ctx , pull )
66- if err != nil {
67- return err
68- }
69-
70- // we don't need to schedule
71- if lastCommitStatus .IsSuccess () {
72- return nil
73- }
74-
7568 if err := pull_model .ScheduleAutoMerge (ctx , doer , pull .ID , style , message ); err != nil {
7669 return err
7770 }
@@ -95,8 +88,8 @@ func RemoveScheduledAutoMerge(ctx context.Context, doer *user_model.User, pull *
9588 })
9689}
9790
98- // MergeScheduledPullRequest merges a previously scheduled pull request when all checks succeeded
99- func MergeScheduledPullRequest (ctx context.Context , sha string , repo * repo_model.Repository ) error {
91+ // StartPRCheckAndAutoMergeBySHA start an automerge check and auto merge task for all pull requests of repository and SHA
92+ func StartPRCheckAndAutoMergeBySHA (ctx context.Context , sha string , repo * repo_model.Repository ) error {
10093 pulls , err := getPullRequestsByHeadSHA (ctx , sha , repo , func (pr * issues_model.PullRequest ) bool {
10194 return ! pr .HasMerged && pr .CanAutoMerge ()
10295 })
@@ -111,6 +104,32 @@ func MergeScheduledPullRequest(ctx context.Context, sha string, repo *repo_model
111104 return nil
112105}
113106
107+ // StartPRCheckAndAutoMerge start an automerge check and auto merge task for a pull request
108+ func StartPRCheckAndAutoMerge (ctx context.Context , pull * issues_model.PullRequest ) {
109+ if pull == nil || pull .HasMerged || ! pull .CanAutoMerge () {
110+ return
111+ }
112+
113+ if err := pull .LoadBaseRepo (ctx ); err != nil {
114+ log .Error ("LoadBaseRepo: %v" , err )
115+ return
116+ }
117+
118+ gitRepo , err := gitrepo .OpenRepository (ctx , pull .BaseRepo )
119+ if err != nil {
120+ log .Error ("OpenRepository: %v" , err )
121+ return
122+ }
123+ defer gitRepo .Close ()
124+ commitID , err := gitRepo .GetRefCommitID (pull .GetGitRefName ())
125+ if err != nil {
126+ log .Error ("GetRefCommitID: %v" , err )
127+ return
128+ }
129+
130+ addToQueue (pull , commitID )
131+ }
132+
114133func getPullRequestsByHeadSHA (ctx context.Context , sha string , repo * repo_model.Repository , filter func (* issues_model.PullRequest ) bool ) (map [int64 ]* issues_model.PullRequest , error ) {
115134 gitRepo , err := gitrepo .OpenRepository (ctx , repo )
116135 if err != nil {
@@ -161,7 +180,8 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.
161180 return pulls , nil
162181}
163182
164- func handlePull (pullID int64 , sha string ) {
183+ // handlePullRequestAutoMerge merge the pull request if all checks are successful
184+ func handlePullRequestAutoMerge (pullID int64 , sha string ) {
165185 ctx , _ , finished := process .GetManager ().AddContext (graceful .GetManager ().HammerContext (),
166186 fmt .Sprintf ("Handle AutoMerge of PR[%d] with sha[%s]" , pullID , sha ))
167187 defer finished ()
@@ -182,24 +202,50 @@ func handlePull(pullID int64, sha string) {
182202 return
183203 }
184204
205+ if err = pr .LoadBaseRepo (ctx ); err != nil {
206+ log .Error ("%-v LoadBaseRepo: %v" , pr , err )
207+ return
208+ }
209+
210+ // check the sha is the same as pull request head commit id
211+ baseGitRepo , err := gitrepo .OpenRepository (ctx , pr .BaseRepo )
212+ if err != nil {
213+ log .Error ("OpenRepository: %v" , err )
214+ return
215+ }
216+ defer baseGitRepo .Close ()
217+
218+ headCommitID , err := baseGitRepo .GetRefCommitID (pr .GetGitRefName ())
219+ if err != nil {
220+ log .Error ("GetRefCommitID: %v" , err )
221+ return
222+ }
223+ if headCommitID != sha {
224+ log .Warn ("Head commit id of auto merge %-v does not match sha [%s], it may means the head branch has been updated. Just ignore this request because a new request expected in the queue" , pr , sha )
225+ return
226+ }
227+
185228 // Get all checks for this pr
186229 // We get the latest sha commit hash again to handle the case where the check of a previous push
187230 // did not succeed or was not finished yet.
188-
189231 if err = pr .LoadHeadRepo (ctx ); err != nil {
190232 log .Error ("%-v LoadHeadRepo: %v" , pr , err )
191233 return
192234 }
193235
194- headGitRepo , err := gitrepo .OpenRepository (ctx , pr .HeadRepo )
195- if err != nil {
196- log .Error ("OpenRepository %-v: %v" , pr .HeadRepo , err )
197- return
236+ var headGitRepo * git.Repository
237+ if pr .BaseRepoID == pr .HeadRepoID {
238+ headGitRepo = baseGitRepo
239+ } else {
240+ headGitRepo , err = gitrepo .OpenRepository (ctx , pr .HeadRepo )
241+ if err != nil {
242+ log .Error ("OpenRepository %-v: %v" , pr .HeadRepo , err )
243+ return
244+ }
245+ defer headGitRepo .Close ()
198246 }
199- defer headGitRepo .Close ()
200247
201248 headBranchExist := headGitRepo .IsBranchExist (pr .HeadBranch )
202-
203249 if pr .HeadRepo == nil || ! headBranchExist {
204250 log .Warn ("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]" , pr , pr .HeadRepoID , pr .HeadBranch )
205251 return
@@ -238,25 +284,11 @@ func handlePull(pullID int64, sha string) {
238284 return
239285 }
240286
241- var baseGitRepo * git.Repository
242- if pr .BaseRepoID == pr .HeadRepoID {
243- baseGitRepo = headGitRepo
244- } else {
245- if err = pr .LoadBaseRepo (ctx ); err != nil {
246- log .Error ("%-v LoadBaseRepo: %v" , pr , err )
247- return
248- }
249-
250- baseGitRepo , err = gitrepo .OpenRepository (ctx , pr .BaseRepo )
251- if err != nil {
252- log .Error ("OpenRepository %-v: %v" , pr .BaseRepo , err )
253- return
254- }
255- defer baseGitRepo .Close ()
256- }
257-
258287 if err := pull_service .Merge (ctx , pr , doer , baseGitRepo , scheduledPRM .MergeStyle , "" , scheduledPRM .Message , true ); err != nil {
259288 log .Error ("pull_service.Merge: %v" , err )
289+ // FIXME: if merge failed, we should display some error message to the pull request page.
290+ // The resolution is add a new column on automerge table named `error_message` to store the error message and displayed
291+ // on the pull request page. But this should not be finished in a bug fix PR which will be backport to release branch.
260292 return
261293 }
262294}
0 commit comments