Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New webhook trigger for receiving Pull Request review requests #24481

Merged
merged 27 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e693713
feat: new webhook for receiving Pull Request review requests
Makonike May 2, 2023
4882266
fix: not issue trigger
Makonike May 2, 2023
22f0ae5
fix: dup reviewer
Makonike May 2, 2023
2617c4c
fix: update swagger
Makonike May 2, 2023
c5a9f4b
fix: no newline at end of file
Makonike May 2, 2023
439a847
feat: convertPayloader
Makonike May 2, 2023
ee0187d
feat: template button
Makonike May 2, 2023
988c136
fix: move reviewers field to pull
Makonike May 9, 2023
9c9dbde
fix: remove reviewers in issue
Makonike May 9, 2023
cc11f8f
fix: update v1_json.tmpl
Makonike May 9, 2023
57964f4
fix: ci lint error
Makonike May 9, 2023
e2a743c
fix: ci lint error
Makonike May 9, 2023
3568067
fix: ci lint error
Makonike May 10, 2023
13dad91
fix: load reviewers return if existed
Makonike May 11, 2023
c5a553f
fix: rename event
Makonike May 11, 2023
332b187
Merge branch 'main' into main
techknowlogick May 11, 2023
161270c
fix: ci lint error
Makonike May 11, 2023
d22436d
fix: batch load reviewers
Makonike May 24, 2023
ff20eee
docs: add comments
Makonike May 24, 2023
018d95d
fix: rename GetReviewersByIssueID to GetReviewsByIssueID
Makonike May 24, 2023
d5f9b9d
fix
Makonike May 24, 2023
49b8888
fix: add translation keys
Makonike May 24, 2023
063c813
fix
Makonike May 24, 2023
64fbc53
Merge branch 'main' into main
GiteaBot May 24, 2023
d058c60
Merge branch 'main' into main
GiteaBot May 24, 2023
7b195d0
Merge branch 'main' into main
GiteaBot May 25, 2023
8364df5
Merge branch 'main' into main
GiteaBot May 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions models/issues/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,10 @@ type PullRequest struct {

ChangedProtectedFiles []string `xorm:"TEXT JSON"`

IssueID int64 `xorm:"INDEX"`
Issue *Issue `xorm:"-"`
Index int64
IssueID int64 `xorm:"INDEX"`
Issue *Issue `xorm:"-"`
Index int64
RequestedReviewers []*user_model.User `xorm:"-"`

HeadRepoID int64 `xorm:"INDEX"`
HeadRepo *repo_model.Repository `xorm:"-"`
Expand Down Expand Up @@ -315,6 +316,25 @@ func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) {
return nil
}

func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) (err error) {
// Reset maybe preexisting reviewers
pr.RequestedReviewers = []*user_model.User{}
lunny marked this conversation as resolved.
Show resolved Hide resolved

reviews, err := GetReviewersByIssueID(pr.Issue.ID)
lunny marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
if len(reviews) > 0 {
for _, review := range reviews {
lunny marked this conversation as resolved.
Show resolved Hide resolved
if err = review.LoadReviewer(ctx); err != nil {
return err
}
pr.RequestedReviewers = append(pr.RequestedReviewers, review.Reviewer)
}
}
return nil
}

// LoadBaseRepo loads the target repository. ErrRepoNotExist may be returned.
func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) {
if pr.BaseRepo != nil {
Expand Down
29 changes: 29 additions & 0 deletions models/issues/pull_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package issues_test
import (
"testing"

user_model "code.gitea.io/gitea/models/user"

"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unittest"
Expand Down Expand Up @@ -74,6 +76,33 @@ func TestPullRequestsNewest(t *testing.T) {
}
}

func TestLoadRequestedReviewers(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())

pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1})
assert.NoError(t, pull.LoadIssue(db.DefaultContext))
issue := pull.Issue
assert.NoError(t, issue.LoadRepo(db.DefaultContext))
assert.Len(t, pull.RequestedReviewers, 0)

user1, err := user_model.GetUserByID(db.DefaultContext, 1)
assert.NoError(t, err)

comment, err := issues_model.AddReviewRequest(issue, user1, &user_model.User{})
assert.NoError(t, err)
assert.NotNil(t, comment)

assert.NoError(t, pull.LoadRequestedReviewers(db.DefaultContext))
assert.Len(t, pull.RequestedReviewers, 1)

comment, err = issues_model.RemoveReviewRequest(issue, user1, &user_model.User{})
assert.NoError(t, err)
assert.NotNil(t, comment)

assert.NoError(t, pull.LoadRequestedReviewers(db.DefaultContext))
assert.Empty(t, pull.RequestedReviewers)
}

