PR #112 added a commitID string parameter to gitea.Client.PostReview and updated cmd/review-bot/main.go to pass evaluatedSHA directly to the client. However, gitea.Adapter.PostReview (the vcs.Client implementation) was not updated — it still calls a.client.PostReview with the old 7-argument signature, omitting the new commitID parameter. Since the review-bot is designed to operate through the vcs.Client abstraction, the commit anchoring added by this PR is silently dropped whenever a caller uses the adapter interface.
But vcs.ReviewRequest has no CommitID field (see related issue), so the adapter has no way to thread it through without the ReviewRequest fix.
Source
PR: #112 — feat(gitea): pass commit_id explicitly in PostReview (#107)
Linked issue: #107 — PostReview: pass CommitID explicitly via ReviewRequest
Code quality rule: Acceptance criterion not met — fix must propagate through the abstraction layer
File: gitea/adapter.go line 181
What needs to happen
Add CommitID string field to vcs.ReviewRequest (see related issue)
Update gitea.Adapter.PostReview to pass req.CommitID to a.client.PostReview
Update github.Client.PostReview to use req.CommitID as the primary commit anchor, falling back to comment-derived CommitID if empty (as originally specified in issue #107)
All callers that currently use the low-level gitea.Client.PostReview directly should migrate to the adapter
## What was missed
PR #112 added a `commitID string` parameter to `gitea.Client.PostReview` and updated `cmd/review-bot/main.go` to pass `evaluatedSHA` directly to the client. However, `gitea.Adapter.PostReview` (the `vcs.Client` implementation) was **not updated** — it still calls `a.client.PostReview` with the old 7-argument signature, omitting the new `commitID` parameter. Since the review-bot is designed to operate through the `vcs.Client` abstraction, the commit anchoring added by this PR is silently dropped whenever a caller uses the adapter interface.
In `gitea/adapter.go`, line 181:
```go
review, err := a.client.PostReview(ctx, owner, repo, number, event, req.Body, giteaComments)
```
Should be:
```go
review, err := a.client.PostReview(ctx, owner, repo, number, event, req.Body, req.CommitID, giteaComments)
```
But `vcs.ReviewRequest` has no `CommitID` field (see related issue), so the adapter has no way to thread it through without the `ReviewRequest` fix.
## Source
- PR: #112 — feat(gitea): pass commit_id explicitly in PostReview (#107)
- Linked issue: #107 — PostReview: pass CommitID explicitly via ReviewRequest
- Code quality rule: Acceptance criterion not met — fix must propagate through the abstraction layer
- File: `gitea/adapter.go` line 181
## What needs to happen
1. Add `CommitID string` field to `vcs.ReviewRequest` (see related issue)
2. Update `gitea.Adapter.PostReview` to pass `req.CommitID` to `a.client.PostReview`
3. Update `github.Client.PostReview` to use `req.CommitID` as the primary commit anchor, falling back to comment-derived CommitID if empty (as originally specified in issue #107)
4. All callers that currently use the low-level `gitea.Client.PostReview` directly should migrate to the adapter
## References
- [PR #112](https://gitea.weiker.me/rodin/review-bot/pulls/112)
- [Issue #107](https://gitea.weiker.me/rodin/review-bot/issues/107)
Plan: Thread CommitID through the VCS abstraction layer
Problem
PR #112 added commitID support to gitea.Client.PostReview at the transport level but never connected it to the vcs.Client abstraction. The vcs.ReviewRequest struct has no CommitID field, so gitea.Adapter.PostReview cannot thread a commit anchor through to the underlying Gitea API. Callers using the vcs.Client interface (the intended path) silently lose commit anchoring.
The GitHub client extracts CommitID from individual ReviewComment.CommitID fields, but there's no top-level request-scoped CommitID — meaning body-only reviews (no inline comments) can't be anchored either.
Constraints
Must not break the existing vcs.Client interface contract for the GitHub adapter
gitea.Client.PostReview currently takes positional parameters — adding commitID as a new positional param changes the signature for all callers
The Gitea API accepts commit_id as a top-level field in the CreatePullReview request body
GitHub API accepts commit_id as a top-level field in the review creation payload
Both cmd/review-bot/main.go (uses vcs.Client interface) and gitea/adapter.go must work correctly after the change
4. Update github.Client.PostReview to prefer req.CommitID
The GitHub client should use req.CommitID as the primary commit anchor. If empty, fall back to extracting from the first comment's CommitID (existing behavior). This matches the issue's specification.
5. Update cmd/review-bot/main.go to set ReviewRequest.CommitID
gitea/adapter_test.go: Verify that commit_id appears in the API payload when ReviewRequest.CommitID is set
gitea/client_test.go: Verify the new parameter is serialized correctly
github/review_test.go: Verify req.CommitID takes priority over comment-level CommitID
Error Cases
Empty CommitID: Omitted from JSON payload via omitempty — API falls back to default behavior (Gitea pins to PR head)
Invalid CommitID: API returns an error — bubbles up as-is through the adapter (no special handling needed)
Conflicting CommitID: For GitHub, req.CommitID takes priority. If req.CommitID is empty and comments disagree, existing ErrConflictingCommitIDs logic applies (in github/review.go)
Edge Cases
Reviews with no inline comments but with CommitID — must still anchor correctly
Reviews where req.CommitID differs from ReviewComment.CommitID — req-level wins (it's the intended anchor)
Backward compatibility: existing code that doesn't set CommitID continues to work (zero-value string → omitempty → not sent)
Testing Strategy
Unit tests for gitea.Client.PostReview verifying commit_id in payload
Unit tests for gitea.Adapter.PostReview verifying end-to-end threading
Unit tests for github.Client.PostReview verifying req-level priority
Integration test verification that existing cmd/review-bot/main.go flow works
Open Questions
The github/review.go file has duplicate type declarations with github/reviews.go (both define reviewResponse, dismissReviewRequest). This appears to be an existing issue — I will NOT attempt to fix it in this PR as it's out of scope. However, it may cause compilation errors that I'll need to investigate.
Should ReviewComment.CommitID be deprecated now that we have request-level CommitID? I think no — per-comment CommitID is still useful for the GitHub adapter's fallback behavior and for mixed-commit scenarios. But the adapter comment in gitea/adapter.go (line 170-172) that says "intentionally not forwarded" should be updated to reference the request-level field.
Completion Checklist
vcs.ReviewRequest has CommitID string field with correct JSON tag
gitea.Client.PostReview includes commit_id in API payload when non-empty
gitea.Adapter.PostReview passes req.CommitID to underlying client
github.Client.PostReview uses req.CommitID as primary, comments as fallback
cmd/review-bot/main.go sets CommitID: pr.Head.SHA on the ReviewRequest
All existing tests pass
New tests cover the commit anchoring path
Code compiles cleanly
## Plan: Thread CommitID through the VCS abstraction layer
## Problem
PR #112 added `commitID` support to `gitea.Client.PostReview` at the transport level but never connected it to the `vcs.Client` abstraction. The `vcs.ReviewRequest` struct has no `CommitID` field, so `gitea.Adapter.PostReview` cannot thread a commit anchor through to the underlying Gitea API. Callers using the `vcs.Client` interface (the intended path) silently lose commit anchoring.
The GitHub client extracts CommitID from individual `ReviewComment.CommitID` fields, but there's no top-level request-scoped CommitID — meaning body-only reviews (no inline comments) can't be anchored either.
## Constraints
- Must not break the existing `vcs.Client` interface contract for the GitHub adapter
- `gitea.Client.PostReview` currently takes positional parameters — adding `commitID` as a new positional param changes the signature for all callers
- The Gitea API accepts `commit_id` as a top-level field in the CreatePullReview request body
- GitHub API accepts `commit_id` as a top-level field in the review creation payload
- Both `cmd/review-bot/main.go` (uses `vcs.Client` interface) and `gitea/adapter.go` must work correctly after the change
## Proposed Approach
### 1. Add `CommitID` field to `vcs.ReviewRequest`
```go
type ReviewRequest struct {
Body string `json:"body"`
Event ReviewEvent `json:"event"`
CommitID string `json:"commit_id,omitempty"`
Comments []ReviewComment `json:"comments,omitempty"`
}
```
This is the canonical way to pass a commit anchor through the abstraction layer.
### 2. Update `gitea.Client.PostReview` to accept and send `commitID`
Add `commitID string` parameter to the function signature. Include `commit_id` in the JSON payload sent to the Gitea API:
```go
func (c *Client) PostReview(ctx context.Context, owner, repo string, number int, event, body, commitID string, comments []ReviewComment) (*Review, error)
```
Payload struct gains: `CommitID string \x60json:"commit_id,omitempty"\x60`
### 3. Update `gitea.Adapter.PostReview` to pass `req.CommitID`
```go
review, err := a.client.PostReview(ctx, owner, repo, number, event, req.Body, req.CommitID, giteaComments)
```
### 4. Update `github.Client.PostReview` to prefer `req.CommitID`
The GitHub client should use `req.CommitID` as the primary commit anchor. If empty, fall back to extracting from the first comment's `CommitID` (existing behavior). This matches the issue's specification.
### 5. Update `cmd/review-bot/main.go` to set `ReviewRequest.CommitID`
```go
reviewReq := vcs.ReviewRequest{
Body: reviewBody,
Event: event,
CommitID: pr.Head.SHA,
Comments: inlineComments,
}
```
### 6. Update tests
- `gitea/adapter_test.go`: Verify that `commit_id` appears in the API payload when `ReviewRequest.CommitID` is set
- `gitea/client_test.go`: Verify the new parameter is serialized correctly
- `github/review_test.go`: Verify `req.CommitID` takes priority over comment-level CommitID
## Error Cases
- **Empty CommitID**: Omitted from JSON payload via `omitempty` — API falls back to default behavior (Gitea pins to PR head)
- **Invalid CommitID**: API returns an error — bubbles up as-is through the adapter (no special handling needed)
- **Conflicting CommitID**: For GitHub, `req.CommitID` takes priority. If `req.CommitID` is empty and comments disagree, existing `ErrConflictingCommitIDs` logic applies (in `github/review.go`)
## Edge Cases
- Reviews with no inline comments but with CommitID — must still anchor correctly
- Reviews where `req.CommitID` differs from `ReviewComment.CommitID` — req-level wins (it's the intended anchor)
- Backward compatibility: existing code that doesn't set `CommitID` continues to work (zero-value string → omitempty → not sent)
## Testing Strategy
- Unit tests for `gitea.Client.PostReview` verifying `commit_id` in payload
- Unit tests for `gitea.Adapter.PostReview` verifying end-to-end threading
- Unit tests for `github.Client.PostReview` verifying req-level priority
- Integration test verification that existing `cmd/review-bot/main.go` flow works
## Open Questions
- The `github/review.go` file has duplicate type declarations with `github/reviews.go` (both define `reviewResponse`, `dismissReviewRequest`). This appears to be an existing issue — I will NOT attempt to fix it in this PR as it's out of scope. However, it may cause compilation errors that I'll need to investigate.
- Should `ReviewComment.CommitID` be deprecated now that we have request-level `CommitID`? I think no — per-comment CommitID is still useful for the GitHub adapter's fallback behavior and for mixed-commit scenarios. But the adapter comment in `gitea/adapter.go` (line 170-172) that says "intentionally not forwarded" should be updated to reference the request-level field.
## Completion Checklist
1. `vcs.ReviewRequest` has `CommitID string` field with correct JSON tag
2. `gitea.Client.PostReview` includes `commit_id` in API payload when non-empty
3. `gitea.Adapter.PostReview` passes `req.CommitID` to underlying client
4. `github.Client.PostReview` uses `req.CommitID` as primary, comments as fallback
5. `cmd/review-bot/main.go` sets `CommitID: pr.Head.SHA` on the ReviewRequest
6. All existing tests pass
7. New tests cover the commit anchoring path
8. Code compiles cleanly
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What was missed
PR #112 added a
commitID stringparameter togitea.Client.PostReviewand updatedcmd/review-bot/main.goto passevaluatedSHAdirectly to the client. However,gitea.Adapter.PostReview(thevcs.Clientimplementation) was not updated — it still callsa.client.PostReviewwith the old 7-argument signature, omitting the newcommitIDparameter. Since the review-bot is designed to operate through thevcs.Clientabstraction, the commit anchoring added by this PR is silently dropped whenever a caller uses the adapter interface.In
gitea/adapter.go, line 181:Should be:
But
vcs.ReviewRequesthas noCommitIDfield (see related issue), so the adapter has no way to thread it through without theReviewRequestfix.Source
gitea/adapter.goline 181What needs to happen
CommitID stringfield tovcs.ReviewRequest(see related issue)gitea.Adapter.PostReviewto passreq.CommitIDtoa.client.PostReviewgithub.Client.PostReviewto usereq.CommitIDas the primary commit anchor, falling back to comment-derived CommitID if empty (as originally specified in issue #107)gitea.Client.PostReviewdirectly should migrate to the adapterReferences
Plan: Thread CommitID through the VCS abstraction layer
Problem
PR #112 added
commitIDsupport togitea.Client.PostReviewat the transport level but never connected it to thevcs.Clientabstraction. Thevcs.ReviewRequeststruct has noCommitIDfield, sogitea.Adapter.PostReviewcannot thread a commit anchor through to the underlying Gitea API. Callers using thevcs.Clientinterface (the intended path) silently lose commit anchoring.The GitHub client extracts CommitID from individual
ReviewComment.CommitIDfields, but there's no top-level request-scoped CommitID — meaning body-only reviews (no inline comments) can't be anchored either.Constraints
vcs.Clientinterface contract for the GitHub adaptergitea.Client.PostReviewcurrently takes positional parameters — addingcommitIDas a new positional param changes the signature for all callerscommit_idas a top-level field in the CreatePullReview request bodycommit_idas a top-level field in the review creation payloadcmd/review-bot/main.go(usesvcs.Clientinterface) andgitea/adapter.gomust work correctly after the changeProposed Approach
1. Add
CommitIDfield tovcs.ReviewRequestThis is the canonical way to pass a commit anchor through the abstraction layer.
2. Update
gitea.Client.PostReviewto accept and sendcommitIDAdd
commitID stringparameter to the function signature. Includecommit_idin the JSON payload sent to the Gitea API:Payload struct gains:
CommitID string \x60json:"commit_id,omitempty"\x603. Update
gitea.Adapter.PostReviewto passreq.CommitID4. Update
github.Client.PostReviewto preferreq.CommitIDThe GitHub client should use
req.CommitIDas the primary commit anchor. If empty, fall back to extracting from the first comment'sCommitID(existing behavior). This matches the issue's specification.5. Update
cmd/review-bot/main.goto setReviewRequest.CommitID6. Update tests
gitea/adapter_test.go: Verify thatcommit_idappears in the API payload whenReviewRequest.CommitIDis setgitea/client_test.go: Verify the new parameter is serialized correctlygithub/review_test.go: Verifyreq.CommitIDtakes priority over comment-level CommitIDError Cases
omitempty— API falls back to default behavior (Gitea pins to PR head)req.CommitIDtakes priority. Ifreq.CommitIDis empty and comments disagree, existingErrConflictingCommitIDslogic applies (ingithub/review.go)Edge Cases
req.CommitIDdiffers fromReviewComment.CommitID— req-level wins (it's the intended anchor)CommitIDcontinues to work (zero-value string → omitempty → not sent)Testing Strategy
gitea.Client.PostReviewverifyingcommit_idin payloadgitea.Adapter.PostReviewverifying end-to-end threadinggithub.Client.PostReviewverifying req-level prioritycmd/review-bot/main.goflow worksOpen Questions
github/review.gofile has duplicate type declarations withgithub/reviews.go(both definereviewResponse,dismissReviewRequest). This appears to be an existing issue — I will NOT attempt to fix it in this PR as it's out of scope. However, it may cause compilation errors that I'll need to investigate.ReviewComment.CommitIDbe deprecated now that we have request-levelCommitID? I think no — per-comment CommitID is still useful for the GitHub adapter's fallback behavior and for mixed-commit scenarios. But the adapter comment ingitea/adapter.go(line 170-172) that says "intentionally not forwarded" should be updated to reference the request-level field.Completion Checklist
vcs.ReviewRequesthasCommitID stringfield with correct JSON taggitea.Client.PostReviewincludescommit_idin API payload when non-emptygitea.Adapter.PostReviewpassesreq.CommitIDto underlying clientgithub.Client.PostReviewusesreq.CommitIDas primary, comments as fallbackcmd/review-bot/main.gosetsCommitID: pr.Head.SHAon the ReviewRequest