New webhook trigger for receiving Pull Request review requests (#24481)
close https://github.com/go-gitea/gitea/issues/16321 Provided a webhook trigger for requesting someone to review the Pull Request. Some modifications have been made to the returned `PullRequestPayload` based on the GitHub webhook settings, including: - add a description of the current reviewer object as `RequestedReviewer` . - setting the action to either **review_requested** or **review_request_removed** based on the operation. - adding the `RequestedReviewers` field to the issues_model.PullRequest. This field will be loaded into the PullRequest through `LoadRequestedReviewers()` when `ToAPIPullRequest` is called. After the Pull Request is merged, I will supplement the relevant documentation.
This commit is contained in:
parent
93c6a9a652
commit
309354c70e
|
@ -178,6 +178,7 @@ type PullRequest struct {
|
||||||
IssueID int64 `xorm:"INDEX"`
|
IssueID int64 `xorm:"INDEX"`
|
||||||
Issue *Issue `xorm:"-"`
|
Issue *Issue `xorm:"-"`
|
||||||
Index int64
|
Index int64
|
||||||
|
RequestedReviewers []*user_model.User `xorm:"-"`
|
||||||
|
|
||||||
HeadRepoID int64 `xorm:"INDEX"`
|
HeadRepoID int64 `xorm:"INDEX"`
|
||||||
HeadRepo *repo_model.Repository `xorm:"-"`
|
HeadRepo *repo_model.Repository `xorm:"-"`
|
||||||
|
@ -302,6 +303,29 @@ func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadRequestedReviewers loads the requested reviewers.
|
||||||
|
func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
||||||
|
if len(pr.RequestedReviewers) > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
reviews, err := GetReviewsByIssueID(pr.Issue.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(reviews) > 0 {
|
||||||
|
err = LoadReviewers(ctx, reviews)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, review := range reviews {
|
||||||
|
pr.RequestedReviewers = append(pr.RequestedReviewers, review.Reviewer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// LoadBaseRepo loads the target repository. ErrRepoNotExist may be returned.
|
// LoadBaseRepo loads the target repository. ErrRepoNotExist may be returned.
|
||||||
func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) {
|
func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) {
|
||||||
if pr.BaseRepo != nil {
|
if pr.BaseRepo != nil {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
issues_model "code.gitea.io/gitea/models/issues"
|
issues_model "code.gitea.io/gitea/models/issues"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -74,6 +75,34 @@ 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)
|
||||||
|
|
||||||
|
pull.RequestedReviewers = nil
|
||||||
|
assert.NoError(t, pull.LoadRequestedReviewers(db.DefaultContext))
|
||||||
|
assert.Empty(t, pull.RequestedReviewers)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPullRequestsOldest(t *testing.T) {
|
func TestPullRequestsOldest(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{
|
prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{
|
||||||
|
|
|
@ -162,6 +162,27 @@ func (r *Review) LoadReviewer(ctx context.Context) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadReviewers loads reviewers
|
||||||
|
func LoadReviewers(ctx context.Context, reviews []*Review) (err error) {
|
||||||
|
reviewerIds := make([]int64, len(reviews))
|
||||||
|
for i := 0; i < len(reviews); i++ {
|
||||||
|
reviewerIds[i] = reviews[i].ReviewerID
|
||||||
|
}
|
||||||
|
reviewers, err := user_model.GetPossibleUserByIDs(ctx, reviewerIds)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userMap := make(map[int64]*user_model.User, len(reviewers))
|
||||||
|
for _, reviewer := range reviewers {
|
||||||
|
userMap[reviewer.ID] = reviewer
|
||||||
|
}
|
||||||
|
for _, review := range reviews {
|
||||||
|
review.Reviewer = userMap[review.ReviewerID]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// LoadReviewerTeam loads reviewer team
|
// LoadReviewerTeam loads reviewer team
|
||||||
func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
|
func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
|
||||||
if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
|
if r.ReviewerTeamID == 0 || r.ReviewerTeam != nil {
|
||||||
|
@ -520,8 +541,8 @@ func GetReviews(ctx context.Context, opts *GetReviewOptions) ([]*Review, error)
|
||||||
return reviews, sess.Find(&reviews)
|
return reviews, sess.Find(&reviews)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReviewersByIssueID gets the latest review of each reviewer for a pull request
|
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||||
func GetReviewersByIssueID(issueID int64) ([]*Review, error) {
|
func GetReviewsByIssueID(issueID int64) ([]*Review, error) {
|
||||||
reviews := make([]*Review, 0, 10)
|
reviews := make([]*Review, 0, 10)
|
||||||
|
|
||||||
sess := db.GetEngine(db.DefaultContext)
|
sess := db.GetEngine(db.DefaultContext)
|
||||||
|
|
|
@ -132,11 +132,22 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
||||||
UpdatedUnix: 946684814,
|
UpdatedUnix: 946684814,
|
||||||
})
|
})
|
||||||
|
|
||||||
allReviews, err := issues_model.GetReviewersByIssueID(issue.ID)
|
allReviews, err := issues_model.GetReviewsByIssueID(issue.ID)
|
||||||
for _, reviewer := range allReviews {
|
|
||||||
assert.NoError(t, reviewer.LoadReviewer(db.DefaultContext))
|
|
||||||
}
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
for _, review := range allReviews {
|
||||||
|
assert.NoError(t, review.LoadReviewer(db.DefaultContext))
|
||||||
|
}
|
||||||
|
if assert.Len(t, allReviews, 3) {
|
||||||
|
for i, review := range allReviews {
|
||||||
|
assert.Equal(t, expectedReviews[i].Reviewer, review.Reviewer)
|
||||||
|
assert.Equal(t, expectedReviews[i].Type, review.Type)
|
||||||
|
assert.Equal(t, expectedReviews[i].UpdatedUnix, review.UpdatedUnix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allReviews, err = issues_model.GetReviewsByIssueID(issue.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, issues_model.LoadReviewers(db.DefaultContext, allReviews))
|
||||||
if assert.Len(t, allReviews, 3) {
|
if assert.Len(t, allReviews, 3) {
|
||||||
for i, review := range allReviews {
|
for i, review := range allReviews {
|
||||||
assert.Equal(t, expectedReviews[i].Reviewer, review.Reviewer)
|
assert.Equal(t, expectedReviews[i].Reviewer, review.Reviewer)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/auth/openid"
|
"code.gitea.io/gitea/modules/auth/openid"
|
||||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
@ -910,6 +911,15 @@ func GetUserByID(ctx context.Context, id int64) (*User, error) {
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserByIDs returns the user objects by given IDs if exists.
|
||||||
|
func GetUserByIDs(ctx context.Context, ids []int64) ([]*User, error) {
|
||||||
|
users := make([]*User, 0, len(ids))
|
||||||
|
err := db.GetEngine(ctx).In("id", ids).
|
||||||
|
Table("user").
|
||||||
|
Find(&users)
|
||||||
|
return users, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetPossibleUserByID returns the user if id > 0 or return system usrs if id < 0
|
// GetPossibleUserByID returns the user if id > 0 or return system usrs if id < 0
|
||||||
func GetPossibleUserByID(ctx context.Context, id int64) (*User, error) {
|
func GetPossibleUserByID(ctx context.Context, id int64) (*User, error) {
|
||||||
switch id {
|
switch id {
|
||||||
|
@ -924,6 +934,25 @@ func GetPossibleUserByID(ctx context.Context, id int64) (*User, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPossibleUserByIDs returns the users if id > 0 or return system users if id < 0
|
||||||
|
func GetPossibleUserByIDs(ctx context.Context, ids []int64) ([]*User, error) {
|
||||||
|
uniqueIDs := container.SetOf(ids...)
|
||||||
|
users := make([]*User, 0, len(ids))
|
||||||
|
_ = uniqueIDs.Remove(0)
|
||||||
|
if uniqueIDs.Remove(-1) {
|
||||||
|
users = append(users, NewGhostUser())
|
||||||
|
}
|
||||||
|
if uniqueIDs.Remove(ActionsUserID) {
|
||||||
|
users = append(users, NewActionsUser())
|
||||||
|
}
|
||||||
|
res, err := GetUserByIDs(ctx, uniqueIDs.Values())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
users = append(users, res...)
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserByNameCtx returns user by given name.
|
// GetUserByNameCtx returns user by given name.
|
||||||
func GetUserByName(ctx context.Context, name string) (*User, error) {
|
func GetUserByName(ctx context.Context, name string) (*User, error) {
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
|
|
|
@ -298,6 +298,12 @@ func (w *Webhook) HasPackageEvent() bool {
|
||||||
(w.ChooseEvents && w.HookEvents.Package)
|
(w.ChooseEvents && w.HookEvents.Package)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasPullRequestReviewRequestEvent returns true if hook enabled pull request review request event.
|
||||||
|
func (w *Webhook) HasPullRequestReviewRequestEvent() bool {
|
||||||
|
return w.SendEverything ||
|
||||||
|
(w.ChooseEvents && w.HookEvents.PullRequestReviewRequest)
|
||||||
|
}
|
||||||
|
|
||||||
// EventCheckers returns event checkers
|
// EventCheckers returns event checkers
|
||||||
func (w *Webhook) EventCheckers() []struct {
|
func (w *Webhook) EventCheckers() []struct {
|
||||||
Has func() bool
|
Has func() bool
|
||||||
|
@ -329,6 +335,7 @@ func (w *Webhook) EventCheckers() []struct {
|
||||||
{w.HasRepositoryEvent, webhook_module.HookEventRepository},
|
{w.HasRepositoryEvent, webhook_module.HookEventRepository},
|
||||||
{w.HasReleaseEvent, webhook_module.HookEventRelease},
|
{w.HasReleaseEvent, webhook_module.HookEventRelease},
|
||||||
{w.HasPackageEvent, webhook_module.HookEventPackage},
|
{w.HasPackageEvent, webhook_module.HookEventPackage},
|
||||||
|
{w.HasPullRequestReviewRequestEvent, webhook_module.HookEventPullRequestReviewRequest},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ func TestWebhook_EventsArray(t *testing.T) {
|
||||||
"pull_request", "pull_request_assign", "pull_request_label", "pull_request_milestone",
|
"pull_request", "pull_request_assign", "pull_request_label", "pull_request_milestone",
|
||||||
"pull_request_comment", "pull_request_review_approved", "pull_request_review_rejected",
|
"pull_request_comment", "pull_request_review_approved", "pull_request_review_rejected",
|
||||||
"pull_request_review_comment", "pull_request_sync", "wiki", "repository", "release",
|
"pull_request_review_comment", "pull_request_sync", "wiki", "repository", "release",
|
||||||
"package",
|
"package", "pull_request_review_request",
|
||||||
},
|
},
|
||||||
(&Webhook{
|
(&Webhook{
|
||||||
HookEvent: &webhook_module.HookEvent{SendEverything: true},
|
HookEvent: &webhook_module.HookEvent{SendEverything: true},
|
||||||
|
|
|
@ -342,6 +342,10 @@ const (
|
||||||
HookIssueDemilestoned HookIssueAction = "demilestoned"
|
HookIssueDemilestoned HookIssueAction = "demilestoned"
|
||||||
// HookIssueReviewed is an issue action for when a pull request is reviewed
|
// HookIssueReviewed is an issue action for when a pull request is reviewed
|
||||||
HookIssueReviewed HookIssueAction = "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.
|
// IssuePayload represents the payload information that is sent along with an issue event.
|
||||||
|
@ -385,6 +389,7 @@ type PullRequestPayload struct {
|
||||||
Index int64 `json:"number"`
|
Index int64 `json:"number"`
|
||||||
Changes *ChangesPayload `json:"changes,omitempty"`
|
Changes *ChangesPayload `json:"changes,omitempty"`
|
||||||
PullRequest *PullRequest `json:"pull_request"`
|
PullRequest *PullRequest `json:"pull_request"`
|
||||||
|
RequestedReviewer *User `json:"requested_reviewer"`
|
||||||
Repository *Repository `json:"repository"`
|
Repository *Repository `json:"repository"`
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
CommitID string `json:"commit_id"`
|
CommitID string `json:"commit_id"`
|
||||||
|
|
|
@ -19,6 +19,7 @@ type PullRequest struct {
|
||||||
Milestone *Milestone `json:"milestone"`
|
Milestone *Milestone `json:"milestone"`
|
||||||
Assignee *User `json:"assignee"`
|
Assignee *User `json:"assignee"`
|
||||||
Assignees []*User `json:"assignees"`
|
Assignees []*User `json:"assignees"`
|
||||||
|
RequestedReviewers []*User `json:"requested_reviewers"`
|
||||||
State StateType `json:"state"`
|
State StateType `json:"state"`
|
||||||
IsLocked bool `json:"is_locked"`
|
IsLocked bool `json:"is_locked"`
|
||||||
Comments int `json:"comments"`
|
Comments int `json:"comments"`
|
||||||
|
|
|
@ -21,6 +21,7 @@ type HookEvents struct {
|
||||||
PullRequestComment bool `json:"pull_request_comment"`
|
PullRequestComment bool `json:"pull_request_comment"`
|
||||||
PullRequestReview bool `json:"pull_request_review"`
|
PullRequestReview bool `json:"pull_request_review"`
|
||||||
PullRequestSync bool `json:"pull_request_sync"`
|
PullRequestSync bool `json:"pull_request_sync"`
|
||||||
|
PullRequestReviewRequest bool `json:"pull_request_review_request"`
|
||||||
Wiki bool `json:"wiki"`
|
Wiki bool `json:"wiki"`
|
||||||
Repository bool `json:"repository"`
|
Repository bool `json:"repository"`
|
||||||
Release bool `json:"release"`
|
Release bool `json:"release"`
|
||||||
|
|
|
@ -26,6 +26,7 @@ const (
|
||||||
HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected"
|
HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected"
|
||||||
HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment"
|
HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment"
|
||||||
HookEventPullRequestSync HookEventType = "pull_request_sync"
|
HookEventPullRequestSync HookEventType = "pull_request_sync"
|
||||||
|
HookEventPullRequestReviewRequest HookEventType = "pull_request_review_request"
|
||||||
HookEventWiki HookEventType = "wiki"
|
HookEventWiki HookEventType = "wiki"
|
||||||
HookEventRepository HookEventType = "repository"
|
HookEventRepository HookEventType = "repository"
|
||||||
HookEventRelease HookEventType = "release"
|
HookEventRelease HookEventType = "release"
|
||||||
|
@ -46,7 +47,7 @@ func (h HookEventType) Event() string {
|
||||||
case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone:
|
case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone:
|
||||||
return "issues"
|
return "issues"
|
||||||
case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone,
|
case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone,
|
||||||
HookEventPullRequestSync:
|
HookEventPullRequestSync, HookEventPullRequestReviewRequest:
|
||||||
return "pull_request"
|
return "pull_request"
|
||||||
case HookEventIssueComment, HookEventPullRequestComment:
|
case HookEventIssueComment, HookEventPullRequestComment:
|
||||||
return "issue_comment"
|
return "issue_comment"
|
||||||
|
|
|
@ -2118,6 +2118,8 @@ settings.event_pull_request_review = Pull Request Reviewed
|
||||||
settings.event_pull_request_review_desc = Pull request approved, rejected, or review comment.
|
settings.event_pull_request_review_desc = Pull request approved, rejected, or review comment.
|
||||||
settings.event_pull_request_sync = Pull Request Synchronized
|
settings.event_pull_request_sync = Pull Request Synchronized
|
||||||
settings.event_pull_request_sync_desc = Pull request synchronized.
|
settings.event_pull_request_sync_desc = Pull request synchronized.
|
||||||
|
settings.event_pull_request_review_request = Pull Request Review Requested
|
||||||
|
settings.event_pull_request_review_request_desc = Pull request review requested or review request removed.
|
||||||
settings.event_pull_request_approvals = Pull Request Approvals
|
settings.event_pull_request_approvals = Pull Request Approvals
|
||||||
settings.event_pull_request_merge = Pull Request Merge
|
settings.event_pull_request_merge = Pull Request Merge
|
||||||
settings.event_package = Package
|
settings.event_package = Package
|
||||||
|
|
|
@ -194,6 +194,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
|
||||||
PullRequestMilestone: pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)),
|
PullRequestMilestone: pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)),
|
||||||
PullRequestComment: pullHook(form.Events, string(webhook_module.HookEventPullRequestComment)),
|
PullRequestComment: pullHook(form.Events, string(webhook_module.HookEventPullRequestComment)),
|
||||||
PullRequestReview: pullHook(form.Events, "pull_request_review"),
|
PullRequestReview: pullHook(form.Events, "pull_request_review"),
|
||||||
|
PullRequestReviewRequest: pullHook(form.Events, string(webhook_module.HookEventPullRequestReviewRequest)),
|
||||||
PullRequestSync: pullHook(form.Events, string(webhook_module.HookEventPullRequestSync)),
|
PullRequestSync: pullHook(form.Events, string(webhook_module.HookEventPullRequestSync)),
|
||||||
Wiki: util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true),
|
Wiki: util.SliceContainsString(form.Events, string(webhook_module.HookEventWiki), true),
|
||||||
Repository: util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true),
|
Repository: util.SliceContainsString(form.Events, string(webhook_module.HookEventRepository), true),
|
||||||
|
@ -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.PullRequestMilestone = pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone))
|
||||||
w.PullRequestComment = pullHook(form.Events, string(webhook_module.HookEventPullRequestComment))
|
w.PullRequestComment = pullHook(form.Events, string(webhook_module.HookEventPullRequestComment))
|
||||||
w.PullRequestReview = pullHook(form.Events, "pull_request_review")
|
w.PullRequestReview = pullHook(form.Events, "pull_request_review")
|
||||||
|
w.PullRequestReviewRequest = pullHook(form.Events, string(webhook_module.HookEventPullRequestReviewRequest))
|
||||||
w.PullRequestSync = pullHook(form.Events, string(webhook_module.HookEventPullRequestSync))
|
w.PullRequestSync = pullHook(form.Events, string(webhook_module.HookEventPullRequestSync))
|
||||||
|
|
||||||
if err := w.UpdateEvent(); err != nil {
|
if err := w.UpdateEvent(); err != nil {
|
||||||
|
|
|
@ -576,7 +576,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is
|
||||||
}
|
}
|
||||||
ctx.Data["OriginalReviews"] = originalAuthorReviews
|
ctx.Data["OriginalReviews"] = originalAuthorReviews
|
||||||
|
|
||||||
reviews, err := issues_model.GetReviewersByIssueID(issue.ID)
|
reviews, err := issues_model.GetReviewsByIssueID(issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetReviewersByIssueID", err)
|
ctx.ServerError("GetReviewersByIssueID", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -177,6 +177,7 @@ func ParseHookEvent(form forms.WebhookForm) *webhook_module.HookEvent {
|
||||||
PullRequestComment: form.PullRequestComment,
|
PullRequestComment: form.PullRequestComment,
|
||||||
PullRequestReview: form.PullRequestReview,
|
PullRequestReview: form.PullRequestReview,
|
||||||
PullRequestSync: form.PullRequestSync,
|
PullRequestSync: form.PullRequestSync,
|
||||||
|
PullRequestReviewRequest: form.PullRequestReviewRequest,
|
||||||
Wiki: form.Wiki,
|
Wiki: form.Wiki,
|
||||||
Repository: form.Repository,
|
Repository: form.Repository,
|
||||||
Package: form.Package,
|
Package: form.Package,
|
||||||
|
|
|
@ -88,6 +88,14 @@ 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
|
||||||
|
}
|
||||||
|
for _, reviewer := range pr.RequestedReviewers {
|
||||||
|
apiPullRequest.RequestedReviewers = append(apiPullRequest.RequestedReviewers, ToUser(ctx, reviewer, nil))
|
||||||
|
}
|
||||||
|
|
||||||
if pr.Issue.ClosedUnix != 0 {
|
if pr.Issue.ClosedUnix != 0 {
|
||||||
apiPullRequest.Closed = pr.Issue.ClosedUnix.AsTimePtr()
|
apiPullRequest.Closed = pr.Issue.ClosedUnix.AsTimePtr()
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,6 +246,7 @@ type WebhookForm struct {
|
||||||
PullRequestComment bool
|
PullRequestComment bool
|
||||||
PullRequestReview bool
|
PullRequestReview bool
|
||||||
PullRequestSync bool
|
PullRequestSync bool
|
||||||
|
PullRequestReviewRequest bool
|
||||||
Wiki bool
|
Wiki bool
|
||||||
Repository bool
|
Repository bool
|
||||||
Package bool
|
Package bool
|
||||||
|
|
|
@ -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.HookEventPullRequestReviewRequest, 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) {
|
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)
|
apiPusher := convert.ToUser(ctx, pusher, nil)
|
||||||
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
|
apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone)
|
||||||
|
|
|
@ -43,7 +43,7 @@ func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_module.
|
||||||
case webhook_module.HookEventPush:
|
case webhook_module.HookEventPush:
|
||||||
return s.Push(p.(*api.PushPayload))
|
return s.Push(p.(*api.PushPayload))
|
||||||
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestAssign, webhook_module.HookEventPullRequestLabel,
|
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestAssign, webhook_module.HookEventPullRequestLabel,
|
||||||
webhook_module.HookEventPullRequestMilestone, webhook_module.HookEventPullRequestSync:
|
webhook_module.HookEventPullRequestMilestone, webhook_module.HookEventPullRequestSync, webhook_module.HookEventPullRequestReviewRequest:
|
||||||
return s.PullRequest(p.(*api.PullRequestPayload))
|
return s.PullRequest(p.(*api.PullRequestPayload))
|
||||||
case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment:
|
case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment:
|
||||||
return s.Review(p.(*api.PullRequestPayload), event)
|
return s.Review(p.(*api.PullRequestPayload), event)
|
||||||
|
|
|
@ -238,6 +238,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Pull Request Review Request -->
|
||||||
|
<div class="seven wide column">
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input name="pull_request_review_request" type="checkbox" tabindex="0" {{if .Webhook.PullRequestReviewRequest}}checked{{end}}>
|
||||||
|
<label>{{.locale.Tr "repo.settings.event_pull_request_review_request"}}</label>
|
||||||
|
<span class="help">{{.locale.Tr "repo.settings.event_pull_request_review_request_desc"}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -19934,6 +19934,13 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "PatchURL"
|
"x-go-name": "PatchURL"
|
||||||
},
|
},
|
||||||
|
"requested_reviewers": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
|
},
|
||||||
|
"x-go-name": "RequestedReviewers"
|
||||||
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"$ref": "#/definitions/StateType"
|
"$ref": "#/definitions/StateType"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue