+1
release-notes/4907.md
+1
release-notes/4907.md
···
1
+
Reverted a change from Gitea which prevented allow/reject reviews on merged or closed PRs. This change was not considered by the Forgejo UI team and there is a consensus that it feels like a regression, since it interferes with workflows known to be used by Forgejo users without providing a tangible benefit.
+2
-11
routers/api/v1/repo/pull_review.go
+2
-11
routers/api/v1/repo/pull_review.go
···
4
4
package repo
5
5
6
6
import (
7
-
"errors"
8
7
"fmt"
9
8
"net/http"
10
9
"strings"
···
520
519
// create review and associate all pending review comments
521
520
review, _, err := pull_service.SubmitReview(ctx, ctx.Doer, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, opts.CommitID, nil)
522
521
if err != nil {
523
-
if errors.Is(err, pull_service.ErrSubmitReviewOnClosedPR) {
524
-
ctx.Error(http.StatusUnprocessableEntity, "", err)
525
-
} else {
526
-
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
527
-
}
522
+
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
528
523
return
529
524
}
530
525
···
612
607
// create review and associate all pending review comments
613
608
review, _, err = pull_service.SubmitReview(ctx, ctx.Doer, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, headCommitID, nil)
614
609
if err != nil {
615
-
if errors.Is(err, pull_service.ErrSubmitReviewOnClosedPR) {
616
-
ctx.Error(http.StatusUnprocessableEntity, "", err)
617
-
} else {
618
-
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
619
-
}
610
+
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
620
611
return
621
612
}
622
613
-2
routers/web/repo/pull_review.go
-2
routers/web/repo/pull_review.go
···
248
248
if issues_model.IsContentEmptyErr(err) {
249
249
ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
250
250
ctx.JSONRedirect(fmt.Sprintf("%s/pulls/%d/files", ctx.Repo.RepoLink, issue.Index))
251
-
} else if errors.Is(err, pull_service.ErrSubmitReviewOnClosedPR) {
252
-
ctx.Status(http.StatusUnprocessableEntity)
253
251
} else {
254
252
ctx.ServerError("SubmitReview", err)
255
253
}
-8
services/pull/review.go
-8
services/pull/review.go
···
6
6
7
7
import (
8
8
"context"
9
-
"errors"
10
9
"fmt"
11
10
"io"
12
11
"regexp"
···
43
42
func (err ErrDismissRequestOnClosedPR) Unwrap() error {
44
43
return util.ErrPermissionDenied
45
44
}
46
-
47
-
// ErrSubmitReviewOnClosedPR represents an error when an user tries to submit an approve or reject review associated to a closed or merged PR.
48
-
var ErrSubmitReviewOnClosedPR = errors.New("can't submit review for a closed or merged PR")
49
45
50
46
// checkInvalidation checks if the line of code comment got changed by another commit.
51
47
// If the line got changed the comment is going to be invalidated.
···
297
293
if reviewType != issues_model.ReviewTypeApprove && reviewType != issues_model.ReviewTypeReject {
298
294
stale = false
299
295
} else {
300
-
if issue.IsClosed {
301
-
return nil, nil, ErrSubmitReviewOnClosedPR
302
-
}
303
-
304
296
headCommitID, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
305
297
if err != nil {
306
298
return nil, nil, err
+12
-16
templates/repo/diff/new_review.tmpl
+12
-16
templates/repo/diff/new_review.tmpl
···
30
30
{{end}}
31
31
<div class="divider"></div>
32
32
{{$showSelfTooltip := (and $.IsSigned ($.Issue.IsPoster $.SignedUser.ID))}}
33
-
{{if not $.Issue.IsClosed}}
34
-
{{if $showSelfTooltip}}
35
-
<span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_approve"}}">
36
-
<button type="submit" name="type" value="approve" disabled class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button>
37
-
</span>
38
-
{{else}}
39
-
<button type="submit" name="type" value="approve" class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button>
40
-
{{end}}
33
+
{{if $showSelfTooltip}}
34
+
<span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_approve"}}">
35
+
<button type="submit" name="type" value="approve" disabled class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button>
36
+
</span>
37
+
{{else}}
38
+
<button type="submit" name="type" value="approve" class="ui submit primary tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.approve"}}</button>
41
39
{{end}}
42
40
<button type="submit" name="type" value="comment" class="ui submit tiny basic button btn-submit">{{ctx.Locale.Tr "repo.diff.review.comment"}}</button>
43
-
{{if not $.Issue.IsClosed}}
44
-
{{if $showSelfTooltip}}
45
-
<span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_reject"}}">
46
-
<button type="submit" name="type" value="reject" disabled class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button>
47
-
</span>
48
-
{{else}}
49
-
<button type="submit" name="type" value="reject" class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button>
50
-
{{end}}
41
+
{{if $showSelfTooltip}}
42
+
<span class="tw-inline-block" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.review.self_reject"}}">
43
+
<button type="submit" name="type" value="reject" disabled class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button>
44
+
</span>
45
+
{{else}}
46
+
<button type="submit" name="type" value="reject" class="ui submit red tiny button btn-submit">{{ctx.Locale.Tr "repo.diff.review.reject"}}</button>
51
47
{{end}}
52
48
</form>
53
49
</div>
+31
-4
tests/integration/pull_review_test.go
+31
-4
tests/integration/pull_review_test.go
···
19
19
"code.gitea.io/gitea/models/unittest"
20
20
user_model "code.gitea.io/gitea/models/user"
21
21
"code.gitea.io/gitea/modules/git"
22
+
"code.gitea.io/gitea/modules/gitrepo"
22
23
"code.gitea.io/gitea/modules/test"
23
24
issue_service "code.gitea.io/gitea/services/issue"
24
25
repo_service "code.gitea.io/gitea/services/repository"
···
412
413
// Have user1 create a fork of repo1.
413
414
testRepoFork(t, user1Session, "user2", "repo1", "user1", "repo1")
414
415
416
+
baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"})
417
+
forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"})
418
+
baseGitRepo, err := gitrepo.OpenRepository(db.DefaultContext, baseRepo)
419
+
require.NoError(t, err)
420
+
defer baseGitRepo.Close()
421
+
415
422
t.Run("Submit approve/reject review on merged PR", func(t *testing.T) {
416
423
// Create a merged PR (made by user1) in the upstream repo1.
417
424
testEditFile(t, user1Session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
···
420
427
assert.EqualValues(t, "pulls", elem[3])
421
428
testPullMerge(t, user1Session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
422
429
430
+
// Get the commit SHA
431
+
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
432
+
BaseRepoID: baseRepo.ID,
433
+
BaseBranch: "master",
434
+
HeadRepoID: forkedRepo.ID,
435
+
HeadBranch: "master",
436
+
})
437
+
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
438
+
require.NoError(t, err)
439
+
423
440
// Grab the CSRF token.
424
441
req := NewRequest(t, "GET", path.Join(elem[1], elem[2], "pulls", elem[4]))
425
442
resp = user2Session.MakeRequest(t, req, http.StatusOK)
426
443
htmlDoc := NewHTMLParser(t, resp.Body)
427
444
428
445
// Submit an approve review on the PR.
429
-
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "approve", http.StatusUnprocessableEntity)
446
+
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], sha, "approve", http.StatusOK)
430
447
431
448
// Submit a reject review on the PR.
432
-
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "reject", http.StatusUnprocessableEntity)
449
+
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], sha, "reject", http.StatusOK)
433
450
})
434
451
435
452
t.Run("Submit approve/reject review on closed PR", func(t *testing.T) {
···
440
457
assert.EqualValues(t, "pulls", elem[3])
441
458
testIssueClose(t, user1Session, elem[1], elem[2], elem[4])
442
459
460
+
// Get the commit SHA
461
+
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
462
+
BaseRepoID: baseRepo.ID,
463
+
BaseBranch: "master",
464
+
HeadRepoID: forkedRepo.ID,
465
+
HeadBranch: "a-test-branch",
466
+
})
467
+
sha, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
468
+
require.NoError(t, err)
469
+
443
470
// Grab the CSRF token.
444
471
req := NewRequest(t, "GET", path.Join(elem[1], elem[2], "pulls", elem[4]))
445
472
resp = user2Session.MakeRequest(t, req, http.StatusOK)
446
473
htmlDoc := NewHTMLParser(t, resp.Body)
447
474
448
475
// Submit an approve review on the PR.
449
-
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "approve", http.StatusUnprocessableEntity)
476
+
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], sha, "approve", http.StatusOK)
450
477
451
478
// Submit a reject review on the PR.
452
-
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], "", "reject", http.StatusUnprocessableEntity)
479
+
testSubmitReview(t, user2Session, htmlDoc.GetCSRF(), "user2", "repo1", elem[4], sha, "reject", http.StatusOK)
453
480
})
454
481
})
455
482
}