github

package
v0.22.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package github implements the vcs.Provider interface for GitHub using the gh CLI.

Index

Constants

View Source
const MaxTransientAttempts = 4

MaxTransientAttempts bounds how many times a transient error may be retried. It is the load-bearing safety net so that over-classification (an error mistakenly treated as transient) can never retry forever. Consumers such as the CreatePR-retry and Bellows sub-tasks pair IsTransient with this bound via ShouldRetry.

Variables

This section is empty.

Functions

func Classify added in v0.21.0

func Classify(err error) error

Classify inspects err and, when it is judged transient, returns it wrapped in a *TransientError so callers can fail-fast on permanent errors and retry on transient ones. Permanent (and nil) errors are returned unchanged.

This is the single shared classification point for the vcs/github package: both the CreatePR-retry loop and the Bellows PR monitor route gh/GitHub errors through it instead of re-implementing ad-hoc string matching.

func IsTransient added in v0.21.0

func IsTransient(err error) bool

IsTransient reports whether err is a transient GitHub/gh failure that is worth retrying. It is the load-bearing predicate consumed by the CreatePR-retry and Bellows sub-tasks.

Transient classes:

  • HTTP 401 (transient auth — token momentarily not accepted)
  • HTTP 403 carrying rate-limit / secondary-rate-limit / abuse signals
  • any HTTP 5xx
  • network failures: dial/timeout/EOF/connection-reset/i/o timeout, plus net.Error timeouts and io.EOF
  • the literal GraphQL "Requires authentication" error

Everything else — including unrecognised errors — is treated as PERMANENT so that misclassification can never cause an unbounded retry loop. Permanent classes explicitly include HTTP 422 validation errors ("No commits between", "a pull request already exists"), branch-protection refusals, and HTTP 404.

func ParseRepoURL

func ParseRepoURL(url string) (owner, repo string, err error)

ParseRepoURL parses a git remote URL into owner and repository name.

func RetryTransient added in v0.21.0

func RetryTransient(ctx context.Context, b RetryBackoff, logFn RetryLogFunc, fn func() error) error

RetryTransient calls fn, retrying only while the returned error is classified transient (IsTransient) and the classifier's bound (MaxTransientAttempts) has not been reached. Permanent errors return immediately so the caller can fall through to its stranded/needs_human path without delay; the final transient error after retries are exhausted is likewise returned unchanged so the caller still reaches that fallthrough. ctx cancellation is honoured between attempts and short-circuits the wait.

This is the single retry primitive shared by the end-of-pipeline CreatePR (internal/daemon) and the Bellows gh-calling paths so the transient/permanent decision lives in exactly one place (the vcs/github classifier).

func ShouldRetry added in v0.21.0

func ShouldRetry(err error, attempt int) bool

ShouldRetry returns true only when err is transient AND the caller has not yet exhausted MaxTransientAttempts. attempt is the zero-based count of attempts already made (i.e. pass 0 before the first retry). This is the bounded primitive that guarantees over-classification can't retry forever; the actual backoff/sleep loop lives in the consuming sub-tasks.

Types

type Provider

type Provider struct {
	// contains filtered or unexported fields
}

Provider implements vcs.Provider for GitHub using the gh CLI.

func New

func New(db *state.DB) *Provider

New creates a GitHub VCS provider. The state DB is optional (may be nil); when non-nil, CreatePR records the PR and runs an initial mergeability check.

func (*Provider) CheckStatus

func (p *Provider) CheckStatus(ctx context.Context, worktreePath string, prNumber int) (*vcs.PRStatus, error)

CheckStatus gets the full status of a PR via gh pr view and GraphQL.

func (*Provider) CheckStatusLight

func (p *Provider) CheckStatusLight(ctx context.Context, worktreePath string, prNumber int) (*vcs.PRStatus, error)

CheckStatusLight gets the review-request, mergeable, and head-SHA state of a PR without fetching unresolved thread counts (which requires expensive GraphQL pagination). headRefOid is included so callers (e.g. the manual assay_rerun handler) can record the run against the actual head; omitting it left HeadSHA empty and Assay re-runs spawned workers with head="".

func (*Provider) CreatePR

func (p *Provider) CreatePR(ctx context.Context, params vcs.CreateParams) (*vcs.PR, error)

CreatePR creates a pull request using the gh CLI and optionally records it in the state DB when a DB was provided at construction time.

func (*Provider) FetchCILogs

func (p *Provider) FetchCILogs(ctx context.Context, worktreePath string, checks []vcs.CICheck) (map[string]string, error)

FetchCILogs fetches CI logs for failing checks from GitHub Actions. Returns a map of check name → log output.

func (*Provider) FetchPRChecks

func (p *Provider) FetchPRChecks(ctx context.Context, worktreePath string, prNumber int) (string, []vcs.CICheck, error)

FetchPRChecks returns the raw output of `gh pr checks` and the parsed failing checks for a PR.

func (*Provider) FetchPendingReviewRequests

func (p *Provider) FetchPendingReviewRequests(ctx context.Context, worktreePath string, prNumber int) ([]vcs.ReviewRequest, error)

FetchPendingReviewRequests uses GraphQL to check for pending review requests, including Bot reviewers (e.g., copilot-pull-request-reviewer) that the gh CLI's --json reviewRequests field does not serialize.

func (*Provider) FetchReviewComments

func (p *Provider) FetchReviewComments(ctx context.Context, worktreePath string, prNumber int) ([]vcs.ReviewComment, error)

FetchReviewComments returns review comments and unresolved threads on a PR via GraphQL and the gh CLI.

func (*Provider) FetchUnresolvedThreadCount

func (p *Provider) FetchUnresolvedThreadCount(ctx context.Context, worktreePath string, prNumber int) (int, error)

FetchUnresolvedThreadCount uses the GraphQL API to count unresolved review threads.

func (*Provider) GetPRByHeadBranch added in v0.16.0

func (p *Provider) GetPRByHeadBranch(ctx context.Context, worktreePath, branch string) (*vcs.OpenPR, error)

GetPRByHeadBranch returns the open PR whose head branch matches the given branch name, or nil if no matching PR is found. Uses --head filtering so only the matching PR is returned regardless of how many open PRs exist.

func (*Provider) GetRepoOwnerAndName

func (p *Provider) GetRepoOwnerAndName(ctx context.Context, worktreePath string) (owner, repo string, err error)

GetRepoOwnerAndName extracts the owner and repository name from git remote origin.

func (*Provider) ListOpenPRs

func (p *Provider) ListOpenPRs(ctx context.Context, worktreePath string) ([]vcs.OpenPR, error)

ListOpenPRs returns all open PRs in the repository.

func (*Provider) MergePR

func (p *Provider) MergePR(ctx context.Context, worktreePath string, prNumber int, strategy string) error

MergePR merges a PR using the gh CLI with the specified strategy. Valid strategies: "squash", "merge", "rebase". Defaults to "squash" if empty.

func (*Provider) Platform

func (p *Provider) Platform() vcs.Platform

Platform returns vcs.GitHub.

func (*Provider) ResolveThread

func (p *Provider) ResolveThread(ctx context.Context, worktreePath string, threadID string) error

ResolveThread resolves a review thread on a GitHub PR via GraphQL.

func (*Provider) ThreadIDByBodyHeader added in v0.20.0

func (p *Provider) ThreadIDByBodyHeader(ctx context.Context, worktreePath string, prNumber int, header string) (string, error)

ThreadIDByBodyHeader returns the GraphQL node ID of the first review thread on the PR whose top comment body contains the given header marker (for example an "<!-- assay-hash: … -->" line). It returns "" (no error) when no thread matches. Assay uses this to locate the thread it previously opened for a finding so the thread can be resolved once the finding is gone.

type RetryBackoff added in v0.21.0

type RetryBackoff struct {
	// BaseDelay is the delay before the first retry. Zero means no delay.
	BaseDelay time.Duration
	// Multiplier grows the delay between successive retries. Values <= 1 keep
	// the delay constant at BaseDelay.
	Multiplier float64
}

RetryBackoff configures the bounded exponential backoff used by RetryTransient. The retry count itself is bounded by the classifier's MaxTransientAttempts (via ShouldRetry), so this struct only controls the delay schedule. A zero BaseDelay disables sleeping entirely, which is convenient in tests.

func DefaultRetryBackoff added in v0.21.0

func DefaultRetryBackoff() RetryBackoff

DefaultRetryBackoff returns the production backoff schedule: a one-second initial delay doubling on each retry. Paired with MaxTransientAttempts (4) this yields delays of roughly 1s, 2s, 4s, 8s before the bead/PR falls through to its stranded/needs_human path.

type RetryLogFunc added in v0.21.0

type RetryLogFunc func(attempt int, delay time.Duration, err error)

RetryLogFunc is an optional callback invoked before each retry sleep so consumers can log the attempt in their own logging style. attempt is the 1-based number of the retry about to be performed; delay is how long the helper will wait before it; err is the transient error that triggered it.

type TransientError added in v0.21.0

type TransientError struct {
	// contains filtered or unexported fields
}

TransientError wraps an error that classification has judged to be transient — i.e. likely to succeed on retry (rate limits, transient auth, 5xx, network blips). Callers can detect it with errors.As or, more conveniently, with IsTransient. The original error remains reachable via Unwrap.

func (*TransientError) Error added in v0.21.0

func (e *TransientError) Error() string

Error implements the error interface, delegating to the wrapped error.

func (*TransientError) Unwrap added in v0.21.0

func (e *TransientError) Unwrap() error

Unwrap returns the wrapped error so errors.Is/errors.As keep working through the transient marker.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL