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
					
				
			
		
					 21 changed files with 305 additions and 117 deletions
				
			
		| 
						 | 
				
			
			@ -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:"-"`
 | 
			
		||||
| 
						 | 
				
			
			@ -302,6 +303,29 @@ func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) {
 | 
			
		|||
	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.
 | 
			
		||||
func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) {
 | 
			
		||||
	if pr.BaseRepo != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import (
 | 
			
		|||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
 | 
			
		||||
	"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) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
func (r *Review) LoadReviewerTeam(ctx context.Context) (err error) {
 | 
			
		||||
	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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetReviewersByIssueID gets the latest review of each reviewer for a pull request
 | 
			
		||||
func GetReviewersByIssueID(issueID int64) ([]*Review, error) {
 | 
			
		||||
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
 | 
			
		||||
func GetReviewsByIssueID(issueID int64) ([]*Review, error) {
 | 
			
		||||
	reviews := make([]*Review, 0, 10)
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -132,11 +132,22 @@ func TestGetReviewersByIssueID(t *testing.T) {
 | 
			
		|||
			UpdatedUnix: 946684814,
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	allReviews, err := issues_model.GetReviewersByIssueID(issue.ID)
 | 
			
		||||
	for _, reviewer := range allReviews {
 | 
			
		||||
		assert.NoError(t, reviewer.LoadReviewer(db.DefaultContext))
 | 
			
		||||
	}
 | 
			
		||||
	allReviews, err := issues_model.GetReviewsByIssueID(issue.ID)
 | 
			
		||||
	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) {
 | 
			
		||||
		for i, review := range allReviews {
 | 
			
		||||
			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/password/hash"
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
	"code.gitea.io/gitea/modules/container"
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
| 
						 | 
				
			
			@ -910,6 +911,15 @@ func GetUserByID(ctx context.Context, id int64) (*User, error) {
 | 
			
		|||
	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
 | 
			
		||||
func GetPossibleUserByID(ctx context.Context, id int64) (*User, error) {
 | 
			
		||||
	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.
 | 
			
		||||
func GetUserByName(ctx context.Context, name string) (*User, error) {
 | 
			
		||||
	if len(name) == 0 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -298,6 +298,12 @@ func (w *Webhook) HasPackageEvent() bool {
 | 
			
		|||
		(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
 | 
			
		||||
func (w *Webhook) EventCheckers() []struct {
 | 
			
		||||
	Has  func() bool
 | 
			
		||||
| 
						 | 
				
			
			@ -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.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_comment", "pull_request_review_approved", "pull_request_review_rejected",
 | 
			
		||||
		"pull_request_review_comment", "pull_request_sync", "wiki", "repository", "release",
 | 
			
		||||
		"package",
 | 
			
		||||
		"package", "pull_request_review_request",
 | 
			
		||||
	},
 | 
			
		||||
		(&Webhook{
 | 
			
		||||
			HookEvent: &webhook_module.HookEvent{SendEverything: true},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,26 +5,27 @@ package webhook
 | 
			
		|||
 | 
			
		||||
// HookEvents is a set of web hook events
 | 
			
		||||
type HookEvents struct {
 | 
			
		||||
	Create               bool `json:"create"`
 | 
			
		||||
	Delete               bool `json:"delete"`
 | 
			
		||||
	Fork                 bool `json:"fork"`
 | 
			
		||||
	Issues               bool `json:"issues"`
 | 
			
		||||
	IssueAssign          bool `json:"issue_assign"`
 | 
			
		||||
	IssueLabel           bool `json:"issue_label"`
 | 
			
		||||
	IssueMilestone       bool `json:"issue_milestone"`
 | 
			
		||||
	IssueComment         bool `json:"issue_comment"`
 | 
			
		||||
	Push                 bool `json:"push"`
 | 
			
		||||
	PullRequest          bool `json:"pull_request"`
 | 
			
		||||
	PullRequestAssign    bool `json:"pull_request_assign"`
 | 
			
		||||
	PullRequestLabel     bool `json:"pull_request_label"`
 | 
			
		||||
	PullRequestMilestone bool `json:"pull_request_milestone"`
 | 
			
		||||
	PullRequestComment   bool `json:"pull_request_comment"`
 | 
			
		||||
	PullRequestReview    bool `json:"pull_request_review"`
 | 
			
		||||
	PullRequestSync      bool `json:"pull_request_sync"`
 | 
			
		||||
	Wiki                 bool `json:"wiki"`
 | 
			
		||||
	Repository           bool `json:"repository"`
 | 
			
		||||
	Release              bool `json:"release"`
 | 
			
		||||
	Package              bool `json:"package"`
 | 
			
		||||
	Create                   bool `json:"create"`
 | 
			
		||||
	Delete                   bool `json:"delete"`
 | 
			
		||||
	Fork                     bool `json:"fork"`
 | 
			
		||||
	Issues                   bool `json:"issues"`
 | 
			
		||||
	IssueAssign              bool `json:"issue_assign"`
 | 
			
		||||
	IssueLabel               bool `json:"issue_label"`
 | 
			
		||||
	IssueMilestone           bool `json:"issue_milestone"`
 | 
			
		||||
	IssueComment             bool `json:"issue_comment"`
 | 
			
		||||
	Push                     bool `json:"push"`
 | 
			
		||||
	PullRequest              bool `json:"pull_request"`
 | 
			
		||||
	PullRequestAssign        bool `json:"pull_request_assign"`
 | 
			
		||||
	PullRequestLabel         bool `json:"pull_request_label"`
 | 
			
		||||
	PullRequestMilestone     bool `json:"pull_request_milestone"`
 | 
			
		||||
	PullRequestComment       bool `json:"pull_request_comment"`
 | 
			
		||||
	PullRequestReview        bool `json:"pull_request_review"`
 | 
			
		||||
	PullRequestSync          bool `json:"pull_request_sync"`
 | 
			
		||||
	PullRequestReviewRequest bool `json:"pull_request_review_request"`
 | 
			
		||||
	Wiki                     bool `json:"wiki"`
 | 
			
		||||
	Repository               bool `json:"repository"`
 | 
			
		||||
	Release                  bool `json:"release"`
 | 
			
		||||
	Package                  bool `json:"package"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HookEvent represents events that will delivery hook.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ const (
 | 
			
		|||
	HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected"
 | 
			
		||||
	HookEventPullRequestReviewComment  HookEventType = "pull_request_review_comment"
 | 
			
		||||
	HookEventPullRequestSync           HookEventType = "pull_request_sync"
 | 
			
		||||
	HookEventPullRequestReviewRequest  HookEventType = "pull_request_review_request"
 | 
			
		||||
	HookEventWiki                      HookEventType = "wiki"
 | 
			
		||||
	HookEventRepository                HookEventType = "repository"
 | 
			
		||||
	HookEventRelease                   HookEventType = "release"
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +47,7 @@ func (h HookEventType) Event() string {
 | 
			
		|||
	case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone:
 | 
			
		||||
		return "issues"
 | 
			
		||||
	case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone,
 | 
			
		||||
		HookEventPullRequestSync:
 | 
			
		||||
		HookEventPullRequestSync, HookEventPullRequestReviewRequest:
 | 
			
		||||
		return "pull_request"
 | 
			
		||||
	case HookEventIssueComment, HookEventPullRequestComment:
 | 
			
		||||
		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_sync = 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_merge = Pull Request Merge
 | 
			
		||||
settings.event_package = Package
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,25 +179,26 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
 | 
			
		|||
		HookEvent: &webhook_module.HookEvent{
 | 
			
		||||
			ChooseEvents: true,
 | 
			
		||||
			HookEvents: webhook_module.HookEvents{
 | 
			
		||||
				Create:               util.SliceContainsString(form.Events, string(webhook_module.HookEventCreate), true),
 | 
			
		||||
				Delete:               util.SliceContainsString(form.Events, string(webhook_module.HookEventDelete), true),
 | 
			
		||||
				Fork:                 util.SliceContainsString(form.Events, string(webhook_module.HookEventFork), true),
 | 
			
		||||
				Issues:               issuesHook(form.Events, "issues_only"),
 | 
			
		||||
				IssueAssign:          issuesHook(form.Events, string(webhook_module.HookEventIssueAssign)),
 | 
			
		||||
				IssueLabel:           issuesHook(form.Events, string(webhook_module.HookEventIssueLabel)),
 | 
			
		||||
				IssueMilestone:       issuesHook(form.Events, string(webhook_module.HookEventIssueMilestone)),
 | 
			
		||||
				IssueComment:         issuesHook(form.Events, string(webhook_module.HookEventIssueComment)),
 | 
			
		||||
				Push:                 util.SliceContainsString(form.Events, string(webhook_module.HookEventPush), true),
 | 
			
		||||
				PullRequest:          pullHook(form.Events, "pull_request_only"),
 | 
			
		||||
				PullRequestAssign:    pullHook(form.Events, string(webhook_module.HookEventPullRequestAssign)),
 | 
			
		||||
				PullRequestLabel:     pullHook(form.Events, string(webhook_module.HookEventPullRequestLabel)),
 | 
			
		||||
				PullRequestMilestone: pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)),
 | 
			
		||||
				PullRequestComment:   pullHook(form.Events, string(webhook_module.HookEventPullRequestComment)),
 | 
			
		||||
				PullRequestReview:    pullHook(form.Events, "pull_request_review"),
 | 
			
		||||
				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),
 | 
			
		||||
				Release:              util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true),
 | 
			
		||||
				Create:                   util.SliceContainsString(form.Events, string(webhook_module.HookEventCreate), true),
 | 
			
		||||
				Delete:                   util.SliceContainsString(form.Events, string(webhook_module.HookEventDelete), true),
 | 
			
		||||
				Fork:                     util.SliceContainsString(form.Events, string(webhook_module.HookEventFork), true),
 | 
			
		||||
				Issues:                   issuesHook(form.Events, "issues_only"),
 | 
			
		||||
				IssueAssign:              issuesHook(form.Events, string(webhook_module.HookEventIssueAssign)),
 | 
			
		||||
				IssueLabel:               issuesHook(form.Events, string(webhook_module.HookEventIssueLabel)),
 | 
			
		||||
				IssueMilestone:           issuesHook(form.Events, string(webhook_module.HookEventIssueMilestone)),
 | 
			
		||||
				IssueComment:             issuesHook(form.Events, string(webhook_module.HookEventIssueComment)),
 | 
			
		||||
				Push:                     util.SliceContainsString(form.Events, string(webhook_module.HookEventPush), true),
 | 
			
		||||
				PullRequest:              pullHook(form.Events, "pull_request_only"),
 | 
			
		||||
				PullRequestAssign:        pullHook(form.Events, string(webhook_module.HookEventPullRequestAssign)),
 | 
			
		||||
				PullRequestLabel:         pullHook(form.Events, string(webhook_module.HookEventPullRequestLabel)),
 | 
			
		||||
				PullRequestMilestone:     pullHook(form.Events, string(webhook_module.HookEventPullRequestMilestone)),
 | 
			
		||||
				PullRequestComment:       pullHook(form.Events, string(webhook_module.HookEventPullRequestComment)),
 | 
			
		||||
				PullRequestReview:        pullHook(form.Events, "pull_request_review"),
 | 
			
		||||
				PullRequestReviewRequest: pullHook(form.Events, string(webhook_module.HookEventPullRequestReviewRequest)),
 | 
			
		||||
				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),
 | 
			
		||||
				Release:                  util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true),
 | 
			
		||||
			},
 | 
			
		||||
			BranchFilter: form.BranchFilter,
 | 
			
		||||
		},
 | 
			
		||||