func TestPullRequestsOldest(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{
Expand Down
7 changes: 7 additions & 0 deletions models/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ func (w *Webhook) HasPackageEvent() bool {
(w.ChooseEvents && w.HookEvents.Package)
}

// HasPullReviewRequestEvent returns true if hook enabled pull request review request event.
func (w *Webhook) HasPullReviewRequestEvent() bool {
return w.SendEverything ||
(w.ChooseEvents && w.HookEvents.PullReviewRequest)
}

// EventCheckers returns event checkers
func (w *Webhook) EventCheckers() []struct {
Has func() bool
Expand Down Expand Up @@ -329,6 +335,7 @@ func (w *Webhook) EventCheckers() []struct {
{w.HasRepositoryEvent, webhook_module.HookEventRepository},
{w.HasReleaseEvent, webhook_module.HookEventRelease},
{w.HasPackageEvent, webhook_module.HookEventPackage},
{w.HasPullReviewRequestEvent, webhook_module.HookEventPullReviewRequest},
}
}

Expand Down
2 changes: 1 addition & 1 deletion models/webhook/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestWebhook_EventsArray(t *testing.T) {
"pull_request", "pull_request_assign", "pull_request_label", "pull_request_milestone",
"pull_request_comment", "pull_request_review_approved", "pull_request_review_rejected",
"pull_request_review_comment", "pull_request_sync", "wiki", "repository", "release",
"package",
"package", "pull_review_request",
lunny marked this conversation as resolved.
Show resolved Hide resolved
},
(&Webhook{
HookEvent: &webhook_module.HookEvent{SendEverything: true},
Expand Down
21 changes: 13 additions & 8 deletions modules/structs/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ const (
HookIssueDemilestoned HookIssueAction = "demilestoned"
// HookIssueReviewed is an issue action for when a pull request is reviewed
HookIssueReviewed HookIssueAction = "reviewed"
// HookIssueReviewRequested is an issue action for when a reviewer is requested for a pull request.
HookIssueReviewRequested HookIssueAction = "review_requested"
// HookIssueReviewRequestRemoved is an issue action for removing a review request to someone on a pull request.
HookIssueReviewRequestRemoved HookIssueAction = "review_request_removed"
)

// IssuePayload represents the payload information that is sent along with an issue event.
Expand Down Expand Up @@ -381,14 +385,15 @@ type ChangesPayload struct {

// PullRequestPayload represents a payload information of pull request event.
type PullRequestPayload struct {
Action HookIssueAction `json:"action"`
Index int64 `json:"number"`
Changes *ChangesPayload `json:"changes,omitempty"`
PullRequest *PullRequest `json:"pull_request"`
Repository *Repository `json:"repository"`
Sender *User `json:"sender"`
CommitID string `json:"commit_id"`
Review *ReviewPayload `json:"review"`
Action HookIssueAction `json:"action"`
Index int64 `json:"number"`
Changes *ChangesPayload `json:"changes,omitempty"`
PullRequest *PullRequest `json:"pull_request"`
RequestedReviewer *User `json:"requested_reviewer"`
Repository *Repository `json:"repository"`
Sender *User `json:"sender"`
CommitID string `json:"commit_id"`
Review *ReviewPayload `json:"review"`
}

// JSONPayload FIXME
Expand Down
27 changes: 14 additions & 13 deletions modules/structs/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ import (

// PullRequest represents a pull request
type PullRequest struct {
ID int64 `json:"id"`
URL string `json:"url"`
Index int64 `json:"number"`
Poster *User `json:"user"`
Title string `json:"title"`
Body string `json:"body"`
Labels []*Label `json:"labels"`
Milestone *Milestone `json:"milestone"`
Assignee *User `json:"assignee"`
Assignees []*User `json:"assignees"`
State StateType `json:"state"`
IsLocked bool `json:"is_locked"`
Comments int `json:"comments"`
ID int64 `json:"id"`
URL string `json:"url"`
Index int64 `json:"number"`
Poster *User `json:"user"`
Title string `json:"title"`
Body string `json:"body"`
Labels []*Label `json:"labels"`
Milestone *Milestone `json:"milestone"`
Assignee *User `json:"assignee"`
Assignees []*User `json:"assignees"`
RequestedReviewers []*User `json:"requested_reviewers"`
State StateType `json:"state"`
IsLocked bool `json:"is_locked"`
Comments int `json:"comments"`

HTMLURL string `json:"html_url"`
DiffURL string `json:"diff_url"`
Expand Down
1 change: 1 addition & 0 deletions modules/webhook/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type HookEvents struct {
PullRequestComment bool `json:"pull_request_comment"`
PullRequestReview bool `json:"pull_request_review"`
PullRequestSync bool `json:"pull_request_sync"`
PullReviewRequest bool `json:"pull_review_request"`
Wiki bool `json:"wiki"`
Repository bool `json:"repository"`
Release bool `json:"release"`
Expand Down
3 changes: 2 additions & 1 deletion modules/webhook/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const (
HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected"
HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment"
HookEventPullRequestSync HookEventType = "pull_request_sync"
HookEventPullReviewRequest HookEventType = "pull_review_request"
HookEventWiki HookEventType = "wiki"
HookEventRepository HookEventType = "repository"
HookEventRelease HookEventType = "release"
Expand All @@ -46,7 +47,7 @@ func (h HookEventType) Event() string {
case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone:
return "issues"
case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone,
HookEventPullRequestSync:
HookEventPullRequestSync, HookEventPullReviewRequest:
return "pull_request"
case HookEventIssueComment, HookEventPullRequestComment:
return "issue_comment"
Expand Down
2 changes: 2 additions & 0 deletions routers/api/v1/utils/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
PullRequestMilestone: pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)),
PullRequestComment: pullHook(form.Events, string(webhook_module.HookEventPullRequestComment)),
PullRequestReview: pullHook(form.Events, "pull_request_review"),
PullReviewRequest: pullHook(form.Events, string(webhook_module.HookEventPullReviewRequest)),
PullRequestSync: pullHook(form.Events, string(webhook_module.HookEventPullRequestSync)),
Wiki: util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true),
Repository: util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true),
Expand Down Expand Up @@ -379,6 +380,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh
w.PullRequestMilestone = pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone))
w.PullRequestComment = pullHook(form.Events, string(webhook_module.HookEventPullRequestComment))
w.PullRequestReview = pullHook(form.Events, "pull_request_review")
w.PullReviewRequest = pullHook(form.Events, string(webhook_module.HookEventPullReviewRequest))
w.PullRequestSync = pullHook(form.Events, string(webhook_module.HookEventPullRequestSync))

if err := w.UpdateEvent(); err != nil {
Expand Down
1 change: 1 addition & 0 deletions routers/web/repo/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ func ParseHookEvent(form forms.WebhookForm) *webhook_module.HookEvent {
PullRequestComment: form.PullRequestComment,
PullRequestReview: form.PullRequestReview,
PullRequestSync: form.PullRequestSync,
PullReviewRequest: form.PullReviewRequest,
Wiki: form.Wiki,
Repository: form.Repository,
Package: form.Package,
Expand Down
10 changes: 10 additions & 0 deletions services/convert/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
},
}

if err := pr.LoadRequestedReviewers(ctx); err != nil {
log.Error("LoadRequestedReviewers[%d]: %v", pr.ID, err)
return nil
}
if len(pr.RequestedReviewers) > 0 {
for _, reviewer := range pr.RequestedReviewers {
apiPullRequest.RequestedReviewers = append(apiPullRequest.RequestedReviewers, ToUser(ctx, reviewer, nil))
}
}
lunny marked this conversation as resolved.
Show resolved Hide resolved

if pr.Issue.ClosedUnix != 0 {
apiPullRequest.Closed = pr.Issue.ClosedUnix.AsTimePtr()
}
Expand Down
1 change: 1 addition & 0 deletions services/forms/repo_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ type WebhookForm struct {
PullRequestComment bool
PullRequestReview bool
PullRequestSync bool
PullReviewRequest bool
Wiki bool
Repository bool
Package bool
Expand Down
28 changes: 28 additions & 0 deletions services/webhook/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,34 @@ func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issue
}
}

func (m *webhookNotifier) NotifyPullReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
if !issue.IsPull {
log.Warn("NotifyPullReviewRequest: issue is not a pull request: %v", issue.ID)
return
}
mode, _ := access_model.AccessLevelUnit(ctx, doer, issue.Repo, unit.TypePullRequests)
if err := issue.LoadPullRequest(ctx); err != nil {
log.Error("LoadPullRequest failed: %v", err)
return
}
apiPullRequest := &api.PullRequestPayload{
Index: issue.Index,
PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil),
RequestedReviewer: convert.ToUser(ctx, reviewer, nil),
Repository: convert.ToRepo(ctx, issue.Repo, mode),
Sender: convert.ToUser(ctx, doer, nil),
}
if isRequest {
apiPullRequest.Action = api.HookIssueReviewRequested
} else {
apiPullRequest.Action = api.HookIssueReviewRequestRemoved
}
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullReviewRequest, apiPullRequest); err != nil {
log.Error("PrepareWebhooks [review_requested: %v]: %v", isRequest, err)
return
}
}

