Help us shape the future of Go! Take the 2026 Go Developer Survey

ghapi

package
v0.2.0-rc.1 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package ghapi provides a unified GitHub API client that owns both REST and GraphQL connections, retry transport, and profiling instrumentation. All GitHub API access in the CLI should go through a single Client instance constructed at startup.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultSleep

func DefaultSleep(ctx context.Context, d time.Duration)

DefaultSleep waits d but returns early when ctx is canceled. Useful for rate-limit retry loops that need to honor cancellation.

func DependabotProxy added in v0.2.0

func DependabotProxy() bool

DependabotProxy reports whether the CLI runs inside Dependabot, behind its REST-only proxy. Dependabot retries on exit 2 and reads back only actions.lock.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound reports whether err is a 404 from the GitHub REST API.

func IsPermissionDenied

func IsPermissionDenied(err error) bool

IsPermissionDenied reports whether err is a 401, or a 403 that is not a rate-limit response. Rate-limit 403s are reported by IsRateLimited instead so callers can back off rather than treat the repo as inaccessible.

func IsProxima added in v0.2.0

func IsProxima(hostname string) bool

IsProxima reports whether hostname is a canonical tenant hostname.

func IsRateLimited

func IsRateLimited(err error) bool

IsRateLimited reports whether err is a rate-limit response: HTTP 429, or a 403 with the budget exhausted or a Retry-After (secondary rate limit), the same rule retryTransport.shouldRetry uses.

func IsSAMLEnforcement added in v0.1.5

func IsSAMLEnforcement(err error) bool

IsSAMLEnforcement reports whether err represents a SAML/SSO enforcement block. It matches both REST 403s (api.HTTPError) and plain errors whose message indicates SAML enforcement (e.g. from the GraphQL resolution path).

func IsTransient added in v0.2.0

func IsTransient(err error) bool

IsTransient reports whether err is a failure a retry may fix: a rate limit, a 5xx, or a transport error. 404s, 422s and permission errors are answers, not outages. A joined error is transient when any branch is, so one 404 can't mask an outage elsewhere in the batch.

func StatusCode

func StatusCode(err error) (code int, ok bool)

StatusCode reports the HTTP status code carried by err when it originates from a REST call. ok is false when err is nil, a transport failure, or a GraphQL error that carries no HTTP status. It lets callers classify failures without importing go-gh, keeping the API transport internal to this package.

Types

type ActionFileRequest

type ActionFileRequest struct {
	Owner string
	Repo  string
	Path  string // sub-action path within the repo, may be empty
	Ref   string // tag, branch, or SHA
}

ActionFileRequest identifies a GitHub Action ref to resolve via GraphQL.

func (ActionFileRequest) NWO

func (r ActionFileRequest) NWO() string

NWO returns "Owner/Repo".

type ActionFileResult

type ActionFileResult struct {
	Hostname    string
	Owner       string
	Repo        string
	OriginalNWO string
	Path        string
	Ref         string
	CommitOID   string
	ActionYML   string
	Err         error
}

ActionFileResult holds the resolved commit OID and action.yml content for one ActionFileRequest. Err is non-nil when this specific ref could not be resolved (e.g. not found, SSO required).

Owner and Repo are the repository's canonical name. OriginalNWO is set when the request followed a rename or transfer redirect.

type ActionRef

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

ActionRef is the path-aware key used by the resolver's per-ref cache and the BFS dedup set in ResolveAllRecursive. Sub-action paths must be distinct identities for graph traversal — actions/cache/save@v4 visits a different action.yml than actions/cache@v4 — even though they collapse to the same repo+ref tarball at runner-download granularity. Use NWORef (not ActionRef) when path is irrelevant.

func ForActionRef

func ForActionRef(owner, repo, path, ref string) ActionRef

ForActionRef builds an ActionRef key.

func (ActionRef) String

func (k ActionRef) String() string

String is diagnostics-only; do not parse.

type BranchHead

type BranchHead struct {
	Name      string
	SHA       string
	Protected bool
}

BranchHead holds a branch name, the SHA of its HEAD commit, and whether the branch has branch-protection rules enabled in the upstream repo.

func OrderedBranches

func OrderedBranches(branches []BranchHead, hintBranch, hintRef, defaultBranch string) []BranchHead

OrderedBranches returns branches in tiered order so the most trust-bearing candidates are compared first:

  1. hintBranch (previously recorded in lockfile for this commit)
  2. hintRef (ref the user wrote in the workflow)
  3. defaultBranch (e.g. main / master)
  4. protected branches, lex-sorted within tier
  5. unprotected branches, lex-sorted within tier

type Client

type Client struct {
	Hostname string
	// contains filtered or unexported fields
}

Client holds authenticated REST and GraphQL clients for a single GitHub hostname. Construct via New with ClientOption values.

func New

func New(hostname string, opts ...ClientOption) (*Client, error)

New creates an authenticated Client for the given hostname using the ambient gh credential store. Use WithClientTransport for test stubs and WithClientProfile for profiling.

func (*Client) BatchBranchContains

func (c *Client) BatchBranchContains(ctx context.Context, owner, repo, sha string, branches []BranchHead) (matchedBranch string, anyChecked bool, err error)

BatchBranchContains checks whether sha is reachable from any of the given branches using the GraphQL Ref.compare API. It batches all branches into one or a few GraphQL queries (batchReachabilitySize per query) and returns the first matching branch name in the order provided.

Returns:

  • matchedBranch: name of the first branch containing sha, or "" if none
  • anyChecked: true if at least one branch was successfully checked
  • err: non-nil only on transport/auth failures (not per-branch misses)

func (*Client) CheckPins added in v0.2.0

func (c *Client) CheckPins(ctx context.Context, pins []PinCheck) []PinState

CheckPins reports, per pin, the repository's canonical name and IDs, whether the pinned commit exists, and where Tag points. It does not walk action.yml: a pinned commit fixes the dependencies it declares.

func (*Client) CommitSHA

func (c *Client) CommitSHA(ctx context.Context, owner, repo, ref string) (string, error)

CommitSHA resolves a ref (branch, tag, or SHA) to its commit SHA via the repos/commits endpoint.

func (*Client) CompareCommits

func (c *Client) CompareCommits(ctx context.Context, owner, repo, sha, branchHeadSHA string) (bool, error)

CompareCommits reports whether sha is on the lineage of branchHeadSHA using the Compare API. A 404 or 422 response (unrelated histories or missing commit) is treated as a non-error false return. Results are memoized for the lifetime of the Client and concurrent identical comparisons are coalesced via singleflight. The request runs under a cancel-free context so that one fanned-out caller's cancellation (the reachability scan cancels siblings on first match) cannot abort the shared comparison the others are waiting on.

func (*Client) CompareRefs

func (c *Client) CompareRefs(ctx context.Context, owner, repo, base, head string) (status, mergeBaseSHA string, err error)

CompareRefs returns the Compare API status and merge-base SHA for base...head. Unlike CompareCommits it surfaces the raw verdict and the underlying error (including *api.HTTPError) so callers can distinguish ancestry, forgery, and inconclusive results. Not cached: ancestry checks key on distinct base/head pairs that rarely repeat within a run.

func (*Client) ForRepo added in v0.2.0

func (c *Client) ForRepo(ctx context.Context, owner, repo string) (*Client, error)

ForRepo selects a host once per repository. Only a repository-level 404 permits public fallback; missing refs, denied access and transport errors do not.

func (*Client) GetBranchHead

func (c *Client) GetBranchHead(ctx context.Context, owner, repo, name string) (BranchHead, bool)

GetBranchHead resolves a single branch's HEAD commit directly via the git/ref endpoint. Unlike ListBranches this is not subject to the paginated 300-branch cap. Results (including 404s) are cached and concurrent lookups are coalesced via singleflight. Returns ok=false on any error.

func (*Client) GetDefaultBranch

func (c *Client) GetDefaultBranch(ctx context.Context, owner, repo string) string

GetDefaultBranch returns the repo's default branch name (e.g. "main"), or "" if the lookup fails. Backed by the shared repoMetadata fetch.

func (*Client) ListBranches

func (c *Client) ListBranches(ctx context.Context, owner, repo string) ([]BranchHead, error)

ListBranches returns all branches with their HEAD SHAs for a repo. Paginates up to 3 pages (300 branches). Results are cached per owner/repo and coalesced via singleflight.

func (*Client) ListProtectedBranches

func (c *Client) ListProtectedBranches(ctx context.Context, owner, repo string) []BranchHead

ListProtectedBranches returns the repo's protected branches. Best-effort: any error yields whatever was collected so far (possibly empty). Results are cached per owner/repo and coalesced via singleflight.

func (*Client) ListTags

func (c *Client) ListTags(ctx context.Context, owner, repo string) ([]TagEntry, error)

ListTags returns all tags with their commit SHAs for a repo (first page, up to 100). Results are cached per owner/repo and coalesced via singleflight.

func (*Client) MatchingHeadRefs

func (c *Client) MatchingHeadRefs(ctx context.Context, owner, repo, prefix string) []BranchHead

MatchingHeadRefs returns branches whose names start with prefix via the git/matching-refs endpoint. Best-effort: any error yields nil.

func (*Client) PeelTagObject

func (c *Client) PeelTagObject(ctx context.Context, owner, repo, sha string) (PeelTagObjectResult, error)

PeelTagObject queries whether sha is an annotated tag object in owner/repo and, if so, returns the commit it dereferences to. Returns a zero result (not an error) when the OID or repo is not accessible — callers decide how to interpret the negative.

func (*Client) PinHost added in v0.2.0

func (c *Client) PinHost(owner, repo, hostname string) error

PinHost binds a repository to its recorded host before any resolution starts. A repository cannot span hosts within a run: caches and ref selection are repository-scoped, and guessing would mix identities.

func (*Client) Releases

func (c *Client) Releases(ctx context.Context, owner, repo string) ([]RepoRelease, error)

Releases lists a repository's most recent releases (up to 30).

func (*Client) RepoIDs

func (c *Client) RepoIDs(ctx context.Context, owner, repo string) (int64, int64, error)

RepoIDs returns the numeric owner ID and repo ID for a NWO. Backed by the shared repoMetadata fetch, so it shares a single repos/{owner}/{repo} round-trip with GetDefaultBranch.

func (*Client) RepoMetadata

func (c *Client) RepoMetadata(ctx context.Context, owner, repo string) (RepoMetadata, error)

RepoMetadata fetches a repository's default branch, visibility, and last push time. Delegates to the shared repoMetadata fetch so it shares the cached, singleflight-coalesced repos/{owner}/{repo} round-trip with GetDefaultBranch and RepoIDs.

func (*Client) RepoTags

func (c *Client) RepoTags(ctx context.Context, owner, repo string) ([]RepoTag, error)

RepoTags lists a repository's tags (up to 100) with the commit SHA each resolves to. Delegates to ListTags so it shares the cached, singleflight- coalesced tag fetch rather than issuing a second identical request.

func (*Client) ResolveActionFiles

func (c *Client) ResolveActionFiles(ctx context.Context, refs []ActionFileRequest) []ActionFileResult

ResolveActionFiles resolves action refs to commit OIDs and fetches their action.yml/yaml content in a single batched GraphQL round-trip. Results are returned in the same order as inputs; per-ref failures are recorded in each result's Err field rather than aborting the batch.

If the whole query is rejected — transport failure, query cost/complexity, or a secondary rate limit — the batch is split in half and each half retried, recursively down to a single ref, so a few oversized or bad refs can't fail their batch-mates. Splitting is skipped once ctx is canceled so a canceled scan doesn't fan out into a flurry of doomed retries.

func (*Client) SSOFallbackEligible added in v0.1.5

func (c *Client) SSOFallbackEligible(ctx context.Context, owner string) bool

SSOFallbackEligible reports whether the given owner's repos can be accessed anonymously when SSO blocks authenticated access. On first call for an owner, it probes the GitHub API with an unauthenticated request to determine accessibility, then caches a definitive result.

type ClientOption

type ClientOption func(*clientConfig)

ClientOption configures a Client at construction time. Pass to New.

func WithClientProfile

func WithClientProfile(p *profile.Session) ClientOption

WithClientProfile attaches profiling instrumentation to API calls.

func WithClientTransport

func WithClientTransport(t http.RoundTripper) ClientOption

WithClientTransport overrides the HTTP transport. Use in tests with httpmock.

type Compare

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

Compare identifies a Compare API result between two SHAs in a repo, e.g. "is base an ancestor of head?". Both SHAs are lowercased.

func ForCompare

func ForCompare(owner, repo, base, head string) Compare

ForCompare builds a Compare key, lowercasing both SHAs.

func (Compare) String

func (k Compare) String() string

String is diagnostics-only; do not parse.

type NWOName

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

NWOName pairs a repo with an arbitrary name (e.g. a branch name). The name preserves case; callers that want case-insensitive lookup must normalize before passing in.

func ForNWOName

func ForNWOName(owner, repo, name string) NWOName

ForNWOName builds an NWOName key.

func (NWOName) String

func (k NWOName) String() string

String is diagnostics-only; do not parse.

type NWORef

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

NWORef pairs a repo with a git ref (tag, branch, or SHA-as-written). Refs preserve their original case because git refs are case-sensitive.

func ForNWORef

func ForNWORef(owner, repo, ref string) NWORef

ForNWORef builds an NWORef key.

func (NWORef) String

func (k NWORef) String() string

String is diagnostics-only; do not parse.

type NWOSha

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

NWOSha pairs a repo with a lowercased commit SHA.

func ForNWOSha

func ForNWOSha(owner, repo, sha string) NWOSha

ForNWOSha builds an NWOSha key, lowercasing the SHA.

func (NWOSha) String

func (k NWOSha) String() string

String is diagnostics-only; do not parse.

type PeelTagObjectResult

type PeelTagObjectResult struct {
	// Typename is the __typename of the object at the given OID
	// ("Tag", "Commit", "Blob", "Tree"), or empty if the OID/repo
	// was not found.
	Typename string

	// CommitOID is the commit SHA the tag peels to (via ^{commit}).
	// Empty when the peel fails or the object is not a tag.
	CommitOID string
}

PeelTagObjectResult holds the outcome of a tag-object peel query.

type PinCheck added in v0.2.0

type PinCheck struct {
	Owner string
	Repo  string
	SHA   string
	// Tag, when set, must still peel to SHA.
	Tag string
	// Head, when set, is a mutable ref whose current commit is reported as
	// HeadOID so the caller can check SHA is still in its history.
	Head string
}

PinCheck is a locked dependency to re-check against the host, mirroring what the runner verifies at job start.

type PinState added in v0.2.0

type PinState struct {
	NameWithOwner string
	OwnerID       int64
	RepoID        int64
	// RepoMissing means the locked owner/repo did not resolve. A 404 can't
	// tell a deleted repository from one this token can't see.
	RepoMissing bool
	// ViaFallback marks a verdict from the REST-only or SSO fallback path,
	// where a missing token or SSO grant is the likelier cause.
	ViaFallback bool
	CommitFound bool
	// TagOID is the commit Tag peels to; empty when the tag is gone.
	TagOID string
	// HeadOID is the commit Head peels to; empty when the ref is gone.
	HeadOID string
	Err     error
}

PinState is the host's view of a PinCheck. Err marks an inconclusive check.

type RefNotFoundError added in v0.2.0

type RefNotFoundError struct {
	Owner, Repo, Ref string
	Err              error
}

RefNotFoundError reports a ref that does not exist in a repository that does. Unlike a transport or rate-limit failure, retrying will not help.

func (*RefNotFoundError) Error added in v0.2.0

func (e *RefNotFoundError) Error() string

func (*RefNotFoundError) Unwrap added in v0.2.0

func (e *RefNotFoundError) Unwrap() error

type Repo

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

Repo identifies a GitHub repository by owner and name. Both components are lowercased on construction so case variants share a single cache slot.

func ForRepo

func ForRepo(owner, repo string) Repo

ForRepo builds a Repo key, lowercasing owner and repo.

func (Repo) String

func (r Repo) String() string

String returns the normalized "owner/repo" key, used for cache-key diagnostics and for singleflight coalescing.

type RepoMetadata

type RepoMetadata struct {
	DefaultBranch string
	Visibility    string // "public", "private", or "internal"
	PushedAt      string // ISO 8601 timestamp of last push
}

RepoMetadata holds repository-level metadata relevant for pinning decisions.

type RepoRelease

type RepoRelease struct {
	TagName     string
	PublishedAt string // ISO 8601 date
	Immutable   bool
}

RepoRelease holds release metadata for a tag.

type RepoTag

type RepoTag struct {
	Name string
	SHA  string
}

RepoTag is a tag name paired with the commit SHA it resolves to, as returned by the repos/tags endpoint (annotated tags dereferenced).

type SSORateLimitedError added in v0.2.0

type SSORateLimitedError struct {
	Host, Owner string
	Err         error
}

SSORateLimitedError reports a SAML-blocked token whose anonymous fallback was rate-limited. The message reuses the SSO guidance so callers render the same authorization hint.

func (*SSORateLimitedError) Error added in v0.2.0

func (e *SSORateLimitedError) Error() string

func (*SSORateLimitedError) Unwrap added in v0.2.0

func (e *SSORateLimitedError) Unwrap() error

type TagEntry

type TagEntry struct {
	Name string
	SHA  string
}

TagEntry holds a tag name and the commit SHA it points at.

Directories

Path Synopsis
Package httpmock provides HTTP test fakes for the ghapi client.
Package httpmock provides HTTP test fakes for the ghapi client.

Jump to

Keyboard shortcuts

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