feat(github): Reviewer + Identity client (Phase 4) #81
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Architecture Reference
Base branch:
feature/github-support— open all PRs against this branch.Goal
Complete the GitHub client by implementing
ReviewerandIdentity, makinggithub.Clienta fullvcs.Client.Background
The GitHub client struct and HTTP helpers were created in issue #80. This issue adds the remaining interface methods.
The
vcs.Clientinterface and all types live invcs/(created in issue #78). The canonicalReviewRequest.Eventvalues are GitHub's strings:"APPROVE","REQUEST_CHANGES","COMMENT"— no translation needed for the GitHub client (it sends them directly to the API).GitHub uses diff-position natively —
ReviewComment.Positionmaps directly to thepositionfield in the POST body. No translation needed.ReviewComment.CommitIDmust be the PR head SHA. Callers are responsible for populating it (see issue #82).Design note: DismissReview vs DeleteReview
GitHub does not allow deleting a submitted review (APPROVED, REQUEST_CHANGES, COMMENT) — only PENDING reviews can be deleted. Attempting to delete a submitted review returns 422.
review-bot replaces old reviews when reposting. The correct cross-platform primitive is
DismissReview:PUT /repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}/dismissalsDeleteReview(Gitea allows full deletion)DeleteReviewstays on the interface for PENDING-only cleanup. Callers that need to replace a submitted review must useDismissReview.Work
github/review.goPostReview—POST /repos/{owner}/{repo}/pulls/{number}/reviews{ "commit_id": "...", "body": "...", "event": "APPROVE|REQUEST_CHANGES|COMMENT", "comments": [{"path", "position", "body"}] }eventvalues are passed directly — they match GitHub's canonical valuesListReviews—GET /repos/{owner}/{repo}/pulls/{number}/reviews. Map each review tovcs.Review. CanonicalStatevalues — GitHub returns native strings that differ from the canonical vcs values; translate in the adapter:statevcs.Review.State(canonical)"APPROVED""APPROVED""CHANGES_REQUESTED""REQUEST_CHANGES""COMMENTED""COMMENT""DISMISSED""DISMISSED"The Gitea adapter must also translate to these same canonical values. Both adapters must agree so that
main.gocan comparereview.Statewithout knowing the provider.DeleteReview—DELETE /repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}ErrCannotDeleteSubmittedReview(exported sentinel error defined ingithub/review.go). Callers inmain.godo not need to check for this specifically — the supersede flow usesDismissReview, notDeleteReview, for submitted reviews.DismissReview—PUT /repos/{owner}/{repo}/pulls/{number}/reviews/{review_id}/dismissals{"message": "<message>", "event": "DISMISS"}github/identity.goGetAuthenticatedUser—GET /user, returnsloginfieldCompile-time check
Unit tests
PostReview: happy path, 401, 422, malformed responseListReviews: happy path, 404, 401DeleteReview: happy path (PENDING), 422 →ErrCannotDeleteSubmittedReviewDismissReview: happy path, 404, 401GetAuthenticatedUser: happy path, 401Exit criteria
var _ vcs.Client = (*github.Client)(nil)compilesgo test ./github/...passes for all methodsOut of scope