Skip to content

Commit

Permalink
Prevent re-review and dismiss review actions on merged PRs
Browse files Browse the repository at this point in the history
  • Loading branch information
kemzeb committed Mar 26, 2024
1 parent 475b6e8 commit 4ca7b0f
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 5 deletions.
41 changes: 38 additions & 3 deletions models/issues/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ func (err ErrNotValidReviewRequest) Unwrap() error {
return util.ErrInvalidArgument
}

// ErrReReviewRequestOnMergedPR represents an error when an user tries to request a re-review on a merged PR.
type ErrReReviewRequestOnMergedPR struct {
}

// IsErrReReviewRequestOnMergedPR checks if an error is an ErrRequestedReReviewOnMergedPR.
func IsErrReReviewRequestOnMergedPR(err error) bool {
_, ok := err.(ErrReReviewRequestOnMergedPR)
return ok
}

func (err ErrReReviewRequestOnMergedPR) Error() string {
return "cannot request a re-review on a merged PR"
}

func (err ErrReReviewRequestOnMergedPR) Unwrap() error {
return util.ErrPermissionDenied
}

// ReviewType defines the sort of feedback a review gives
type ReviewType int

Expand Down Expand Up @@ -618,9 +636,26 @@ func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_mo
return nil, err
}

// skip it when reviewer hase been request to review
if review != nil && review.Type == ReviewTypeRequest {
return nil, committer.Commit() // still commit the transaction, or committer.Close() will rollback it, even if it's a reused transaction.
if review != nil {
// NOTE: in case of failure we still commit the transaction here, else committer.Close() will rollback it,
// even if it's a reused transaction.

// skip it when reviewer hase been request to review
if review.Type == ReviewTypeRequest {
return nil, committer.Commit()
}

if err := issue.LoadPullRequest(ctx); err != nil {
return nil, err
}

if issue.PullRequest.HasMerged {
var err error = ErrReReviewRequestOnMergedPR{}
if err2 := committer.Commit(); err2 != nil {
err = err2
}
return nil, err
}
}

// if the reviewer is an official reviewer,
Expand Down
4 changes: 4 additions & 0 deletions routers/web/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,10 @@ func UpdatePullReviewRequest(ctx *context.Context) {

_, err = issue_service.ReviewRequest(ctx, issue, ctx.Doer, reviewer, action == "attach")
if err != nil {
if issues_model.IsErrReReviewRequestOnMergedPR(err) {
ctx.Status(http.StatusForbidden)
return
}
ctx.ServerError("ReviewRequest", err)
return
}
Expand Down
4 changes: 4 additions & 0 deletions routers/web/repo/pull_review.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ func DismissReview(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.DismissReviewForm)
comm, err := pull_service.DismissReview(ctx, form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.Doer, true, true)
if err != nil {
if pull_service.IsErrReReviewRequestOnMergedPR(err) {
ctx.Status(http.StatusForbidden)
return
}
ctx.ServerError("pull_service.DismissReview", err)
return
}
Expand Down
28 changes: 28 additions & 0 deletions services/pull/review.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,30 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
)

var notEnoughLines = regexp.MustCompile(`fatal: file .* has only \d+ lines?`)

// ErrDismissRequestOnMergedPR represents an error when an user tries to dismiss a review associated to a merged PR.
type ErrDismissRequestOnMergedPR struct {
}

// IsErrReReviewRequestOnMergedPR checks if an error is an ErrDismissRequestOnMergedPR.
func IsErrReReviewRequestOnMergedPR(err error) bool {
_, ok := err.(ErrDismissRequestOnMergedPR)
return ok
}

func (err ErrDismissRequestOnMergedPR) Error() string {
return "can't dismiss a review associated to a merged PR"
}

func (err ErrDismissRequestOnMergedPR) Unwrap() error {
return util.ErrPermissionDenied
}

// checkInvalidation checks if the line of code comment got changed by another commit.
// If the line got changed the comment is going to be invalidated.
func checkInvalidation(ctx context.Context, c *issues_model.Comment, doer *user_model.User, repo *git.Repository, branch string) error {
Expand Down Expand Up @@ -382,6 +401,15 @@ 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")
}

issue := review.Issue
if err := issue.LoadPullRequest(ctx); err != nil {
return nil, err
}

if issue.PullRequest.HasMerged {
return nil, ErrDismissRequestOnMergedPR{}
}

if err := issues_model.DismissReview(ctx, review, isDismiss); err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/issue/view_content/sidebar.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
{{end}}
</div>
<div class="tw-flex tw-items-center tw-gap-2">
{{if (and $.Permission.IsAdmin (or (eq .Review.Type 1) (eq .Review.Type 3)) (not $.Issue.IsClosed))}}
{{if (and $.Permission.IsAdmin (or (eq .Review.Type 1) (eq .Review.Type 3)) (not $.Issue.IsClosed) (not $.Issue.PullRequest.HasMerged))}}
<a href="#" class="ui muted icon tw-flex tw-items-center show-modal" data-tooltip-content="{{ctx.Locale.Tr "repo.issues.dismiss_review"}}" data-modal="#dismiss-review-modal-{{.Review.ID}}">
{{svg "octicon-x" 20}}
</a>
Expand Down Expand Up @@ -91,7 +91,7 @@
{{svg "octicon-hourglass" 16}}
</span>
{{end}}
{{if .CanChange}}
{{if and .CanChange (or .Checked (not $.Issue.PullRequest.HasMerged))}}
<a href="#" class="ui muted icon re-request-review{{if .Checked}} checked{{end}}" data-tooltip-content="{{if .Checked}}{{ctx.Locale.Tr "repo.issues.remove_request_review"}}{{else}}{{ctx.Locale.Tr "repo.issues.re_request_review"}}{{end}}" data-issue-id="{{$.Issue.ID}}" data-id="{{.ItemID}}" data-update-url="{{$.RepoLink}}/issues/request_review">{{if .Checked}}{{svg "octicon-trash"}}{{else}}{{svg "octicon-sync"}}{{end}}</a>
{{end}}
{{svg (printf "octicon-%s" .Review.Type.Icon) 16 (printf "text %s" (.Review.HTMLTypeColorName))}}
Expand Down

0 comments on commit 4ca7b0f

Please sign in to comment.