Skip to content

Commit 123c8d2

Browse files
authored
Fix review request webhook bug (#35339) (#35596)
Frontport from #35339
1 parent b2f2f85 commit 123c8d2

File tree

6 files changed

+110
-29
lines changed

6 files changed

+110
-29
lines changed

services/pull/comment.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *iss
6969
if err != nil {
7070
return nil, err
7171
}
72+
if len(data.CommitIDs) == 0 {
73+
return nil, nil
74+
}
7275
}
7376

7477
dataJSON, err := json.Marshal(data)

services/pull/pull.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,20 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
156156

157157
issue_service.ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifiers)
158158

159+
// Request reviews, these should be requested before other notifications because they will add request reviews record
160+
// on database
161+
permDoer, err := access_model.GetUserRepoPermission(ctx, repo, issue.Poster)
162+
for _, reviewer := range opts.Reviewers {
163+
if _, err = issue_service.ReviewRequest(ctx, pr.Issue, issue.Poster, &permDoer, reviewer, true); err != nil {
164+
return err
165+
}
166+
}
167+
for _, teamReviewer := range opts.TeamReviewers {
168+
if _, err = issue_service.TeamReviewRequest(ctx, pr.Issue, issue.Poster, teamReviewer, true); err != nil {
169+
return err
170+
}
171+
}
172+
159173
mentions, err := issues_model.FindAndUpdateIssueMentions(ctx, issue, issue.Poster, issue.Content)
160174
if err != nil {
161175
return err
@@ -174,17 +188,7 @@ func NewPullRequest(ctx context.Context, opts *NewPullRequestOptions) error {
174188
}
175189
notify_service.IssueChangeAssignee(ctx, issue.Poster, issue, assignee, false, assigneeCommentMap[assigneeID])
176190
}
177-
permDoer, err := access_model.GetUserRepoPermission(ctx, repo, issue.Poster)
178-
for _, reviewer := range opts.Reviewers {
179-
if _, err = issue_service.ReviewRequest(ctx, pr.Issue, issue.Poster, &permDoer, reviewer, true); err != nil {
180-
return err
181-
}
182-
}
183-
for _, teamReviewer := range opts.TeamReviewers {
184-
if _, err = issue_service.TeamReviewRequest(ctx, pr.Issue, issue.Poster, teamReviewer, true); err != nil {
185-
return err
186-
}
187-
}
191+
188192
return nil
189193
}
190194

