Add dismiss review feature (#12674)
* Add dismiss review feature refs: https://github.blog/2016-10-12-dismissing-reviews-on-pull-requests/ https://developer.github.com/v3/pulls/reviews/#dismiss-a-review-for-a-pull-request * change modal ui and error message * Add unDismissReview api Signed-off-by: a1012112796 <1012112796@qq.com> Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
parent
c69c01d2b6
commit
ac701637b4
36 changed files with 593 additions and 39 deletions
|
@ -26,30 +26,31 @@ type ActionType int
|
|||
|
||||
// Possible action types.
|
||||
const (
|
||||
ActionCreateRepo ActionType = iota + 1 // 1
|
||||
ActionRenameRepo // 2
|
||||
ActionStarRepo // 3
|
||||
ActionWatchRepo // 4
|
||||
ActionCommitRepo // 5
|
||||
ActionCreateIssue // 6
|
||||
ActionCreatePullRequest // 7
|
||||
ActionTransferRepo // 8
|
||||
ActionPushTag // 9
|
||||
ActionCommentIssue // 10
|
||||
ActionMergePullRequest // 11
|
||||
ActionCloseIssue // 12
|
||||
ActionReopenIssue // 13
|
||||
ActionClosePullRequest // 14
|
||||
ActionReopenPullRequest // 15
|
||||
ActionDeleteTag // 16
|
||||
ActionDeleteBranch // 17
|
||||
ActionMirrorSyncPush // 18
|
||||
ActionMirrorSyncCreate // 19
|
||||
ActionMirrorSyncDelete // 20
|
||||
ActionApprovePullRequest // 21
|
||||
ActionRejectPullRequest // 22
|
||||
ActionCommentPull // 23
|
||||
ActionPublishRelease // 24
|
||||
ActionCreateRepo ActionType = iota + 1 // 1
|
||||
ActionRenameRepo // 2
|
||||
ActionStarRepo // 3
|
||||
ActionWatchRepo // 4
|
||||
ActionCommitRepo // 5
|
||||
ActionCreateIssue // 6
|
||||
ActionCreatePullRequest // 7
|
||||
ActionTransferRepo // 8
|
||||
ActionPushTag // 9
|
||||
ActionCommentIssue // 10
|
||||
ActionMergePullRequest // 11
|
||||
ActionCloseIssue // 12
|
||||
ActionReopenIssue // 13
|
||||
ActionClosePullRequest // 14
|
||||
ActionReopenPullRequest // 15
|
||||
ActionDeleteTag // 16
|
||||
ActionDeleteBranch // 17
|
||||
ActionMirrorSyncPush // 18
|
||||
ActionMirrorSyncCreate // 19
|
||||
ActionMirrorSyncDelete // 20
|
||||
ActionApprovePullRequest // 21
|
||||
ActionRejectPullRequest // 22
|
||||
ActionCommentPull // 23
|
||||
ActionPublishRelease // 24
|
||||
ActionPullReviewDismissed // 25
|
||||
)
|
||||
|
||||
// Action represents user operation type and other information to
|
||||
|
@ -259,7 +260,7 @@ func (a *Action) GetCreate() time.Time {
|
|||
// GetIssueInfos returns a list of issues associated with
|
||||
// the action.
|
||||
func (a *Action) GetIssueInfos() []string {
|
||||
return strings.SplitN(a.Content, "|", 2)
|
||||
return strings.SplitN(a.Content, "|", 3)
|
||||
}
|
||||
|
||||
// GetIssueTitle returns the title of first issue associated
|
||||
|
|
|
@ -157,7 +157,8 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
|
|||
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
|
||||
sess := x.Where("issue_id = ?", pr.IssueID).
|
||||
And("type = ?", ReviewTypeApprove).
|
||||
And("official = ?", true)
|
||||
And("official = ?", true).
|
||||
And("dismissed = ?", false)
|
||||
if protectBranch.DismissStaleApprovals {
|
||||
sess = sess.And("stale = ?", false)
|
||||
}
|
||||
|
@ -178,6 +179,7 @@ func (protectBranch *ProtectedBranch) MergeBlockedByRejectedReview(pr *PullReque
|
|||
rejectExist, err := x.Where("issue_id = ?", pr.IssueID).
|
||||
And("type = ?", ReviewTypeReject).
|
||||
And("official = ?", true).
|
||||
And("dismissed = ?", false).
|
||||
Exist(new(Review))
|
||||
if err != nil {
|
||||
log.Error("MergeBlockedByRejectedReview: %v", err)
|
||||
|
|
|
@ -104,4 +104,4 @@
|
|||
issue_id: 12
|
||||
official: true
|
||||
updated_unix: 1603196749
|
||||
created_unix: 1603196749
|
||||
created_unix: 1603196749
|
||||
|
|
|
@ -99,6 +99,8 @@ const (
|
|||
CommentTypeProject
|
||||
// 31 Project board changed
|
||||
CommentTypeProjectBoard
|
||||
// Dismiss Review
|
||||
CommentTypeDismissReview
|
||||
)
|
||||
|
||||
// CommentTag defines comment tag type
|
||||
|
|
|
@ -530,7 +530,7 @@ func (issues IssueList) getApprovalCounts(e Engine) (map[int64][]*ReviewCount, e
|
|||
}
|
||||
sess := e.In("issue_id", ids)
|
||||
err := sess.Select("issue_id, type, count(id) as `count`").
|
||||
Where("official = ?", true).
|
||||
Where("official = ? AND dismissed = ?", true, false).
|
||||
GroupBy("issue_id, type").
|
||||
OrderBy("issue_id").
|
||||
Table("review").
|
||||
|
|
|
@ -286,6 +286,8 @@ var migrations = []Migration{
|
|||
NewMigration("Recreate user table to fix default values", recreateUserTableToFixDefaultValues),
|
||||
// v169 -> v170
|
||||
NewMigration("Update DeleteBranch comments to set the old_ref to the commit_sha", commentTypeDeleteBranchUseOldRef),
|
||||
// v170 -> v171
|
||||
NewMigration("Add Dismissed to Review table", addDismissedReviewColumn),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
|
|
22
models/migrations/v170.go
Normal file
22
models/migrations/v170.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func addDismissedReviewColumn(x *xorm.Engine) error {
|
||||
type Review struct {
|
||||
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
|
||||
}
|
||||
|
||||
if err := x.Sync2(new(Review)); err != nil {
|
||||
return fmt.Errorf("Sync2: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -234,7 +234,7 @@ func (pr *PullRequest) GetApprovalCounts() ([]*ReviewCount, error) {
|
|||
func (pr *PullRequest) getApprovalCounts(e Engine) ([]*ReviewCount, error) {
|
||||
rCounts := make([]*ReviewCount, 0, 6)
|
||||
sess := e.Where("issue_id = ?", pr.IssueID)
|
||||
return rCounts, sess.Select("issue_id, type, count(id) as `count`").Where("official = ?", true).GroupBy("issue_id, type").Table("review").Find(&rCounts)
|
||||
return rCounts, sess.Select("issue_id, type, count(id) as `count`").Where("official = ? AND dismissed = ?", true, false).GroupBy("issue_id, type").Table("review").Find(&rCounts)
|
||||
}
|
||||
|
||||
// GetApprovers returns the approvers of the pull request
|
||||
|
|
|
@ -63,9 +63,10 @@ type Review struct {
|
|||
IssueID int64 `xorm:"index"`
|
||||
Content string `xorm:"TEXT"`
|
||||
// Official is a review made by an assigned approver (counts towards approval)
|
||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CommitID string `xorm:"VARCHAR(40)"`
|
||||
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||
CommitID string `xorm:"VARCHAR(40)"`
|
||||
Stale bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Dismissed bool `xorm:"NOT NULL DEFAULT false"`
|
||||
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
|
@ -466,8 +467,8 @@ func GetReviewersByIssueID(issueID int64) ([]*Review, error) {
|
|||
}
|
||||
|
||||
// Get latest review of each reviwer, sorted in order they were made
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -558,6 +559,19 @@ func MarkReviewsAsNotStale(issueID int64, commitID string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// DismissReview change the dismiss status of a review
|
||||
func DismissReview(review *Review, isDismiss bool) (err error) {
|
||||
if review.Dismissed == isDismiss || (review.Type != ReviewTypeApprove && review.Type != ReviewTypeReject) {
|
||||
return nil
|
||||
}
|
||||
|
||||
review.Dismissed = isDismiss
|
||||
|
||||
_, err = x.Cols("dismissed").Update(review)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// InsertReviews inserts review and review comments
|
||||
func InsertReviews(reviews []*Review) error {
|
||||
sess := x.NewSession()
|
||||
|
|
|
@ -142,3 +142,13 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDismissReview(t *testing.T) {
|
||||
review1 := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
|
||||
review2 := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
|
||||
assert.NoError(t, DismissReview(review1, true))
|
||||
assert.NoError(t, DismissReview(review2, true))
|
||||
assert.NoError(t, DismissReview(review2, true))
|
||||
assert.NoError(t, DismissReview(review2, false))
|
||||
assert.NoError(t, DismissReview(review2, false))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue