From eb5b55b1b7438a40da2462401a95dfdff493b20d Mon Sep 17 00:00:00 2001
From: Earl Warren <contact@earl-warren.org>
Date: Thu, 11 Jan 2024 12:32:18 +0100
Subject: [PATCH] [GITEA] GET
 /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments/{comment}

Refs: https://codeberg.org/forgejo/forgejo/issues/2109
(cherry picked from commit 69fcf26dee0e6886460b533575f29e5b818bbc17)
(cherry picked from commit 1296f4d115e1441657cfdac53807743a8b7ca6ba)
(cherry picked from commit 119d10d9e277e7f738eba8087ce6cf4905e183e8)
---
 routers/api/v1/api.go                     |  9 ++--
 routers/api/v1/repo/pull_review.go        | 63 +++++++++++++++++++++++
 templates/swagger/v1_json.tmpl            | 63 +++++++++++++++++++++++
 tests/integration/api_pull_review_test.go | 19 ++++---
 4 files changed, 141 insertions(+), 13 deletions(-)

diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index c5399473c6..6e800fdee8 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -1261,9 +1261,12 @@ func Routes() *web.Route {
 									Get(repo.GetPullReview).
 									Delete(reqToken(), repo.DeletePullReview).
 									Post(reqToken(), bind(api.SubmitPullReviewOptions{}), repo.SubmitPullReview)
-								m.Combo("/comments").
-									Get(repo.GetPullReviewComments).
-									Post(reqToken(), bind(api.CreatePullReviewCommentOptions{}), repo.CreatePullReviewComment)
+								m.Group("/comments", func() {
+									m.Combo("").
+										Get(repo.GetPullReviewComments).
+										Post(reqToken(), bind(api.CreatePullReviewCommentOptions{}), repo.CreatePullReviewComment)
+									m.Get("/{comment}", commentAssignment("comment"), repo.GetPullReviewComment)
+								})
 								m.Post("/dismissals", reqToken(), bind(api.DismissPullReviewOptions{}), repo.DismissPullReview)
 								m.Post("/undismissals", reqToken(), repo.UnDismissPullReview)
 							})
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index e6b39f653e..ad9e2c5981 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -208,6 +208,69 @@ func GetPullReviewComments(ctx *context.APIContext) {
 	ctx.JSON(http.StatusOK, apiComments)
 }
 
+// GetPullReviewComment get a pull review comment
+func GetPullReviewComment(ctx *context.APIContext) {
+	// swagger:operation GET /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments/{comment} repository repoGetPullReviewComment
+	// ---
+	// summary: Get a pull review comment
+	// produces:
+	// - application/json
+	// parameters:
+	// - name: owner
+	//   in: path
+	//   description: owner of the repo
+	//   type: string
+	//   required: true
+	// - name: repo
+	//   in: path
+	//   description: name of the repo
+	//   type: string
+	//   required: true
+	// - name: index
+	//   in: path
+	//   description: index of the pull request
+	//   type: integer
+	//   format: int64
+	//   required: true
+	// - name: id
+	//   in: path
+	//   description: id of the review
+	//   type: integer
+	//   format: int64
+	//   required: true
+	// - name: comment
+	//   in: path
+	//   description: id of the comment
+	//   type: integer
+	//   format: int64
+	//   required: true
+	// responses:
+	//   "200":
+	//     "$ref": "#/responses/PullReviewComment"
+	//   "403":
+	//     "$ref": "#/responses/forbidden"
+	//   "404":
+	//     "$ref": "#/responses/notFound"
+
+	review, _, statusSet := prepareSingleReview(ctx)
+	if statusSet {
+		return
+	}
+
+	if err := ctx.Comment.LoadPoster(ctx); err != nil {
+		ctx.InternalServerError(err)
+		return
+	}
+
+	apiComment, err := convert.ToPullReviewComment(ctx, review, ctx.Comment, ctx.Doer)
+	if err != nil {
+		ctx.InternalServerError(err)
+		return
+	}
+
+	ctx.JSON(http.StatusOK, apiComment)
+}
+
 // CreatePullReviewComments add a new comment to a pull request review
 func CreatePullReviewComment(ctx *context.APIContext) {
 	// swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments repository repoCreatePullReviewComment
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 5a20163238..91f4593e67 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -11605,6 +11605,69 @@
         }
       }
     },
+    "/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments/{comment}": {
+      "get": {
+        "produces": [
+          "application/json"
+        ],
+        "tags": [
+          "repository"
+        ],
+        "summary": "Get a pull review comment",
+        "operationId": "repoGetPullReviewComment",
+        "parameters": [
+          {
+            "type": "string",
+            "description": "owner of the repo",
+            "name": "owner",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "string",
+            "description": "name of the repo",
+            "name": "repo",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "integer",
+            "format": "int64",
+            "description": "index of the pull request",
+            "name": "index",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "integer",
+            "format": "int64",
+            "description": "id of the review",
+            "name": "id",
+            "in": "path",
+            "required": true
+          },
+          {
+            "type": "integer",
+            "format": "int64",
+            "description": "id of the comment",
+            "name": "comment",
+            "in": "path",
+            "required": true
+          }
+        ],
+        "responses": {
+          "200": {
+            "$ref": "#/responses/PullReviewComment"
+          },
+          "403": {
+            "$ref": "#/responses/forbidden"
+          },
+          "404": {
+            "$ref": "#/responses/notFound"
+          }
+        }
+      }
+    },
     "/repos/{owner}/{repo}/pulls/{index}/reviews/{id}/dismissals": {
       "post": {
         "produces": [
diff --git a/tests/integration/api_pull_review_test.go b/tests/integration/api_pull_review_test.go
index 4d4df739d7..db44e1ade5 100644
--- a/tests/integration/api_pull_review_test.go
+++ b/tests/integration/api_pull_review_test.go
@@ -68,6 +68,7 @@ func TestAPIPullReviewCreateComment(t *testing.T) {
 			}
 
 			newCommentBody := "first new line"
+			var reviewComment api.PullReviewComment
 
 			{
 				req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/pulls/%d/reviews/%d/comments", repo.FullName(), pullIssue.Index, review.ID), &api.CreatePullReviewCommentOptions{
@@ -76,24 +77,22 @@ func TestAPIPullReviewCreateComment(t *testing.T) {
 					OldLineNum: reviewLine,
 				}).AddTokenAuth(token)
 				resp := MakeRequest(t, req, http.StatusOK)
-				var reviewComment *api.PullReviewComment
 				DecodeJSON(t, resp, &reviewComment)
 				assert.EqualValues(t, review.ID, reviewComment.ReviewID)
+				assert.EqualValues(t, newCommentBody, reviewComment.Body)
+				assert.EqualValues(t, reviewLine, reviewComment.OldLineNum)
+				assert.EqualValues(t, 0, reviewComment.LineNum)
+				assert.EqualValues(t, path, reviewComment.Path)
 			}
 
 			{
-				req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments", repo.FullName(), pullIssue.Index, review.ID).
+				req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/pulls/%d/reviews/%d/comments/%d", repo.FullName(), pullIssue.Index, review.ID, reviewComment.ID).
 					AddTokenAuth(token)
 				resp := MakeRequest(t, req, http.StatusOK)
 
-				var reviewComments []*api.PullReviewComment
-				DecodeJSON(t, resp, &reviewComments)
-				assert.Len(t, reviewComments, 2)
-				assert.EqualValues(t, existingCommentBody, reviewComments[0].Body)
-				assert.EqualValues(t, reviewComments[0].OldLineNum, reviewComments[1].OldLineNum)
-				assert.EqualValues(t, reviewComments[0].LineNum, reviewComments[1].LineNum)
-				assert.EqualValues(t, newCommentBody, reviewComments[1].Body)
-				assert.EqualValues(t, path, reviewComments[1].Path)
+				var comment api.PullReviewComment
+				DecodeJSON(t, resp, &comment)
+				assert.EqualValues(t, reviewComment, comment)
 			}
 
 			{