tests/integration/pull_compare_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,15 @@ func TestPullCompare_EnableAllowEditsFromMaintainer(t *testing.T) {
102102

103103
// user4 creates a new branch and a PR
104104
testEditFileToNewBranch(t, user4Session, "user4", forkedRepoName, "master", "user4/update-readme", "README.md", "Hello, World\n(Edited by user4)\n")
105-
resp := testPullCreateDirectly(t, user4Session, repo3.OwnerName, repo3.Name, "master", "user4", forkedRepoName, "user4/update-readme", "PR for user4 forked repo3")
105+
resp := testPullCreateDirectly(t, user4Session, createPullRequestOptions{
106+
BaseRepoOwner: repo3.OwnerName,
107+
BaseRepoName: repo3.Name,
108+
BaseBranch: "master",
109+
HeadRepoOwner: "user4",
110+
HeadRepoName: forkedRepoName,
111+
HeadBranch: "user4/update-readme",
112+
Title: "PR for user4 forked repo3",
113+
})
106114
prURL := test.RedirectURL(resp)
107115

108116
// user2 (admin of repo3) goes to the PR files page

tests/integration/pull_create_test.go

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,26 +60,50 @@ func testPullCreate(t *testing.T, session *TestSession, user, repo string, toSel
6060
return resp
6161
}
6262

63-
func testPullCreateDirectly(t *testing.T, session *TestSession, baseRepoOwner, baseRepoName, baseBranch, headRepoOwner, headRepoName, headBranch, title string) *httptest.ResponseRecorder {
64-
headCompare := headBranch
65-
if headRepoOwner != "" {
66-
if headRepoName != "" {
67-
headCompare = fmt.Sprintf("%s/%s:%s", headRepoOwner, headRepoName, headBranch)
63+
type createPullRequestOptions struct {
64+
BaseRepoOwner string
65+
BaseRepoName string
66+
BaseBranch string
67+
HeadRepoOwner string
68+
HeadRepoName string
69+
HeadBranch string
70+
Title string
71+
ReviewerIDs string // comma-separated list of user IDs
72+
}
73+
74+
func (opts createPullRequestOptions) IsValid() bool {
75+
return opts.BaseRepoOwner != "" && opts.BaseRepoName != "" && opts.BaseBranch != "" &&
76+
opts.HeadBranch != "" && opts.Title != ""
77+
}
78+
79+
func testPullCreateDirectly(t *testing.T, session *TestSession, opts createPullRequestOptions) *httptest.ResponseRecorder {
80+
if !opts.IsValid() {
81+
t.Fatal("Invalid pull request options")
82+
}
83+
84+
headCompare := opts.HeadBranch
85+
if opts.HeadRepoOwner != "" {
86+
if opts.HeadRepoName != "" {
87+
headCompare = fmt.Sprintf("%s/%s:%s", opts.HeadRepoOwner, opts.HeadRepoName, opts.HeadBranch)
6888
} else {
69-
headCompare = fmt.Sprintf("%s:%s", headRepoOwner, headBranch)
89+
headCompare = fmt.Sprintf("%s:%s", opts.HeadRepoOwner, opts.HeadBranch)
7090
}
7191
}
72-
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/compare/%s...%s", baseRepoOwner, baseRepoName, baseBranch, headCompare))
92+
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/compare/%s...%s", opts.BaseRepoOwner, opts.BaseRepoName, opts.BaseBranch, headCompare))
7393
resp := session.MakeRequest(t, req, http.StatusOK)
7494

7595
// Submit the form for creating the pull
7696
htmlDoc := NewHTMLParser(t, resp.Body)
7797
link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action")
7898
assert.True(t, exists, "The template has changed")
79-
req = NewRequestWithValues(t, "POST", link, map[string]string{
99+
params := map[string]string{
80100
"_csrf": htmlDoc.GetCSRF(),
81-
"title": title,
82-
})
101+
"title": opts.Title,
102+
}
103+
if opts.ReviewerIDs != "" {
104+
params["reviewer_ids"] = opts.ReviewerIDs
105+
}
106+
req = NewRequestWithValues(t, "POST", link, params)
83107
resp = session.MakeRequest(t, req, http.StatusOK)
84108
return resp
85109
}
@@ -246,7 +270,15 @@ func TestPullCreatePrFromBaseToFork(t *testing.T) {
246270
testEditFile(t, sessionBase, "user2", "repo1", "master", "README.md", "Hello, World (Edited)\n")
247271

248272
// Create a PR
249-
resp := testPullCreateDirectly(t, sessionFork, "user1", "repo1", "master", "user2", "repo1", "master", "This is a pull title")
273+
resp := testPullCreateDirectly(t, sessionFork, createPullRequestOptions{
274+
BaseRepoOwner: "user1",
275+
BaseRepoName: "repo1",
276+
BaseBranch: "master",
277+
HeadRepoOwner: "user2",
278+
HeadRepoName: "repo1",
279+
HeadBranch: "master",
280+
Title: "This is a pull title",
281+
})
250282
// check the redirected URL
251283
url := test.RedirectURL(resp)
252284
assert.Regexp(t, "^/user1/repo1/pulls/[0-9]*$", url)

tests/integration/pull_review_test.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,29 @@ func TestPullView_CodeOwner(t *testing.T) {
184184
session := loginUser(t, "user5")
185185

186186
// create a pull request on the forked repository, code reviewers should not be mentioned
187-
testPullCreateDirectly(t, session, "user5", "test_codeowner", forkedRepo.DefaultBranch, "", "", "codeowner-basebranch-forked", "Test Pull Request on Forked Repository")
187+
testPullCreateDirectly(t, session, createPullRequestOptions{
188+
BaseRepoOwner: "user5",
189+
BaseRepoName: "test_codeowner",
190+
BaseBranch: forkedRepo.DefaultBranch,
191+
HeadRepoOwner: "",
192+
HeadRepoName: "",
193+
HeadBranch: "codeowner-basebranch-forked",
194+
Title: "Test Pull Request on Forked Repository",
195+
})
188196

189197
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"})
190198
unittest.AssertNotExistsBean(t, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})
191199

192200
// create a pull request to base repository, code reviewers should be mentioned
193-
testPullCreateDirectly(t, session, repo.OwnerName, repo.Name, repo.DefaultBranch, forkedRepo.OwnerName, forkedRepo.Name, "codeowner-basebranch-forked", "Test Pull Request3")
201+
testPullCreateDirectly(t, session, createPullRequestOptions{
202+
BaseRepoOwner: repo.OwnerName,
203+
BaseRepoName: repo.Name,
204+
BaseBranch: repo.DefaultBranch,
205+
HeadRepoOwner: forkedRepo.OwnerName,
206+
HeadRepoName: forkedRepo.Name,
207+
HeadBranch: "codeowner-basebranch-forked",
208+
Title: "Test Pull Request3",
209+
})
194210

195211
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{BaseRepoID: repo.ID, HeadRepoID: forkedRepo.ID, HeadBranch: "codeowner-basebranch-forked"})
196212
unittest.AssertExistsAndLoadBean(t, &issues_model.Review{IssueID: pr.IssueID, Type: issues_model.ReviewTypeRequest, ReviewerID: 8})

tests/integration/repo_webhook_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"time"
1616

1717
auth_model "code.gitea.io/gitea/models/auth"
18+
"code.gitea.io/gitea/models/perm"
1819
"code.gitea.io/gitea/models/repo"
1920
"code.gitea.io/gitea/models/unittest"
2021
user_model "code.gitea.io/gitea/models/user"
@@ -681,15 +682,30 @@ func Test_WebhookPullRequest(t *testing.T) {
681682
}, http.StatusOK)
682683
defer provider.Close()
683684

685+
testCtx := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeAll)
686+
// add user4 as collabrator so that it can be a reviewer
687+
doAPIAddCollaborator(testCtx, "user4", perm.AccessModeWrite)(t)
688+
684689
// 1. create a new webhook with special webhook for repo1
685-
session := loginUser(t, "user2")
690+
sessionUser2 := loginUser(t, "user2")
691+
sessionUser4 := loginUser(t, "user4")
686692

687-
testAPICreateWebhookForRepo(t, session, "user2", "repo1", provider.URL(), "pull_request")
693+
// ignore the possible review_requested event to keep the test deterministic
694+
testAPICreateWebhookForRepo(t, sessionUser2, "user2", "repo1", provider.URL(), "pull_request_only")
688695

689-
testAPICreateBranch(t, session, "user2", "repo1", "master", "master2", http.StatusCreated)
696+
testAPICreateBranch(t, sessionUser2, "user2", "repo1", "master", "master2", http.StatusCreated)
690697
// 2. trigger the webhook
691698
repo1 := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 1})
692-
testCreatePullToDefaultBranch(t, session, repo1, repo1, "master2", "first pull request")
699+
testPullCreateDirectly(t, sessionUser4, createPullRequestOptions{
700+
BaseRepoOwner: repo1.OwnerName,
701+
BaseRepoName: repo1.Name,
702+
BaseBranch: repo1.DefaultBranch,
703+
HeadRepoOwner: "",
704+
HeadRepoName: "",
705+
HeadBranch: "master2",
706+
Title: "first pull request",
707+
ReviewerIDs: "2", // add user2 as reviewer
708+
})
693709

694710
// 3. validate the webhook is triggered
695711
assert.Equal(t, "pull_request", triggeredEvent)
@@ -701,6 +717,8 @@ func Test_WebhookPullRequest(t *testing.T) {
701717
assert.Equal(t, 0, *payloads[0].PullRequest.Additions)
702718
assert.Equal(t, 0, *payloads[0].PullRequest.ChangedFiles)
703719
assert.Equal(t, 0, *payloads[0].PullRequest.Deletions)
720+
assert.Len(t, payloads[0].PullRequest.RequestedReviewers, 1)
721+
assert.Equal(t, int64(2), payloads[0].PullRequest.RequestedReviewers[0].ID)
704722
})
705723
}
706724

0 commit comments

Comments
 (0)