Skip to content

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

Merged
silverwind merged 15 commits intogo-gitea:mainfrom
silverwind:reply
Apr 27, 2026
Merged

Add API endpoint to reply to pull request review comments#36683
silverwind merged 15 commits intogo-gitea:mainfrom
silverwind:reply

Conversation

@silverwind
Copy link
Copy Markdown
Member

@silverwind silverwind commented Feb 20, 2026

Adds a dedicated endpoint for replying to pull request review comments, matching GitHub's API exactly:

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

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

Needed for https://gitea.com/gitea/gitea-mcp/issues/129
Fixes: #37419


This PR was written with the help of Claude Opus 4.7

@GiteaBot GiteaBot added the lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. label Feb 20, 2026
@silverwind silverwind changed the title Add in_reply_to field to CreatePullReviewComment API Add in_reply_to_id field to CreatePullReviewComment API Feb 20, 2026
@silverwind silverwind changed the title Add in_reply_to_id field to CreatePullReviewComment API Add API to reply to pull request review comments Feb 20, 2026
Add `in_reply_to` field to `CreatePullReviewComment` that accepts a
comment ID, consistent with GitHub's API. The handler resolves the
comment ID to the internal review ID and creates the reply as a
non-pending comment so it threads correctly under the original review.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds API support for replying to pull request review comments via the in_reply_to_id parameter, matching the GitHub API design. When a reply-only request is made (all comments have InReplyToID set and no pending review exists), the API returns the review to which the comments were added rather than creating a new review.

Changes:

  • Added InReplyToID field to CreatePullReviewComment struct for specifying which review comment to reply to
  • Implemented resolveInReplyTo helper function to validate and resolve reply comment IDs to their parent review IDs
  • Modified CreatePullReview to handle reply comments by passing the resolved review ID to CreateCodeComment and falling back to the parent review when no new pending review is created
  • Added integration test validating that replies are correctly threaded under the original review

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
modules/structs/pull_review.go Added InReplyToID field to CreatePullReviewComment struct with documentation
templates/swagger/v1_json.tmpl Added OpenAPI specification for the in_reply_to_id parameter
routers/api/v1/repo/pull_review.go Implemented resolveInReplyTo validation function and integrated reply logic into CreatePullReview handler
tests/integration/api_pull_review_test.go Added TestAPIPullReviewCommentReply test case verifying reply functionality

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread routers/api/v1/repo/pull_review.go Outdated
Comment thread tests/integration/api_pull_review_test.go
Comment thread routers/api/v1/repo/pull_review.go Outdated
Comment thread routers/api/v1/repo/pull_review.go Outdated
@wxiaoguang
Copy link
Copy Markdown
Contributor

AI code breaks the Gitea's "route handler" patterns.

It should either let the sub-function fully handle the error and make the caller check ctx.Written(), or the caller fully handle the error but not swallow it.

And it's not proper to do err := issues_model.ErrCommentNotExist{ID: commentID}; ctx.APIErrorNotFound("GetCommentByID", err). Take a look at how "APIErrorNotFound" works.

silverwind and others added 2 commits March 15, 2026 12:21
- Follow Gitea route handler pattern: resolveInReplyTo writes to ctx,
  caller checks ctx.Written()
