feat: implement GitHub API methods for PR review #130

Closed
opened 2026-05-14 20:32:23 +00:00 by rodin · 1 comment
Owner

Problem

The github package has the HTTP transport layer (retry logic, rate limiting, redirect safety, SSRF protection) but no higher-level API methods. The TODO comment in client.go notes that baseURL is populated but not yet used.

Currently, review-bot supports Gitea PRs but cannot review GitHub PRs despite having GitHub Actions runner support via the composite action.

What to implement

Mirror the methods from gitea/client.go for the GitHub API:

  • GetPullRequest(ctx, owner, repo, number)/repos/{owner}/{repo}/pulls/{number}
  • GetPullRequestDiff(ctx, owner, repo, number)/repos/{owner}/{repo}/pulls/{number} with Accept: application/vnd.github.diff
  • GetPullRequestFiles(ctx, owner, repo, number)/repos/{owner}/{repo}/pulls/{number}/files
  • GetCommitStatuses(ctx, owner, repo, sha)/repos/{owner}/{repo}/commits/{sha}/statuses (or /check-runs)
  • GetFileContent(ctx, owner, repo, filepath)/repos/{owner}/{repo}/contents/{path}
  • GetFileContentRef(ctx, owner, repo, filepath, ref) → same with ?ref=
  • ListContents(ctx, owner, repo, path)/repos/{owner}/{repo}/contents/{path}
  • PostReview(ctx, owner, repo, number, event, body, commitID, comments)/repos/{owner}/{repo}/pulls/{number}/reviews
  • ListReviews(ctx, owner, repo, number)/repos/{owner}/{repo}/pulls/{number}/reviews
  • DeleteReview(ctx, owner, repo, number, reviewID) → DELETE /repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}
  • GetAuthenticatedUser(ctx)/user

Notes

  • The action.yml already supports GitHub runners and detects VCS_TYPE=github
  • The binary needs a way to route to either gitea.Client or github.Client based on VCS_TYPE
  • Both clients should satisfy a common VCSClient interface (defined in cmd/review-bot per Go conventions)
  • Review verdict mapping: GitHub uses APPROVE, REQUEST_CHANGES, COMMENT (same as Gitea)

Acceptance Criteria

  • All listed API methods implemented in github/client.go
  • Each method has a corresponding test using httptest.NewServer
  • TODO comment removed from client.go
  • cmd/review-bot/main.go routes to either client based on VCS_TYPE env var (or --vcs-type flag)
  • Integration test updated/extended for GitHub
  • go test ./... passes
## Problem The `github` package has the HTTP transport layer (retry logic, rate limiting, redirect safety, SSRF protection) but no higher-level API methods. The `TODO` comment in `client.go` notes that `baseURL` is populated but not yet used. Currently, review-bot supports Gitea PRs but cannot review GitHub PRs despite having GitHub Actions runner support via the composite action. ## What to implement Mirror the methods from `gitea/client.go` for the GitHub API: - `GetPullRequest(ctx, owner, repo, number)` → `/repos/{owner}/{repo}/pulls/{number}` - `GetPullRequestDiff(ctx, owner, repo, number)` → `/repos/{owner}/{repo}/pulls/{number}` with `Accept: application/vnd.github.diff` - `GetPullRequestFiles(ctx, owner, repo, number)` → `/repos/{owner}/{repo}/pulls/{number}/files` - `GetCommitStatuses(ctx, owner, repo, sha)` → `/repos/{owner}/{repo}/commits/{sha}/statuses` (or `/check-runs`) - `GetFileContent(ctx, owner, repo, filepath)` → `/repos/{owner}/{repo}/contents/{path}` - `GetFileContentRef(ctx, owner, repo, filepath, ref)` → same with `?ref=` - `ListContents(ctx, owner, repo, path)` → `/repos/{owner}/{repo}/contents/{path}` - `PostReview(ctx, owner, repo, number, event, body, commitID, comments)` → `/repos/{owner}/{repo}/pulls/{number}/reviews` - `ListReviews(ctx, owner, repo, number)` → `/repos/{owner}/{repo}/pulls/{number}/reviews` - `DeleteReview(ctx, owner, repo, number, reviewID)` → DELETE `/repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}` - `GetAuthenticatedUser(ctx)` → `/user` ## Notes - The action.yml already supports GitHub runners and detects `VCS_TYPE=github` - The binary needs a way to route to either `gitea.Client` or `github.Client` based on `VCS_TYPE` - Both clients should satisfy a common `VCSClient` interface (defined in `cmd/review-bot` per Go conventions) - Review verdict mapping: GitHub uses `APPROVE`, `REQUEST_CHANGES`, `COMMENT` (same as Gitea) ## Acceptance Criteria - [ ] All listed API methods implemented in `github/client.go` - [ ] Each method has a corresponding test using `httptest.NewServer` - [ ] `TODO` comment removed from `client.go` - [ ] `cmd/review-bot/main.go` routes to either client based on `VCS_TYPE` env var (or `--vcs-type` flag) - [ ] Integration test updated/extended for GitHub - [ ] `go test ./...` passes
rodin self-assigned this 2026-05-14 20:35:50 +00:00
Author
Owner

Plan: feat: implement GitHub API methods for PR review

Problem

The github package has the HTTP transport layer but no higher-level API methods. The review-bot supports Gitea PRs but cannot route to GitHub despite the action.yml supporting GitHub runners. This issue adds the missing API methods to github/client.go and wires them into cmd/review-bot/main.go via a VCS_TYPE flag.

Constraints

  • No new third-party dependencies (CONVENTIONS.md strict allowlist)
  • All new code must pass go test ./... and go vet ./...
  • Each method needs a test using httptest.NewServer
  • VCSClient interface defined in cmd/review-bot per Go conventions
  • GitHub uses APPROVE, REQUEST_CHANGES, COMMENT — same event names as Gitea

Proposed Approach

Phase 1: Create vcs package with shared types

New package at vcs/types.go with:

  • type ReviewEvent string with constants ReviewEventApprove, ReviewEventRequestChanges, ReviewEventComment
  • type ReviewComment struct { Path, Body string; Position int; CommitID string }
  • type Review struct { ID int64; Body, State, CommitID string; User UserInfo }
  • type UserInfo struct { Login string }
  • type ReviewRequest struct { Body string; Event ReviewEvent; Comments []ReviewComment }

This package is imported by the github package review methods.

Phase 2: Add doRequestWithBody to github/client.go

New helper method that handles POST/PUT/DELETE with a JSON body. No retry (non-idempotent). Sets Content-Type: application/json. Respects HTTP/SSRF security (blocks HTTP unless AllowInsecureHTTP set).

Phase 3: Add local types to github/client.go

  • type PullRequest struct (Title, Body, Head.Sha, Head.Ref)
  • type CommitStatus struct (Status, Context, Description, TargetURL)
  • type ChangedFile struct (Filename, Status)
  • type ContentEntry struct (Name, Path, Type)
  • Plus max diff size constant + ErrDiffTooLarge error

Phase 4: Add API methods to github/client.go

  • GetPullRequestGET /repos/{owner}/{repo}/pulls/{number}
  • GetPullRequestDiff → same URL with Accept: application/vnd.github.diff
  • GetPullRequestFilesGET /repos/{owner}/{repo}/pulls/{number}/files
  • GetCommitStatusesGET /repos/{owner}/{repo}/commits/{sha}/statuses
  • GetFileContentGET /repos/{owner}/{repo}/contents/{path} (base64 decode response)
  • GetFileContentRef → same with ?ref= param
  • ListContentsGET /repos/{owner}/{repo}/contents/{path} (returns array)
  • Remove TODO comment

Phase 5: Add review.go and identity.go to github package

  • review.go: PostReview, ListReviews, DeleteReview, DismissReview using vcs types
  • identity.go: GetAuthenticatedUser

Phase 6: Update cmd/review-bot/main.go

Add --vcs-type flag (values: gitea, github; default: gitea for backward compat).
Define VCSClient interface in cmd/review-bot/ using local adapter types.
Extend giteaClientAdapter and add githubClientAdapter to satisfy the interface.
Route based on VCS_TYPE env var or --vcs-type flag.

Open Questions

  1. GetCommitStatuses uses GitHub's legacy /statuses endpoint. If github.concur.com uses only check-runs, a separate GetCheckRuns method will be needed. Starting with statuses for now (matches issue spec).
  2. ListContents: GitHub returns an object (not array) when path is a file. Will handle both shapes.
  3. Integration test: adding a note that the integration test can be run against GitHub by setting VCS_TYPE=github.

Acceptance Criteria

  • All listed API methods implemented in github/client.go
  • Each method has a corresponding test using httptest.NewServer
  • TODO comment removed from client.go
  • cmd/review-bot/main.go routes to either client based on VCS_TYPE env var / --vcs-type flag
  • Integration test updated/extended for GitHub
  • go test ./... passes
## Plan: feat: implement GitHub API methods for PR review ## Problem The `github` package has the HTTP transport layer but no higher-level API methods. The review-bot supports Gitea PRs but cannot route to GitHub despite the action.yml supporting GitHub runners. This issue adds the missing API methods to `github/client.go` and wires them into `cmd/review-bot/main.go` via a `VCS_TYPE` flag. ## Constraints - No new third-party dependencies (CONVENTIONS.md strict allowlist) - All new code must pass `go test ./...` and `go vet ./...` - Each method needs a test using `httptest.NewServer` - VCSClient interface defined in `cmd/review-bot` per Go conventions - GitHub uses `APPROVE`, `REQUEST_CHANGES`, `COMMENT` — same event names as Gitea ## Proposed Approach ### Phase 1: Create `vcs` package with shared types New package at `vcs/types.go` with: - `type ReviewEvent string` with constants `ReviewEventApprove`, `ReviewEventRequestChanges`, `ReviewEventComment` - `type ReviewComment struct { Path, Body string; Position int; CommitID string }` - `type Review struct { ID int64; Body, State, CommitID string; User UserInfo }` - `type UserInfo struct { Login string }` - `type ReviewRequest struct { Body string; Event ReviewEvent; Comments []ReviewComment }` This package is imported by the `github` package review methods. ### Phase 2: Add `doRequestWithBody` to `github/client.go` New helper method that handles POST/PUT/DELETE with a JSON body. No retry (non-idempotent). Sets `Content-Type: application/json`. Respects HTTP/SSRF security (blocks HTTP unless AllowInsecureHTTP set). ### Phase 3: Add local types to `github/client.go` - `type PullRequest struct` (Title, Body, Head.Sha, Head.Ref) - `type CommitStatus struct` (Status, Context, Description, TargetURL) - `type ChangedFile struct` (Filename, Status) - `type ContentEntry struct` (Name, Path, Type) - Plus max diff size constant + `ErrDiffTooLarge` error ### Phase 4: Add API methods to `github/client.go` - `GetPullRequest` → `GET /repos/{owner}/{repo}/pulls/{number}` - `GetPullRequestDiff` → same URL with `Accept: application/vnd.github.diff` - `GetPullRequestFiles` → `GET /repos/{owner}/{repo}/pulls/{number}/files` - `GetCommitStatuses` → `GET /repos/{owner}/{repo}/commits/{sha}/statuses` - `GetFileContent` → `GET /repos/{owner}/{repo}/contents/{path}` (base64 decode response) - `GetFileContentRef` → same with `?ref=` param - `ListContents` → `GET /repos/{owner}/{repo}/contents/{path}` (returns array) - Remove `TODO` comment ### Phase 5: Add `review.go` and `identity.go` to `github` package - `review.go`: `PostReview`, `ListReviews`, `DeleteReview`, `DismissReview` using `vcs` types - `identity.go`: `GetAuthenticatedUser` ### Phase 6: Update `cmd/review-bot/main.go` Add `--vcs-type` flag (values: `gitea`, `github`; default: `gitea` for backward compat). Define `VCSClient` interface in `cmd/review-bot/` using local adapter types. Extend `giteaClientAdapter` and add `githubClientAdapter` to satisfy the interface. Route based on `VCS_TYPE` env var or `--vcs-type` flag. ## Open Questions 1. `GetCommitStatuses` uses GitHub's legacy `/statuses` endpoint. If `github.concur.com` uses only check-runs, a separate `GetCheckRuns` method will be needed. Starting with statuses for now (matches issue spec). 2. `ListContents`: GitHub returns an object (not array) when path is a file. Will handle both shapes. 3. Integration test: adding a note that the integration test can be run against GitHub by setting `VCS_TYPE=github`. ## Acceptance Criteria - [ ] All listed API methods implemented in `github/client.go` - [ ] Each method has a corresponding test using `httptest.NewServer` - [ ] `TODO` comment removed from `client.go` - [ ] `cmd/review-bot/main.go` routes to either client based on `VCS_TYPE` env var / `--vcs-type` flag - [ ] Integration test updated/extended for GitHub - [ ] `go test ./...` passes
rodin closed this issue 2026-05-14 22:06:21 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rodin/review-bot#130