Fix bug when pushing to a pull request which enabled dismiss approval automatically (#25882) (#26158)
Fix #25858 Backport #25882 The option `dissmiss stale approvals` was listed on protected branch but never implemented. This PR fixes that. <img width="1006" alt="图片" src="https://github.com/go-gitea/gitea/assets/81045/60bfa968-4db7-4c24-b8be-2e5978f91bb9"> <img width="1021" alt="图片" src="https://github.com/go-gitea/gitea/assets/81045/8dabc14d-2dfe-40c2-94ed-24fcbf6e0e8f"> (cherry picked from commit 666038a06df6356a06d309966a925bf00253e3fa)
This commit is contained in:
parent
7bb8526736
commit
4640c53386
7 changed files with 252 additions and 163 deletions
|
@ -552,7 +552,7 @@ func GetIssueWithAttrsByID(id int64) (*Issue, error) {
|
||||||
|
|
||||||
// GetIssuesByIDs return issues with the given IDs.
|
// GetIssuesByIDs return issues with the given IDs.
|
||||||
func GetIssuesByIDs(ctx context.Context, issueIDs []int64) (IssueList, error) {
|
func GetIssuesByIDs(ctx context.Context, issueIDs []int64) (IssueList, error) {
|
||||||
issues := make([]*Issue, 0, 10)
|
issues := make([]*Issue, 0, len(issueIDs))
|
||||||
return issues, db.GetEngine(ctx).In("id", issueIDs).Find(&issues)
|
return issues, db.GetEngine(ctx).In("id", issueIDs).Find(&issues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -314,15 +314,13 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(reviews) > 0 {
|
if err = reviews.LoadReviewers(ctx); err != nil {
|
||||||
err = LoadReviewers(ctx, reviews)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, review := range reviews {
|
for _, review := range reviews {
|
||||||
pr.RequestedReviewers = append(pr.RequestedReviewers, review.Reviewer)
|
pr.RequestedReviewers = append(pr.RequestedReviewers, review.Reviewer)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,27 +162,6 @@ 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 {
|
||||||
|
@ -236,50 +215,6 @@ func GetReviewByID(ctx context.Context, id int64) (*Review, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindReviewOptions represent possible filters to find reviews
|
|
||||||
type FindReviewOptions struct {
|
|
||||||
db.ListOptions
|
|
||||||
Type ReviewType
|
|
||||||
IssueID int64
|
|
||||||
ReviewerID int64
|
|
||||||
OfficialOnly bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts *FindReviewOptions) toCond() builder.Cond {
|
|
||||||
cond := builder.NewCond()
|
|
||||||
if opts.IssueID > 0 {
|
|
||||||
cond = cond.And(builder.Eq{"issue_id": opts.IssueID})
|
|
||||||
}
|
|
||||||
if opts.ReviewerID > 0 {
|
|
||||||
cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
|
|
||||||
}
|
|
||||||
if opts.Type != ReviewTypeUnknown {
|
|
||||||
cond = cond.And(builder.Eq{"type": opts.Type})
|
|
||||||
}
|
|
||||||
if opts.OfficialOnly {
|
|
||||||
cond = cond.And(builder.Eq{"official": true})
|
|
||||||
}
|
|
||||||
return cond
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindReviews returns reviews passing FindReviewOptions
|
|
||||||
func FindReviews(ctx context.Context, opts FindReviewOptions) ([]*Review, error) {
|
|
||||||
reviews := make([]*Review, 0, 10)
|
|
||||||
sess := db.GetEngine(ctx).Where(opts.toCond())
|
|
||||||
if opts.Page > 0 {
|
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
|
||||||
}
|
|
||||||
return reviews, sess.
|
|
||||||
Asc("created_unix").
|
|
||||||
Asc("id").
|
|
||||||
Find(&reviews)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CountReviews returns count of reviews passing FindReviewOptions
|
|
||||||
func CountReviews(opts FindReviewOptions) (int64, error) {
|
|
||||||
return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateReviewOptions represent the options to create a review. Type, Issue and Reviewer are required.
|
// CreateReviewOptions represent the options to create a review. Type, Issue and Reviewer are required.
|
||||||
type CreateReviewOptions struct {
|
type CreateReviewOptions struct {
|
||||||
Content string
|
Content string
|
||||||
|
@ -512,76 +447,6 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co
|
||||||
return review, comm, committer.Commit()
|
return review, comm, committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetReviewOptions represent filter options for GetReviews
|
|
||||||
type GetReviewOptions struct {
|
|
||||||
IssueID int64
|
|
||||||
ReviewerID int64
|
|
||||||
Dismissed util.OptionalBool
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReviews return reviews based on GetReviewOptions
|
|
||||||
func GetReviews(ctx context.Context, opts *GetReviewOptions) ([]*Review, error) {
|
|
||||||
if opts == nil {
|
|
||||||
return nil, fmt.Errorf("opts are nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
sess := db.GetEngine(ctx)
|
|
||||||
|
|
||||||
if opts.IssueID != 0 {
|
|
||||||
sess = sess.Where("issue_id=?", opts.IssueID)
|
|
||||||
}
|
|
||||||
if opts.ReviewerID != 0 {
|
|
||||||
sess = sess.Where("reviewer_id=?", opts.ReviewerID)
|
|
||||||
}
|
|
||||||
if !opts.Dismissed.IsNone() {
|
|
||||||
sess = sess.Where("dismissed=?", opts.Dismissed.IsTrue())
|
|
||||||
}
|
|
||||||
|
|
||||||
reviews := make([]*Review, 0, 4)
|
|
||||||
return reviews, sess.Find(&reviews)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
// Get latest review of each reviewer, 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 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
|
|
||||||
}
|
|
||||||
|
|
||||||
teamReviewRequests := make([]*Review, 0, 5)
|
|
||||||
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 original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
|
|
||||||
issueID).
|
|
||||||
Find(&teamReviewRequests); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(teamReviewRequests) > 0 {
|
|
||||||
reviews = append(reviews, teamReviewRequests...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return reviews, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
|
||||||
func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) ([]*Review, error) {
|
|
||||||
reviews := make([]*Review, 0, 10)
|
|
||||||
|
|
||||||
// Get latest review of each reviewer, sorted in order they were made
|
|
||||||
if err := db.GetEngine(db.DefaultContext).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, original_author_id) ORDER BY review.updated_unix ASC",
|
|
||||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
|
||||||
Find(&reviews); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return reviews, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReviewByIssueIDAndUserID get the latest review of reviewer for a pull request
|
// GetReviewByIssueIDAndUserID get the latest review of reviewer for a pull request
|
||||||
func GetReviewByIssueIDAndUserID(ctx context.Context, issueID, userID int64) (*Review, error) {
|
func GetReviewByIssueIDAndUserID(ctx context.Context, issueID, userID int64) (*Review, error) {
|
||||||
review := new(Review)
|
review := new(Review)
|
||||||
|
@ -633,7 +498,7 @@ func MarkReviewsAsNotStale(issueID int64, commitID string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DismissReview change the dismiss status of a review
|
// DismissReview change the dismiss status of a review
|
||||||
func DismissReview(review *Review, isDismiss bool) (err error) {
|
func DismissReview(ctx context.Context, review *Review, isDismiss bool) (err error) {
|
||||||
if review.Dismissed == isDismiss || (review.Type != ReviewTypeApprove && review.Type != ReviewTypeReject) {
|
if review.Dismissed == isDismiss || (review.Type != ReviewTypeApprove && review.Type != ReviewTypeReject) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -644,7 +509,7 @@ func DismissReview(review *Review, isDismiss bool) (err error) {
|
||||||
return ErrReviewNotExist{}
|
return ErrReviewNotExist{}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).ID(review.ID).Cols("dismissed").Update(review)
|
_, err = db.GetEngine(ctx).ID(review.ID).Cols("dismissed").Update(review)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
172
models/issues/review_list.go
Normal file
172
models/issues/review_list.go
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package issues
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReviewList []*Review
|
||||||
|
|
||||||
|
// LoadReviewers loads reviewers
|
||||||
|
func (reviews ReviewList) LoadReviewers(ctx context.Context) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (reviews ReviewList) LoadIssues(ctx context.Context) error {
|
||||||
|
issueIds := container.Set[int64]{}
|
||||||
|
for i := 0; i < len(reviews); i++ {
|
||||||
|
issueIds.Add(reviews[i].IssueID)
|
||||||
|
}
|
||||||
|
|
||||||
|
issues, err := GetIssuesByIDs(ctx, issueIds.Values())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := issues.LoadRepositories(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
issueMap := make(map[int64]*Issue, len(issues))
|
||||||
|
for _, issue := range issues {
|
||||||
|
issueMap[issue.ID] = issue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, review := range reviews {
|
||||||
|
review.Issue = issueMap[review.IssueID]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindReviewOptions represent possible filters to find reviews
|
||||||
|
type FindReviewOptions struct {
|
||||||
|
db.ListOptions
|
||||||
|
Type ReviewType
|
||||||
|
IssueID int64
|
||||||
|
ReviewerID int64
|
||||||
|
OfficialOnly bool
|
||||||
|
Dismissed util.OptionalBool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *FindReviewOptions) toCond() builder.Cond {
|
||||||
|
cond := builder.NewCond()
|
||||||
|
if opts.IssueID > 0 {
|
||||||
|
cond = cond.And(builder.Eq{"issue_id": opts.IssueID})
|
||||||
|
}
|
||||||
|
if opts.ReviewerID > 0 {
|
||||||
|
cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
|
||||||
|
}
|
||||||
|
if opts.Type != ReviewTypeUnknown {
|
||||||
|
cond = cond.And(builder.Eq{"type": opts.Type})
|
||||||
|
}
|
||||||
|
if opts.OfficialOnly {
|
||||||
|
cond = cond.And(builder.Eq{"official": true})
|
||||||
|
}
|
||||||
|
if !opts.Dismissed.IsNone() {
|
||||||
|
cond = cond.And(builder.Eq{"dismissed": opts.Dismissed.IsTrue()})
|
||||||
|
}
|
||||||
|
return cond
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindReviews returns reviews passing FindReviewOptions
|
||||||
|
func FindReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, error) {
|
||||||
|
reviews := make([]*Review, 0, 10)
|
||||||
|
sess := db.GetEngine(ctx).Where(opts.toCond())
|
||||||
|
if opts.Page > 0 && !opts.IsListAll() {
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
}
|
||||||
|
return reviews, sess.
|
||||||
|
Asc("created_unix").
|
||||||
|
Asc("id").
|
||||||
|
Find(&reviews)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindLatestReviews returns only latest reviews per user, passing FindReviewOptions
|
||||||
|
func FindLatestReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, error) {
|
||||||
|
reviews := make([]*Review, 0, 10)
|
||||||
|
cond := opts.toCond()
|
||||||
|
sess := db.GetEngine(ctx).Where(cond)
|
||||||
|
if opts.Page > 0 {
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
sess.In("id", builder.
|
||||||
|
Select("max ( id ) ").
|
||||||
|
From("review").
|
||||||
|
Where(cond).
|
||||||
|
GroupBy("reviewer_id"))
|
||||||
|
|
||||||
|
return reviews, sess.
|
||||||
|
Asc("created_unix").
|
||||||
|
Asc("id").
|
||||||
|
Find(&reviews)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountReviews returns count of reviews passing FindReviewOptions
|
||||||
|
func CountReviews(opts FindReviewOptions) (int64, error) {
|
||||||
|
return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
||||||
|
func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) (ReviewList, error) {
|
||||||
|
reviews := make([]*Review, 0, 10)
|
||||||
|
|
||||||
|
// Get latest review of each reviewer, sorted in order they were made
|
||||||
|
if err := db.GetEngine(db.DefaultContext).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, original_author_id) ORDER BY review.updated_unix ASC",
|
||||||
|
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
||||||
|
Find(&reviews); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reviews, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||||
|
func GetReviewsByIssueID(issueID int64) (ReviewList, error) {
|
||||||
|
reviews := make([]*Review, 0, 10)
|
||||||
|
|
||||||
|
sess := db.GetEngine(db.DefaultContext)
|
||||||
|
|
||||||
|
// Get latest review of each reviewer, 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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
teamReviewRequests := make([]*Review, 0, 5)
|
||||||
|
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 original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
|
||||||
|
issueID).
|
||||||
|
Find(&teamReviewRequests); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(teamReviewRequests) > 0 {
|
||||||
|
reviews = append(reviews, teamReviewRequests...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return reviews, nil
|
||||||
|
}
|
|
@ -147,7 +147,7 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
||||||
|
|
||||||
allReviews, err = issues_model.GetReviewsByIssueID(issue.ID)
|
allReviews, err = issues_model.GetReviewsByIssueID(issue.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, issues_model.LoadReviewers(db.DefaultContext, allReviews))
|
assert.NoError(t, allReviews.LoadReviewers(db.DefaultContext))
|
||||||
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)
|
||||||
|
@ -167,46 +167,46 @@ func TestDismissReview(t *testing.T) {
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(rejectReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, rejectReviewExample, true))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, true))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, true))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, false))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, false))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(requestReviewExample, false))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, requestReviewExample, false))
|
||||||
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9})
|
||||||
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11})
|
||||||
assert.True(t, rejectReviewExample.Dismissed)
|
assert.True(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(rejectReviewExample, false))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, rejectReviewExample, false))
|
||||||
assert.False(t, rejectReviewExample.Dismissed)
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.False(t, approveReviewExample.Dismissed)
|
assert.False(t, approveReviewExample.Dismissed)
|
||||||
|
|
||||||
assert.NoError(t, issues_model.DismissReview(approveReviewExample, true))
|
assert.NoError(t, issues_model.DismissReview(db.DefaultContext, approveReviewExample, true))
|
||||||
assert.False(t, rejectReviewExample.Dismissed)
|
assert.False(t, rejectReviewExample.Dismissed)
|
||||||
assert.False(t, requestReviewExample.Dismissed)
|
assert.False(t, requestReviewExample.Dismissed)
|
||||||
assert.True(t, approveReviewExample.Dismissed)
|
assert.True(t, approveReviewExample.Dismissed)
|
||||||
|
|
|
@ -307,6 +307,17 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
|
||||||
if err := issues_model.MarkReviewsAsStale(pr.IssueID); err != nil {
|
if err := issues_model.MarkReviewsAsStale(pr.IssueID); err != nil {
|
||||||
log.Error("MarkReviewsAsStale: %v", err)
|
log.Error("MarkReviewsAsStale: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dismiss all approval reviews if protected branch rule item enabled.
|
||||||
|
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
|
||||||
|
}
|
||||||
|
if pb != nil && pb.DismissStaleApprovals {
|
||||||
|
if err := DismissApprovalReviews(ctx, doer, pr); err != nil {
|
||||||
|
log.Error("DismissApprovalReviews: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := issues_model.MarkReviewsAsNotStale(pr.IssueID, newCommitID); err != nil {
|
if err := issues_model.MarkReviewsAsNotStale(pr.IssueID, newCommitID); err != nil {
|
||||||
log.Error("MarkReviewsAsNotStale: %v", err)
|
log.Error("MarkReviewsAsNotStale: %v", err)
|
||||||
|
|
|
@ -316,6 +316,52 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos
|
||||||
return review, comm, nil
|
return review, comm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DismissApprovalReviews dismiss all approval reviews because of new commits
|
||||||
|
func DismissApprovalReviews(ctx context.Context, doer *user_model.User, pull *issues_model.PullRequest) error {
|
||||||
|
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
|
||||||
|
ListOptions: db.ListOptions{
|
||||||
|
ListAll: true,
|
||||||
|
},
|
||||||
|
IssueID: pull.IssueID,
|
||||||
|
Type: issues_model.ReviewTypeApprove,
|
||||||
|
Dismissed: util.OptionalBoolFalse,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := reviews.LoadIssues(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.WithTx(ctx, func(subCtx context.Context) error {
|
||||||
|
for _, review := range reviews {
|
||||||
|
if err := issues_model.DismissReview(subCtx, review, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
comment, err := issue_service.CreateComment(ctx, &issues_model.CreateCommentOptions{
|
||||||
|
Doer: doer,
|
||||||
|
Content: "New commits pushed, approval review dismissed automatically according to repository settings",
|
||||||
|
Type: issues_model.CommentTypeDismissReview,
|
||||||
|
ReviewID: review.ID,
|
||||||
|
Issue: review.Issue,
|
||||||
|
Repo: review.Issue.Repo,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
comment.Review = review
|
||||||
|
comment.Poster = doer
|
||||||
|
comment.Issue = review.Issue
|
||||||
|
|
||||||
|
notification.NotifyPullReviewDismiss(ctx, doer, review, comment)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// DismissReview dismissing stale review by repo admin
|
// DismissReview dismissing stale review by repo admin
|
||||||
func DismissReview(ctx context.Context, reviewID, repoID int64, message string, doer *user_model.User, isDismiss, dismissPriors bool) (comment *issues_model.Comment, err error) {
|
func DismissReview(ctx context.Context, reviewID, repoID int64, message string, doer *user_model.User, isDismiss, dismissPriors bool) (comment *issues_model.Comment, err error) {
|
||||||
review, err := issues_model.GetReviewByID(ctx, reviewID)
|
review, err := issues_model.GetReviewByID(ctx, reviewID)
|
||||||
|
@ -337,12 +383,12 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
|
||||||
return nil, fmt.Errorf("reviews's repository is not the same as the one we expect")
|
return nil, fmt.Errorf("reviews's repository is not the same as the one we expect")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = issues_model.DismissReview(review, isDismiss); err != nil {
|
if err := issues_model.DismissReview(ctx, review, isDismiss); err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if dismissPriors {
|
if dismissPriors {
|
||||||
reviews, err := issues_model.GetReviews(ctx, &issues_model.GetReviewOptions{
|
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
|
||||||
IssueID: review.IssueID,
|
IssueID: review.IssueID,
|
||||||
ReviewerID: review.ReviewerID,
|
ReviewerID: review.ReviewerID,
|
||||||
Dismissed: util.OptionalBoolFalse,
|
Dismissed: util.OptionalBoolFalse,
|
||||||
|
@ -351,7 +397,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, oldReview := range reviews {
|
for _, oldReview := range reviews {
|
||||||
if err = issues_model.DismissReview(oldReview, true); err != nil {
|
if err = issues_model.DismissReview(ctx, oldReview, true); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,11 +407,8 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string,
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = review.Issue.LoadPullRequest(ctx); err != nil {
|
if err := review.Issue.LoadAttributes(ctx); err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
|
||||||
if err = review.Issue.LoadAttributes(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
comment, err = issue_service.CreateComment(ctx, &issues_model.CreateCommentOptions{
|
comment, err = issue_service.CreateComment(ctx, &issues_model.CreateCommentOptions{
|
||||||
|
|
Loading…
Reference in a new issue