Add API endpoint to reply to pull request review comments (#36683)

Adds a dedicated endpoint for replying to pull request review comments,

```
POST /repos/{owner}/{repo}/pulls/{index}/comments/{id}/replies
{ "body": "..." }
```

The reply is threaded under the same review as the parent comment.

Ref: https://gitea.com/gitea/gitea-mcp/issues/129
Fixes: https://github.com/go-gitea/gitea/issues/37419
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Nicolas <bircni@icloud.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
silverwind
2026-04-27 10:45:59 +02:00
committed by GitHub
parent b45be5b20d
commit 331450b17a
6 changed files with 225 additions and 0 deletions

View File

@@ -1369,6 +1369,7 @@ func Routes() *web.Router {
m.Combo("/requested_reviewers", reqToken()).
Delete(bind(api.PullReviewRequestOptions{}), repo.DeleteReviewRequests).
Post(bind(api.PullReviewRequestOptions{}), repo.CreateReviewRequests)
m.Post("/comments/{id}/replies", reqToken(), mustNotBeArchived, bind(api.CreatePullReviewCommentReplyOptions{}), repo.CreatePullReviewCommentReply)
})
m.Get("/{base}/*", repo.GetPullRequestByBaseHead)
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo())

View File

@@ -208,6 +208,88 @@ func GetPullReviewComments(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, apiComments)
}
// CreatePullReviewCommentReply replies to a pull request review comment.
// The URL mirrors GitHub's endpoint, {index} is verified against the parent comment's pull request.
func CreatePullReviewCommentReply(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/pulls/{index}/comments/{id}/replies repository repoCreatePullReviewCommentReply
// ---
// summary: Reply to a pull request review comment
// consumes:
// - application/json
// 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 comment to reply to
// type: integer
// format: int64
// required: true
// - name: body
// in: body
// required: true
// schema:
// "$ref": "#/definitions/CreatePullReviewCommentReplyOptions"
// responses:
// "201":
// "$ref": "#/responses/PullReviewComment"
// "400":
// "$ref": "#/responses/validationError"
// "404":
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/validationError"
opts := web.GetForm(ctx).(*api.CreatePullReviewCommentReplyOptions)
parent := getPullReviewCommentToResolve(ctx)
if parent == nil {
return
}
if parent.Issue.Index != ctx.PathParamInt64("index") {
ctx.APIErrorNotFound()
return
}
if parent.ReviewID == 0 {
ctx.APIError(http.StatusBadRequest, "comment is not a review comment")
return
}
comment, err := pull_service.CreateCodeComment(ctx,
ctx.Doer, ctx.Repo.GitRepo, parent.Issue,
parent.Line, opts.Body, parent.TreePath,
false, parent.ReviewID,
"", nil,
)
if err != nil {
ctx.APIErrorInternal(err)
return
}
if err := comment.LoadPoster(ctx); err != nil {
ctx.APIErrorInternal(err)
return
}
comment.Issue = parent.Issue
ctx.JSON(http.StatusCreated, convert.ToPullReviewComment(ctx, comment, ctx.Doer))
}
// ResolvePullReviewComment resolves a review comment in a pull request
func ResolvePullReviewComment(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/pulls/comments/{id}/resolve repository repoResolvePullReviewComment

View File

@@ -168,6 +168,9 @@ type swaggerParameterBodies struct {
// in:body
CreatePullReviewComment api.CreatePullReviewComment
// in:body
CreatePullReviewCommentReplyOptions api.CreatePullReviewCommentReplyOptions
// in:body
SubmitPullReviewOptions api.SubmitPullReviewOptions