func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) {
apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
Expand Down
2 changes: 1 addition & 1 deletion services/webhook/payloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_module.
case webhook_module.HookEventPush:
return s.Push(p.(*api.PushPayload))
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestAssign, webhook_module.HookEventPullRequestLabel,
webhook_module.HookEventPullRequestMilestone, webhook_module.HookEventPullRequestSync:
webhook_module.HookEventPullRequestMilestone, webhook_module.HookEventPullRequestSync, webhook_module.HookEventPullReviewRequest:
return s.PullRequest(p.(*api.PullRequestPayload))
case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment:
return s.Review(p.(*api.PullRequestPayload), event)
Expand Down
10 changes: 10 additions & 0 deletions templates/repo/settings/webhook/settings.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,16 @@
</div>
</div>
</div>
<!-- Pull Request Review Request -->
<div class="seven wide column">
<div class="field">
<div class="ui checkbox">
<input name="pull_review_request" type="checkbox" tabindex="0" {{if .Webhook.PullReviewRequest}}checked{{end}}>
<label>{{.locale.Tr "repo.settings.event_pull_review_request"}}</label>
<span class="help">{{.locale.Tr "repo.settings.event_pull_review_request_desc"}}</span>
</div>
</div>
</div>
</div>
</div>

Expand Down
7 changes: 7 additions & 0 deletions templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.