feat(vcs): add CommitID to ReviewRequest (#115) #118

Merged
aweiker merged 5 commits from review-bot-issue-115 into feature/github-support 2026-05-14 01:49:33 +00:00
4 changed files with 44 additions and 4 deletions
+2 -2
View File
@@ -439,7 +439,7 @@ func main() {
inlineComments = append(inlineComments, vcs.ReviewComment{
Path: f.File,
Position: pos,
CommitID: pr.Head.SHA,
CommitID: evaluatedSHA,
Body: fmt.Sprintf("**[%s]** %s", f.Severity, f.Finding),
})
}
@@ -485,7 +485,7 @@ func main() {
reviewReq := vcs.ReviewRequest{
Body: reviewBody,
Event: event,
CommitID: pr.Head.SHA,
CommitID: evaluatedSHA,
Review

[NIT] Inline comments are built with CommitID set from pr.Head.SHA earlier, while the review-level CommitID now uses evaluatedSHA. For consistency, consider using evaluatedSHA for inline comment CommitID as well. Functionally this is fine due to the stale-head check, but aligning both to evaluatedSHA reduces any chance of mismatch if refetch fails.

**[NIT]** Inline comments are built with CommitID set from pr.Head.SHA earlier, while the review-level CommitID now uses evaluatedSHA. For consistency, consider using evaluatedSHA for inline comment CommitID as well. Functionally this is fine due to the stale-head check, but aligning both to evaluatedSHA reduces any chance of mismatch if refetch fails.
Comments: inlineComments,
}
posted, err := client.PostReview(ctx, owner, repoName, prNumber, reviewReq)
+1 -1
View File
3
@@ -409,7 +409,7 @@ func TestAdapter_RequestReviewerSelf(t *testing.T) {
}
}
func TestAdapter_PostReview_CommitID_Threading(t *testing.T) {
func TestAdapter_PostReview_CommitID(t *testing.T) {
var gotPayload struct {
Body string `json:"body"`
Event string `json:"event"`
+40
View File
@@ -147,6 +147,46 @@ func TestPostReview(t *testing.T) {
}
Review

[NIT] TestPostReview_CommitID uses io.ReadAll(r.Body) then json.Unmarshal, while the existing TestPostReview uses json.NewDecoder(r.Body).Decode. Inconsistent style within the same file, though not a correctness issue. Consider using the decoder pattern to match the surrounding tests.

**[NIT]** TestPostReview_CommitID uses `io.ReadAll(r.Body)` then `json.Unmarshal`, while the existing TestPostReview uses `json.NewDecoder(r.Body).Decode`. Inconsistent style within the same file, though not a correctness issue. Consider using the decoder pattern to match the surrounding tests.
}
func TestPostReview_CommitID(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
t.Fatalf("expected POST, got %s", r.Method)
}
body, _ := io.ReadAll(r.Body)
var payload struct {
Body string `json:"body"`
Event string `json:"event"`
CommitID string `json:"commit_id"`
}
if err := json.Unmarshal(body, &payload); err != nil {
t.Fatalf("unmarshal payload: %v", err)
}
if payload.CommitID != "deadbeef123" {
t.Errorf("expected commit_id %q, got %q", "deadbeef123", payload.CommitID)
}
if payload.Event != "APPROVED" {
t.Errorf("expected event APPROVED, got %q", payload.Event)
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"id":101,"user":{"login":"review-bot"},"state":"APPROVED","stale":false,"commit_id":"deadbeef123"}`))
}))
defer server.Close()
client := NewClient(server.URL, "test-token")
review, err := client.PostReview(context.Background(), "owner", "repo", 3, "APPROVED", "LGTM", "deadbeef123", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if review.ID != 101 {
t.Errorf("expected review ID 101, got %d", review.ID)
}
if review.CommitID != "deadbeef123" {
t.Errorf("expected commit_id %q, got %q", "deadbeef123", review.CommitID)
}
}
func TestGetPullRequest_Non200(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
+1 -1
View File
@@ -103,7 +103,7 @@ func (c *Client) PostReview(ctx context.Context, owner, repo string, number int,
// the resolved commit_id.
for _, comment := range req.Comments {
if comment.CommitID != "" {
Outdated
Review

[NIT] The conflict detection logic between req.CommitID and per-comment CommitIDs works correctly but uses a subtle implicit assumption: the initial payload.CommitID = req.CommitID means the loop's payload.CommitID == "" check is only true when req.CommitID was also empty. This is correct but slightly hard to follow at a glance — a brief inline comment like // req.CommitID already applied above on the empty-check branch would improve readability.

**[NIT]** The conflict detection logic between `req.CommitID` and per-comment CommitIDs works correctly but uses a subtle implicit assumption: the initial `payload.CommitID = req.CommitID` means the loop's `payload.CommitID == ""` check is only true when `req.CommitID` was also empty. This is correct but slightly hard to follow at a glance — a brief inline comment like `// req.CommitID already applied above` on the empty-check branch would improve readability.
if payload.CommitID == "" {
if payload.CommitID == "" { // only reachable when req.CommitID is empty
payload.CommitID = comment.CommitID
} else if payload.CommitID != comment.CommitID {
return nil, ErrConflictingCommitIDs