Skip to content

Commit 851c9e8

Browse files
committed
Merge branch 'also_auto-merge_on_review_updates' of github.com:6543-forks/gitea into 6543-forks-also_auto-merge_on_review_updates
2 parents 8b36324 + 7432f99 commit 851c9e8

File tree

4 files changed

+118
-42
lines changed

4 files changed

+118
-42
lines changed

models/issues/review.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,14 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) {
155155
if r.CodeComments != nil {
156156
return err
157157
}
158-
if err = r.loadIssue(ctx); err != nil {
158+
if err = r.LoadIssue(ctx); err != nil {
159159
return err
160160
}
161161
r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r, false)
162162
return err
163163
}
164164

165-
func (r *Review) loadIssue(ctx context.Context) (err error) {
165+
func (r *Review) LoadIssue(ctx context.Context) (err error) {
166166
if r.Issue != nil {
167167
return err
168168
}
@@ -199,7 +199,7 @@ func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
199199

200200
// LoadAttributes loads all attributes except CodeComments
201201
func (r *Review) LoadAttributes(ctx context.Context) (err error) {
202-
if err = r.loadIssue(ctx); err != nil {
202+
if err = r.LoadIssue(ctx); err != nil {
203203
return err
204204
}
205205
if err = r.LoadCodeComments(ctx); err != nil {

services/automerge/automerge.go

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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
3233
func 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
6366
func 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+
// StartPullRequestAutoMergeCheckBySHA start an automerge check task for repository and SHA
92+
func StartPullRequestAutoMergeCheckBySHA(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,33 @@ func MergeScheduledPullRequest(ctx context.Context, sha string, repo *repo_model
111104
return nil
112105
}
113106

107+
// StartPullRequestAutoMergeCheck start an automerge check task for a pull request
108+
func StartPullRequestAutoMergeCheck(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+
125+
commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
126+
if err != nil {
127+
log.Error("GetRefCommitID: %v", err)
128+
return
129+
}
130+
131+
addToQueue(pull, commitID)
132+
}
133+
114134
func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) {
115135
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
116136
if err != nil {
@@ -161,7 +181,8 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.
161181
return pulls, nil
162182
}
163183

164-
func handlePull(pullID int64, sha string) {
184+
// handlePullRequestAutoMerge merge the pull request if all checks are successful
185+
func handlePullRequestAutoMerge(pullID int64, sha string) {
165186
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(),
166187
fmt.Sprintf("Handle AutoMerge of PR[%d] with sha[%s]", pullID, sha))
167188
defer finished()
@@ -182,24 +203,50 @@ func handlePull(pullID int64, sha string) {
182203
return
183204
}
184205

206+
if err = pr.LoadBaseRepo(ctx); err != nil {
207+
log.Error("%-v LoadBaseRepo: %v", pr, err)
208+
return
209+
}
210+
211+
// check the sha is the same as pull request head commit id
212+
baseGitRepo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
213+
if err != nil {
214+
log.Error("OpenRepository: %v", err)
215+
return
216+
}
217+
defer baseGitRepo.Close()
218+
219+
headCommitID, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
220+
if err != nil {
221+
log.Error("GetRefCommitID: %v", err)
222+
return
223+
}
224+
if headCommitID != sha {
225+
log.Warn("Head commit id of auto merge %-v does not match sha [%s]", pr, sha)
226+
return
227+
}
228+
185229
// Get all checks for this pr
186230
// We get the latest sha commit hash again to handle the case where the check of a previous push
187231
// did not succeed or was not finished yet.
188-
189232
if err = pr.LoadHeadRepo(ctx); err != nil {
190233
log.Error("%-v LoadHeadRepo: %v", pr, err)
191234
return
192235
}
193236

194-
headGitRepo, err := gitrepo.OpenRepository(ctx, pr.HeadRepo)
195-
if err != nil {
196-
log.Error("OpenRepository %-v: %v", pr.HeadRepo, err)
197-
return
237+
var headGitRepo *git.Repository
238+
if pr.BaseRepoID == pr.HeadRepoID {
239+
headGitRepo = baseGitRepo
240+
} else {
241+
headGitRepo, err = gitrepo.OpenRepository(ctx, pr.HeadRepo)
242+
if err != nil {
243+
log.Error("OpenRepository %-v: %v", pr.HeadRepo, err)
244+
return
245+
}
246+
defer headGitRepo.Close()
198247
}
199-
defer headGitRepo.Close()
200248

201249
headBranchExist := headGitRepo.IsBranchExist(pr.HeadBranch)
202-
203250
if pr.HeadRepo == nil || !headBranchExist {
204251
log.Warn("Head branch of auto merge %-v does not exist [HeadRepoID: %d, Branch: %s]", pr, pr.HeadRepoID, pr.HeadBranch)
205252
return
@@ -238,23 +285,6 @@ func handlePull(pullID int64, sha string) {
238285
return
239286
}
240287

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-
258288
if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil {
259289
log.Error("pull_service.Merge: %v", err)
260290
return

services/automerge/notify.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package automerge
5+
6+
import (
7+
"context"
8+
9+
issues_model "code.gitea.io/gitea/models/issues"
10+
user_model "code.gitea.io/gitea/models/user"
11+
"code.gitea.io/gitea/modules/log"
12+
notify_service "code.gitea.io/gitea/services/notify"
13+
)
14+
15+
type automergeNotifier struct {
16+
notify_service.NullNotifier
17+
}
18+
19+
var _ notify_service.Notifier = &automergeNotifier{}
20+
21+
// NewNotifier create a new automergeNotifier notifier
22+
func NewNotifier() notify_service.Notifier {
23+
return &automergeNotifier{}
24+
}
25+
26+
func (n *automergeNotifier) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
27+
// as a missing / blocking reviews could have blocked a pending automerge let's recheck
28+
if review.Type == issues_model.ReviewTypeApprove {
29+
if err := StartPullRequestAutoMergeCheckBySHA(ctx, review.CommitID, pr.BaseRepo); err != nil {
30+
log.Error("StartPullRequestAutoMergeCheckBySHA: %v", err)
31+
}
32+
}
33+
}
34+
35+
func (n *automergeNotifier) PullReviewDismiss(ctx context.Context, doer *user_model.User, review *issues_model.Review, comment *issues_model.Comment) {
36+
if err := review.LoadIssue(ctx); err != nil {
37+
log.Error("LoadIssue: %v", err)
38+
return
39+
}
40+
if err := review.Issue.LoadPullRequest(ctx); err != nil {
41+
log.Error("LoadPullRequest: %v", err)
42+
return
43+
}
44+
// as reviews could have blocked a pending automerge let's recheck
45+
StartPullRequestAutoMergeCheck(ctx, review.Issue.PullRequest)
46+
}

services/repository/commitstatus/commitstatus.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
117117
}
118118

119119
if status.State.IsSuccess() {
120-
if err := automerge.MergeScheduledPullRequest(ctx, sha, repo); err != nil {
120+
if err := automerge.StartPullRequestAutoMergeCheckBySHA(ctx, sha, repo); err != nil {
121121
return fmt.Errorf("MergeScheduledPullRequest[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
122122
}
123123
}

0 commit comments

Comments
 (0)