diff --git a/models/issues/review.go b/models/issues/review.go index 22f217a5508..af6c61a87c3 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -543,6 +543,10 @@ func SubmitReview(ctx context.Context, doer *user_model.User, issue *Issue, revi } } + if reviewType == ReviewTypePending { + return review, nil, committer.Commit() + } + comm, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReview, Doer: doer, diff --git a/modules/structs/pull_review.go b/modules/structs/pull_review.go index 82c86b5b4ac..7ae8f487943 100644 --- a/modules/structs/pull_review.go +++ b/modules/structs/pull_review.go @@ -86,6 +86,7 @@ type CreatePullReviewOptions struct { // CreatePullReviewComment represent a review comment for creation api type CreatePullReviewComment struct { // the tree path + // required: true Path string `json:"path"` Body string `json:"body"` // if comment to old file line or 0 diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index 54bd995fa6c..686b3e0ae3e 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -503,6 +503,13 @@ func CreatePullReview(ctx *context.APIContext) { // "$ref": "#/responses/validationError" opts := web.GetForm[*api.CreatePullReviewOptions](ctx) + for _, comment := range opts.Comments { + if comment.Path == "" || (comment.NewLineNum <= 0 && comment.OldLineNum <= 0) { + ctx.APIError(http.StatusUnprocessableEntity, "review comments require a path and a positive new_position or old_position") + return + } + } + pr, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.PathParamInt64("index")) if err != nil { ctx.APIErrorAuto(err) diff --git a/services/pull/review.go b/services/pull/review.go index 43ddca15aab..777ab4a7bf2 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -325,6 +325,9 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos if err != nil { return nil, nil, err } + if reviewType == issues_model.ReviewTypePending { + return review, nil, nil + } mentions, err := issues_model.FindAndUpdateIssueMentions(ctx, issue, doer, comm.Content) if err != nil { diff --git a/templates/swagger/v1-openapi3.generated.json b/templates/swagger/v1-openapi3.generated.json index 787e2569aea..9943304678c 100644 --- a/templates/swagger/v1-openapi3.generated.json +++ b/templates/swagger/v1-openapi3.generated.json @@ -4596,6 +4596,9 @@ "x-go-name": "Path" } }, + "required": [ + "path" + ], "type": "object", "x-go-package": "gitea.dev/modules/structs" }, diff --git a/templates/swagger/v1-swagger.generated.json b/templates/swagger/v1-swagger.generated.json index 03d590c4077..c90b2b6fcee 100644 --- a/templates/swagger/v1-swagger.generated.json +++ b/templates/swagger/v1-swagger.generated.json @@ -27644,6 +27644,9 @@ "CreatePullReviewComment": { "description": "CreatePullReviewComment represent a review comment for creation api", "type": "object", + "required": [ + "path" + ], "properties": { "body": { "type": "string", diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go index e173b3b5237..da4e63c51b7 100644 --- a/tests/integration/api_pull_review_test.go +++ b/tests/integration/api_pull_review_test.go @@ -90,6 +90,20 @@ func testAPIPullReviewGeneral(t *testing.T) { assert.EqualValues(t, comment.UpdatedUnix, reviewComments[0].Updated.Unix()) assert.Equal(t, comment.HTMLURL(t.Context()), reviewComments[0].HTMLURL) + for _, invalidComment := range []api.CreatePullReviewComment{ + {Body: "missing path", NewLineNum: 1}, + {Path: "README.md", Body: "missing line"}, + } { + req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews", repo.OwnerName, repo.Name, pullIssue.Index), &api.CreatePullReviewOptions{ + Comments: []api.CreatePullReviewComment{ + {Path: "README.md", Body: "comment before invalid anchor", NewLineNum: 1}, + invalidComment, + }, + }).AddTokenAuth(token) + MakeRequest(t, req, http.StatusUnprocessableEntity) + } + unittest.AssertNotExistsBean(t, &issues_model.Comment{IssueID: pullIssue.ID, Content: "comment before invalid anchor"}) + // test CreatePullReview req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/reviews", repo.OwnerName, repo.Name, pullIssue.Index), &api.CreatePullReviewOptions{ Body: "body1", @@ -130,6 +144,7 @@ func testAPIPullReviewGeneral(t *testing.T) { assert.EqualValues(t, "APPROVED", review.State) assert.Equal(t, 3, review.CodeCommentsCount) + unittest.AssertCount(t, &issues_model.Comment{ReviewID: review.ID, Type: issues_model.CommentTypeReview}, 1) reviewComment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ReviewID: review.ID, Type: issues_model.CommentTypeReview}) req = NewRequestWithJSON(t, http.MethodPatch, fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d", repo.OwnerName, repo.Name, reviewComment.ID), &api.EditIssueCommentOption{Body: "just one nit"}).AddTokenAuth(getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue)) MakeRequest(t, req, http.StatusOK)