- Fix improper APIErrorNotFound usage (don't pass internal func names)
- Move zero-check to call site so resolveInReplyTo always gets valid ID
- Validate all reply comments target the same review (reject with 422)
- Add test for cross-review reply rejection

Co-Authored-By: Claude (Opus 4.6) <noreply@anthropic.com>
@silverwind
Copy link
Copy Markdown
Member Author

silverwind commented Mar 15, 2026

AI code breaks the Gitea's "route handler" patterns.

It should either let the sub-function fully handle the error and make the caller check ctx.Written(), or the caller fully handle the error but not swallow it.

And it's not proper to do err := issues_model.ErrCommentNotExist{ID: commentID}; ctx.APIErrorNotFound("GetCommentByID", err). Take a look at how "APIErrorNotFound" works.

Written by Claude.

Done in 2c980f5:

  • resolveInReplyTo now follows Gitea route handler pattern: writes to ctx on error, caller checks ctx.Written()
  • Removed improper APIErrorNotFound("GetCommentByID", err) — now uses bare ctx.APIErrorNotFound()
  • Removed the fabricated ErrCommentNotExist{ID: commentID} construction

@silverwind silverwind marked this pull request as ready for review March 15, 2026 12:19
@wxiaoguang
Copy link
Copy Markdown
Contributor

Can you ask your AI why it keeps generating slops like errors.New()?

@wxiaoguang wxiaoguang marked this pull request as draft March 15, 2026 12:31
Copy link
Copy Markdown
Contributor

@wxiaoguang wxiaoguang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such logic can't be right.

You should never use error return for a succeeded operation across modules.

image

@GiteaBot GiteaBot added lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Mar 15, 2026
@bircni
Copy link
Copy Markdown
Member

bircni commented Apr 5, 2026

@silverwind updates?

silverwind and others added 3 commits April 19, 2026 19:37
- Detect reply-only requests up front and skip SubmitReview for them,
  instead of catching ContentEmptyErr as a success signal. wxiaoguang:
  "never use error return for a succeeded operation across modules".
- Pass API error messages as plain strings to ctx.APIError rather than
  wrapping in errors.New.
- Resolve all in_reply_to IDs before creating any comments.

Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
- Inline the single-use resolveInReplyTo helper into the validation loop.
- Break the isReplyOnly condition into named booleans for readability.

Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
@silverwind silverwind marked this pull request as ready for review April 19, 2026 18:35
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread routers/api/v1/repo/pull_review.go Outdated
Comment thread routers/api/v1/repo/pull_review.go Outdated
Use the existing helper for repo-scoped lookup + IsPull/code-comment
validation. Drop the separate GetPullRequestByIndex + LoadIssue +
IssueID-equality dance; verify the URL's pull index against the
parent comment's loaded issue instead. Switch the "not a review
comment" branch from 422 to 400 to match the resolve/unresolve
endpoints.

Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
@silverwind silverwind marked this pull request as ready for review April 25, 2026 18:57
@silverwind silverwind requested a review from wxiaoguang April 25, 2026 18:58
Comment thread routers/api/v1/repo/pull_review.go
@wxiaoguang wxiaoguang dismissed their stale review April 26, 2026 10:48

dismiss change request

@GiteaBot GiteaBot added lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. and removed lgtm/blocked A maintainer has reservations with the PR and thus it cannot be merged labels Apr 26, 2026
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@lunny lunny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GiteaBot GiteaBot added lgtm/need 1 This PR needs approval from one additional maintainer to be merged. and removed lgtm/need 2 This PR needs two approvals by maintainers to be considered for merging. labels Apr 26, 2026
@bircni
Copy link
Copy Markdown
Member

bircni commented Apr 26, 2026

@silverwind
Copy link
Copy Markdown
Member Author

#36683 (comment) explains my reasoning why GH-compatible API is better clearly imho. I wouldn't want to write a incompatible API but if people prefer we can add another endpoint that does not need index (the pr number).

@lunny
Copy link
Copy Markdown
Member

lunny commented Apr 26, 2026

LGTM except #36683 (files)

then why do you approve?

I’m fine with either solution, whether it’s backward-compatible Github or not.

@bircni
Copy link
Copy Markdown
Member

bircni commented Apr 26, 2026

LGTM except #36683 (files)

then why do you approve?

I’m fine with either solution, whether it’s backward-compatible Github or not.

I prefer the compatibility to GH

@GiteaBot GiteaBot added lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. and removed lgtm/need 1 This PR needs approval from one additional maintainer to be merged. labels Apr 26, 2026
@silverwind silverwind enabled auto-merge (squash) April 26, 2026 20:54
@silverwind silverwind added the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Apr 27, 2026
@silverwind silverwind merged commit 331450b into go-gitea:main Apr 27, 2026
26 checks passed
@silverwind silverwind deleted the reply branch April 27, 2026 08:46
@GiteaBot GiteaBot removed the reviewed/wait-merge This pull request is part of the merge queue. It will be merged soon. label Apr 27, 2026
silverwind added a commit to hanism01/gitea that referenced this pull request Apr 27, 2026
…-review-feedback

* origin/main: (144 commits)
  Add API endpoint to reply to pull request review comments (go-gitea#36683)
  Add CurrentURL template variable back (go-gitea#37444)
  refactor: use named `Permission` field in `Repository` struct instead of anonymous embedding (go-gitea#37441)
  Refactor pull request view (3) (go-gitea#37439)
  Update 1.26.1 changelog in main (go-gitea#37442)
  Make GetPossibleUserByID can handle deleted user (go-gitea#37430)
  Fix fetch action redirect (go-gitea#37437)
  Refactor integration test DecodeJSON calls to use generic return value (go-gitea#37432)
  Integrate renovate bot for all dependency updates (go-gitea#37050)
  Refactor pull request view (2) (go-gitea#37428)
  Use MarkLongPolling instead of hard-coded route path (go-gitea#37427)
  Optimize CI caches (go-gitea#37387)
  Update AGENTS.md (go-gitea#37420)
  Update Nix flake (go-gitea#37425)
  [skip ci] Updated translations via Crowdin
  remove excessive quote from terraform instructions (go-gitea#37424)
  Improve testing init, clean up webhook tests (go-gitea#37412)
  Fix color regressions, add `priority` color (go-gitea#37417)
  [skip ci] Updated translations via Crowdin
  Stabilize e2e logout propagation test (go-gitea#37403)
  ...

# Conflicts:
#	models/project/column.go
#	routers/web/repo/issue_page_meta.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lgtm/done This PR has enough approvals to get merged. There are no important open reservations anymore. topic/api Concerns mainly the API type/enhancement An improvement of existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(api): Add endpoint to reply to a comment thread

6 participants