From 2e6f46f28dbaa2a36537e4c63f95519772bb88de Mon Sep 17 00:00:00 2001 From: claw Date: Tue, 12 May 2026 10:04:57 -0700 Subject: [PATCH] feat(vcs): extract interfaces and types from gitea/ (Phase 1, #78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vcs/interfaces.go and vcs/types.go as the foundation for multi-platform VCS support. Interfaces are discovered from working gitea/client.go code, not invented in a vacuum. vcs/interfaces.go — role-based interfaces: - PRReader: GetPullRequest, GetPullRequestDiff, GetPullRequestFiles - FileReader: GetFileContent (path + ref), ListContents - Reviewer: PostReview (ReviewRequest), ListReviews, DeleteReview - Identity: GetAuthenticatedUser - Client: all four composed vcs/types.go — types extracted from gitea/: - PullRequest, ChangedFile, ContentEntry, Review (identical to gitea/) - ReviewComment: uses GitHub diff-position convention (Position int, CommitID string) instead of Gitea's NewPosition int64 - ReviewRequest: new type wrapping Body, Event, Comments vcs/check.go (//go:build ignore) — documents the gaps gitea.Client must bridge in Phase 2: 1. PostReview signature mismatch (event+body+[]ReviewComment vs ReviewRequest) 2. GetFileContent missing ref parameter 3. ReviewComment type mismatch (NewPosition vs Position/CommitID) No behavior changes. All existing tests pass. --- vcs/check.go | 30 +++++++++++++++++++++++ vcs/interfaces.go | 37 ++++++++++++++++++++++++++++ vcs/types.go | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 vcs/check.go create mode 100644 vcs/interfaces.go create mode 100644 vcs/types.go diff --git a/vcs/check.go b/vcs/check.go new file mode 100644 index 0000000..4989eac --- /dev/null +++ b/vcs/check.go @@ -0,0 +1,30 @@ +//go:build ignore + +// This file is excluded from normal builds. +// Run `go build -v .` inside this file to see the documented gaps between +// gitea.Client and vcs.Client that Phase 2 (Gitea adapter) must bridge. +// +// Known gaps (as of Phase 1): +// +// 1. PostReview signature mismatch: +// gitea.Client: PostReview(ctx, owner, repo, number, event, body string, comments []gitea.ReviewComment) +// vcs.Reviewer: PostReview(ctx, owner, repo, number, req vcs.ReviewRequest) +// +// 2. GetFileContent signature mismatch: +// gitea.Client: GetFileContent(ctx, owner, repo, filepath string) [no ref; uses default branch] +// vcs.FileReader: GetFileContent(ctx, owner, repo, path, ref string) +// (gitea.Client has GetFileContentRef for the ref variant) +// +// 3. ReviewComment type mismatch: +// gitea.ReviewComment uses NewPosition int64 (Gitea line-number convention) +// vcs.ReviewComment uses Position int (GitHub diff-position convention) +// +// The Gitea adapter (Phase 2) will wrap gitea.Client to bridge these gaps. + +package vcs + +import "gitea.weiker.me/rodin/review-bot/gitea" + +// This compile-time assertion intentionally fails. +// It documents what the Gitea adapter must implement to satisfy vcs.Client. +var _ Client = (*gitea.Client)(nil) diff --git a/vcs/interfaces.go b/vcs/interfaces.go new file mode 100644 index 0000000..62642f1 --- /dev/null +++ b/vcs/interfaces.go @@ -0,0 +1,37 @@ +package vcs + +import "context" + +// PRReader can fetch pull request metadata, diffs, and changed files. +type PRReader interface { + GetPullRequest(ctx context.Context, owner, repo string, number int) (*PullRequest, error) + GetPullRequestDiff(ctx context.Context, owner, repo string, number int) (string, error) + GetPullRequestFiles(ctx context.Context, owner, repo string, number int) ([]ChangedFile, error) +} + +// FileReader can fetch file contents and list directory entries. +type FileReader interface { + GetFileContent(ctx context.Context, owner, repo, path, ref string) (string, error) + ListContents(ctx context.Context, owner, repo, path string) ([]ContentEntry, error) +} + +// Reviewer can post, list, and delete pull request reviews. +type Reviewer interface { + PostReview(ctx context.Context, owner, repo string, number int, req ReviewRequest) (*Review, error) + ListReviews(ctx context.Context, owner, repo string, number int) ([]Review, error) + DeleteReview(ctx context.Context, owner, repo string, number int, reviewID int64) error +} + +// Identity can report who the authenticated user is. +type Identity interface { + GetAuthenticatedUser(ctx context.Context) (string, error) +} + +// Client is the full VCS interface: PR reads, file reads, review management, and identity. +// Platform adapters (gitea, github) implement this interface. +type Client interface { + PRReader + FileReader + Reviewer + Identity +} diff --git a/vcs/types.go b/vcs/types.go new file mode 100644 index 0000000..82f0ec1 --- /dev/null +++ b/vcs/types.go @@ -0,0 +1,62 @@ +// Package vcs defines the shared interface and types for VCS platform clients. +// Adapters (gitea, github) implement these interfaces; the core review logic +// uses them without knowing the underlying platform. +package vcs + +// PullRequest holds relevant PR metadata. +type PullRequest struct { + Title string `json:"title"` + Body string `json:"body"` + Head struct { + Sha string `json:"sha"` + Ref string `json:"ref"` + } `json:"head"` +} + +// ChangedFile represents a file modified in a PR. +type ChangedFile struct { + Filename string `json:"filename"` + Status string `json:"status"` +} + +// ContentEntry represents a file or directory entry from the contents API. +type ContentEntry struct { + Name string `json:"name"` + Path string `json:"path"` + Type string `json:"type"` // "file" or "dir" +} + +// Review represents a pull request review. +type Review struct { + ID int64 `json:"id"` + Body string `json:"body"` + User struct { + Login string `json:"login"` + } `json:"user"` + State string `json:"state"` + Stale bool `json:"stale"` + CommitID string `json:"commit_id"` +} + +// ReviewComment represents an inline comment in a review. +// All adapters use GitHub diff-position convention: +// - Position is a 1-indexed offset from the @@ hunk line in the unified diff. +// - CommitID is the commit SHA the comment is anchored to. +// +// Adapters are responsible for translating to/from platform-native formats +// (e.g. Gitea uses line numbers; GitHub uses diff positions natively). +type ReviewComment struct { + Path string `json:"path"` + Position int `json:"position"` // diff-position: 1-indexed offset from @@ hunk line + CommitID string `json:"commit_id"` + Body string `json:"body"` +} + +// ReviewRequest is the payload for posting a review. +type ReviewRequest struct { + // Body is the top-level review comment. + Body string `json:"body"` + // Event is "APPROVED" or "REQUEST_CHANGES". + Event string `json:"event"` + Comments []ReviewComment `json:"comments,omitempty"` +}