| 
						 | 
				
			
			@ -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.PullRequestReviewRequest = pullHook(form.Events, string(webhook_module.HookEventPullRequestReviewRequest))
 | 
			
		||||
	w.PullRequestSync = pullHook(form.Events, string(webhook_module.HookEventPullRequestSync))
 | 
			
		||||
 | 
			
		||||
	if err := w.UpdateEvent(); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -576,7 +576,7 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is
 | 
			
		|||
	}
 | 
			
		||||
	ctx.Data["OriginalReviews"] = originalAuthorReviews
 | 
			
		||||
 | 
			
		||||
	reviews, err := issues_model.GetReviewersByIssueID(issue.ID)
 | 
			
		||||
	reviews, err := issues_model.GetReviewsByIssueID(issue.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.ServerError("GetReviewersByIssueID", err)
 | 
			
		||||
		return
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -160,26 +160,27 @@ func ParseHookEvent(form forms.WebhookForm) *webhook_module.HookEvent {
 | 
			
		|||
		SendEverything: form.SendEverything(),
 | 
			
		||||
		ChooseEvents:   form.ChooseEvents(),
 | 
			
		||||
		HookEvents: webhook_module.HookEvents{
 | 
			
		||||
			Create:               form.Create,
 | 
			
		||||
			Delete:               form.Delete,
 | 
			
		||||
			Fork:                 form.Fork,
 | 
			
		||||
			Issues:               form.Issues,
 | 
			
		||||
			IssueAssign:          form.IssueAssign,
 | 
			
		||||
			IssueLabel:           form.IssueLabel,
 | 
			
		||||
			IssueMilestone:       form.IssueMilestone,
 | 
			
		||||
			IssueComment:         form.IssueComment,
 | 
			
		||||
			Release:              form.Release,
 | 
			
		||||
			Push:                 form.Push,
 | 
			
		||||
			PullRequest:          form.PullRequest,
 | 
			
		||||
			PullRequestAssign:    form.PullRequestAssign,
 | 
			
		||||
			PullRequestLabel:     form.PullRequestLabel,
 | 
			
		||||
			PullRequestMilestone: form.PullRequestMilestone,
 | 
			
		||||
			PullRequestComment:   form.PullRequestComment,
 | 
			
		||||
			PullRequestReview:    form.PullRequestReview,
 | 
			
		||||
			PullRequestSync:      form.PullRequestSync,
 | 
			
		||||
			Wiki:                 form.Wiki,
 | 
			
		||||
			Repository:           form.Repository,
 | 
			
		||||
			Package:              form.Package,
 | 
			
		||||
			Create:                   form.Create,
 | 
			
		||||
			Delete:                   form.Delete,
 | 
			
		||||
			Fork:                     form.Fork,
 | 
			
		||||
			Issues:                   form.Issues,
 | 
			
		||||
			IssueAssign:              form.IssueAssign,
 | 
			
		||||
			IssueLabel:               form.IssueLabel,
 | 
			
		||||
			IssueMilestone:           form.IssueMilestone,
 | 
			
		||||
			IssueComment:             form.IssueComment,
 | 
			
		||||
			Release:                  form.Release,
 | 
			
		||||
			Push:                     form.Push,
 | 
			
		||||
			PullRequest:              form.PullRequest,
 | 
			
		||||
			PullRequestAssign:        form.PullRequestAssign,
 | 
			
		||||
			PullRequestLabel:         form.PullRequestLabel,
 | 
			
		||||
			PullRequestMilestone:     form.PullRequestMilestone,
 | 
			
		||||
			PullRequestComment:       form.PullRequestComment,
 | 
			
		||||
			PullRequestReview:        form.PullRequestReview,
 | 
			
		||||
			PullRequestSync:          form.PullRequestSync,
 | 
			
		||||
			PullRequestReviewRequest: form.PullRequestReviewRequest,
 | 
			
		||||
			Wiki:                     form.Wiki,
 | 
			
		||||
			Repository:               form.Repository,
 | 
			
		||||
			Package:                  form.Package,
 | 
			
		||||
		},
 | 
			
		||||
		BranchFilter: form.BranchFilter,
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
		apiPullRequest.Closed = pr.Issue.ClosedUnix.AsTimePtr()
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,30 +228,31 @@ func (f *ProtectBranchForm) Validate(req *http.Request, errs binding.Errors) bin
 | 
			
		|||
 | 
			
		||||
// WebhookForm form for changing web hook
 | 
			
		||||
type WebhookForm struct {
 | 
			
		||||
	Events               string
 | 
			
		||||
	Create               bool
 | 
			
		||||
	Delete               bool
 | 
			
		||||
	Fork                 bool
 | 
			
		||||
	Issues               bool
 | 
			
		||||
	IssueAssign          bool
 | 
			
		||||
	IssueLabel           bool
 | 
			
		||||
	IssueMilestone       bool
 | 
			
		||||
	IssueComment         bool
 | 
			
		||||
	Release              bool
 | 
			
		||||
	Push                 bool
 | 
			
		||||
	PullRequest          bool
 | 
			
		||||
	PullRequestAssign    bool
 | 
			
		||||
	PullRequestLabel     bool
 | 
			
		||||
	PullRequestMilestone bool
 | 
			
		||||
	PullRequestComment   bool
 | 
			
		||||
	PullRequestReview    bool
 | 
			
		||||
	PullRequestSync      bool
 | 
			
		||||
	Wiki                 bool
 | 
			
		||||
	Repository           bool
 | 
			
		||||
	Package              bool
 | 
			
		||||
	Active               bool
 | 
			
		||||
	BranchFilter         string `binding:"GlobPattern"`
 | 
			
		||||
	AuthorizationHeader  string
 | 
			
		||||
	Events                   string
 | 
			
		||||
	Create                   bool
 | 
			
		||||
	Delete                   bool
 | 
			
		||||
	Fork                     bool
 | 
			
		||||
	Issues                   bool
 | 
			
		||||
	IssueAssign              bool
 | 
			
		||||
	IssueLabel               bool
 | 
			
		||||
	IssueMilestone           bool
 | 
			
		||||
	IssueComment             bool
 | 
			
		||||
	Release                  bool
 | 
			
		||||
	Push                     bool
 | 
			
		||||
	PullRequest              bool
 | 
			
		||||
	PullRequestAssign        bool
 | 
			
		||||
	PullRequestLabel         bool
 | 
			
		||||
	PullRequestMilestone     bool
 | 
			
		||||
	PullRequestComment       bool
 | 
			
		||||
	PullRequestReview        bool
 | 
			
		||||
	PullRequestSync          bool
 | 
			
		||||
	PullRequestReviewRequest bool
 | 
			
		||||
	Wiki                     bool
 | 
			
		||||
	Repository               bool
 | 
			
		||||
	Package                  bool
 | 
			
		||||
	Active                   bool
 | 
			
		||||
	BranchFilter             string `binding:"GlobPattern"`
 | 
			
		||||
	AuthorizationHeader      string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PushOnly if the hook will be triggered when push
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
	apiPusher := convert.ToUser(ctx, pusher, nil)
 | 
			
		||||
	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:
 | 
			
		||||
		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.HookEventPullRequestReviewRequest:
 | 
			
		||||
		return s.PullRequest(p.(*api.PullRequestPayload))
 | 
			
		||||
	case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment:
 | 
			
		||||
		return s.Review(p.(*api.PullRequestPayload), event)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_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>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								templates/swagger/v1_json.tmpl
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										7
									
								
								templates/swagger/v1_json.tmpl
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -19934,6 +19934,13 @@
 | 
			
		|||
          "type": "string",
 | 
			
		||||
          "x-go-name": "PatchURL"
 | 
			
		||||
        },
 | 
			
		||||
        "requested_reviewers": {
 | 
			
		||||
          "type": "array",
 | 
			
		||||
          "items": {
 | 
			
		||||
            "$ref": "#/definitions/User"
 | 
			
		||||
          },
 | 
			
		||||
          "x-go-name": "RequestedReviewers"
 | 
			
		||||
        },
 | 
			
		||||
        "state": {
 | 
			
		||||
          "$ref": "#/definitions/StateType"
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue