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 ¶
- func DefaultSleep(ctx context.Context, d time.Duration)
- func IsNotFound(err error) bool
- func IsPermissionDenied(err error) bool
- func IsRateLimited(err error) bool
- func IsSAMLEnforcement(err error) bool
- func StatusCode(err error) (code int, ok bool)
- type ActionFileRequest
- type ActionFileResult
- type ActionRef
- type BranchHead
- type Client
- func (c *Client) BatchBranchContains(ctx context.Context, owner, repo, sha string, branches []BranchHead) (matchedBranch string, anyChecked bool, err error)
- func (c *Client) CommitSHA(ctx context.Context, owner, repo, ref string) (string, error)
- func (c *Client) CompareCommits(ctx context.Context, owner, repo, sha, branchHeadSHA string) (bool, error)
- func (c *Client) CompareRefs(ctx context.Context, owner, repo, base, head string) (status, mergeBaseSHA string, err error)
- func (c *Client) GetBranchHead(ctx context.Context, owner, repo, name string) (BranchHead, bool)
- func (c *Client) GetDefaultBranch(ctx context.Context, owner, repo string) string
- func (c *Client) ListBranches(ctx context.Context, owner, repo string) ([]BranchHead, error)
- func (c *Client) ListProtectedBranches(ctx context.Context, owner, repo string) []BranchHead
- func (c *Client) ListTags(ctx context.Context, owner, repo string) ([]TagEntry, error)
- func (c *Client) MatchingHeadRefs(ctx context.Context, owner, repo, prefix string) []BranchHead
- func (c *Client) PeelTagObject(ctx context.Context, owner, repo, sha string) (PeelTagObjectResult, error)
- func (c *Client) Releases(ctx context.Context, owner, repo string) ([]RepoRelease, error)
- func (c *Client) RepoIDs(ctx context.Context, owner, repo string) (int64, int64, error)
- func (c *Client) RepoMetadata(ctx context.Context, owner, repo string) (RepoMetadata, error)
- func (c *Client) RepoTags(ctx context.Context, owner, repo string) ([]RepoTag, error)
- func (c *Client) ResolveActionFiles(ctx context.Context, refs []ActionFileRequest) []ActionFileResult
- func (c *Client) SSOFallbackEligible(ctx context.Context, owner string) bool
- type ClientOption
- type Compare
- type NWOName
- type NWORef
- type NWOSha
- type PeelTagObjectResult
- type Repo
- type RepoMetadata
- type RepoRelease
- type RepoTag
- type TagEntry
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DefaultSleep ¶
DefaultSleep waits d but returns early when ctx is canceled. Useful for rate-limit retry loops that need to honor cancellation.
func IsNotFound ¶
IsNotFound reports whether err is a 404 from the GitHub REST API.
func IsPermissionDenied ¶
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 IsRateLimited ¶
IsRateLimited reports whether err is a primary rate-limit response (HTTP 429) or a secondary one (HTTP 403 with the rate-limit budget exhausted).
func IsSAMLEnforcement ¶ added in v0.1.5
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 StatusCode ¶
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.
type ActionFileResult ¶
type ActionFileResult struct {
Owner string
Repo 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).
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 ¶
ForActionRef builds an ActionRef key.
type BranchHead ¶
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:
- hintBranch (previously recorded in lockfile for this commit)
- hintRef (ref the user wrote in the workflow)
- defaultBranch (e.g. main / master)
- protected branches, lex-sorted within tier
- 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) CommitSHA ¶
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) GetBranchHead ¶
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 ¶
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 ¶
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 ¶
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) RepoIDs ¶
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 ¶
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 ¶
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
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 the 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 ¶
ForCompare builds a Compare key, lowercasing both SHAs.
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 ¶
ForNWOName builds an NWOName key.
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.
type NWOSha ¶
type NWOSha struct {
// contains filtered or unexported fields
}
NWOSha pairs a repo with a lowercased commit SHA.
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 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.
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 ¶
RepoRelease holds release metadata for a tag.