Documentation
¶
Overview ¶
Package ghapi wraps go-github behind a narrow domain interface. No other package may import go-github: a major-version bump changes the import path, and confining it here keeps that from rippling through every file that names a pull request.
Index ¶
- Constants
- Variables
- func Describe(err error) string
- type API
- type CachingTransport
- type Client
- func (c *Client) AuthenticatedLogin(ctx context.Context) (string, error)
- func (c *Client) FindPR(ctx context.Context, owner, repo, branch string) (PRInfo, error)
- func (c *Client) HasToken() bool
- func (c *Client) LastRate() (remaining int, reset time.Time)
- func (c *Client) ListRunJobs(ctx context.Context, owner, repo string, runID int64) ([]Job, error)
- func (c *Client) ListWorkflowRuns(ctx context.Context, owner, repo, workflowFile, branch string, limit int) ([]Run, error)
- func (c *Client) ListWorkflows(ctx context.Context, owner, repo string) ([]Workflow, error)
- func (c *Client) SuccessfulRunDurations(ctx context.Context, owner, repo, workflowFile, branch string, limit int) ([]time.Duration, error)
- type Conclusion
- type Job
- type Options
- type PRInfo
- type PRState
- type RateLimitError
- type RetryTransport
- type Run
- type RunStatus
- type Step
- type Workflow
Constants ¶
const DefaultRequestTimeout = 15 * time.Second
DefaultRequestTimeout bounds every individual API call. The CI wait passes a much longer parent context but each request is still capped.
Variables ¶
var ErrNotFound = errors.New("not found on GitHub")
ErrNotFound reports a 404 from GitHub. Callers map it to exit code 3.
ErrUnauthorized reports a 401 or 403 that is not a rate limit. Its message names the token-resolution order, because that is almost always the fix.
Functions ¶
Types ¶
type API ¶
type API interface {
FindPR(ctx context.Context, owner, repo, branch string) (PRInfo, error)
ListWorkflows(ctx context.Context, owner, repo string) ([]Workflow, error)
ListWorkflowRuns(ctx context.Context, owner, repo, workflowFile, branch string, limit int) ([]Run, error)
ListRunJobs(ctx context.Context, owner, repo string, runID int64) ([]Job, error)
SuccessfulRunDurations(ctx context.Context, owner, repo, workflowFile, branch string, limit int) ([]time.Duration, error)
AuthenticatedLogin(ctx context.Context) (string, error)
HasToken() bool
// LastRate reports the rate-limit budget GitHub returned with the most
// recent call, so a long polling loop can widen its interval before it
// runs the quota out. remaining is -1 when nothing has been observed yet.
LastRate() (remaining int, reset time.Time)
}
API is the narrow interface the rest of flow depends on. Everything above this package mocks API, never go-github itself.
type CachingTransport ¶
type CachingTransport struct {
Base http.RoundTripper
// contains filtered or unexported fields
}
CachingTransport implements conditional requests with ETags. A 45-minute CI wait polling every 5s is roughly 540 requests; without this, each one costs a rate-limit unit even when nothing changed.
It is deliberately a small in-memory map rather than a dependency on an unmaintained HTTP cache library: flow's polling loop is the only consumer, the responses are small, and the cache lives no longer than one command.
func NewCachingTransport ¶
func NewCachingTransport(base http.RoundTripper) *CachingTransport
NewCachingTransport wraps base with an ETag cache.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the go-github-backed implementation of API.
func New ¶
New builds a client. A missing token is not an error: the client still works for public data, and every caller already handles the Unknown case.
func (*Client) AuthenticatedLogin ¶
AuthenticatedLogin returns the login the token belongs to. The token itself is never returned or logged.
func (*Client) FindPR ¶
FindPR returns the newest pull request whose head is branch. A branch with no pull request yields PRNone, not an error — working before opening a PR is the normal case.
The head filter is "{owner}:{branch}", so this finds same-repo pull requests only. A PR opened from a fork has a head of "{forkOwner}:{branch}" and reads as PRNone, which makes `flow delete` ask "No pull request found for branch X. Delete anyway?" rather than naming the open PR. That is the intended trade-off for flow's workflow, where branches live in the repository itself; it fails safe, because PRNone still prompts rather than deleting. Matching fork PRs would mean listing without a head filter and comparing Head.Ref, which would also match an unrelated fork that happens to reuse the name.
func (*Client) ListRunJobs ¶
ListRunJobs returns every job of a run, following pagination: the ScaleOps workflow has well over one page of jobs, and a truncated list would silently drop a gating job.
func (*Client) ListWorkflowRuns ¶
func (c *Client) ListWorkflowRuns(ctx context.Context, owner, repo, workflowFile, branch string, limit int) ([]Run, error)
ListWorkflowRuns returns runs of one workflow file on one branch, newest first.
func (*Client) ListWorkflows ¶ added in v0.4.0
ListWorkflows returns the repository's active workflows, so flow can ask which one builds the chart rather than making the user look up a filename. Disabled workflows are left out: they cannot produce the run flow would wait for.
type Conclusion ¶
type Conclusion string
Conclusion is how a completed run or job finished.
const ( ConclusionSuccess Conclusion = "success" ConclusionFailure Conclusion = "failure" ConclusionCancelled Conclusion = "cancelled" ConclusionSkipped Conclusion = "skipped" ConclusionTimedOut Conclusion = "timed_out" ConclusionNeutral Conclusion = "neutral" ConclusionNone Conclusion = "" )
Workflow run and job conclusions.
type Job ¶
type Job struct {
ID int64 `json:"id"`
Name string `json:"name"`
Status RunStatus `json:"status"`
Conclusion Conclusion `json:"conclusion,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
Steps []Step `json:"steps,omitempty"`
}
Job is one job within a run.
func (Job) Done ¶
Done reports a job that will not change state again. A skipped job counts as satisfied: on a default dev build, the GPU and FIPS legs are always skipped, and waiting for them would hang forever.
type Options ¶
type Options struct {
APIBase string
Token string
UserAgent string
RequestTimeout time.Duration
DisableRetries bool
DisableCaching bool
// Transport overrides the base RoundTripper; tests use httptest.
Transport http.RoundTripper
}
Options configure the client.
type PRInfo ¶
type PRInfo struct {
State PRState `json:"state"`
Number int `json:"number,omitempty"` // 0 when None or Unknown
URL string `json:"url,omitempty"`
MergedAt *time.Time `json:"merged_at,omitempty"`
// Reason explains why State is Unknown, for display.
Reason string `json:"reason,omitempty"`
}
PRInfo is everything flow needs to know about a branch's pull request.
type PRState ¶
type PRState int
PRState models pull-request existence as three values, because "there is no PR" and "I could not find out" must never collapse into the same branch of a conditional — the wording a user sees differs, and so does the right action.
const ( // PRUnknown means the state could not be determined. PRUnknown PRState = iota // PRNone means it was determined that no pull request exists. PRNone PROpen PRMerged PRClosed )
Pull request states.
func (PRState) MarshalJSON ¶
MarshalJSON emits the name rather than the ordinal, so golden payloads stay readable and stable.
func (*PRState) UnmarshalJSON ¶
UnmarshalJSON parses the name form.
type RateLimitError ¶
RateLimitError reports an exhausted rate limit and when it resets.
func (*RateLimitError) Error ¶
func (e *RateLimitError) Error() string
type RetryTransport ¶
type RetryTransport struct {
Base http.RoundTripper
// Sleep overrides the wait between attempts; tests substitute a no-op.
// Left nil, the wait is a cancellable timer, so Ctrl-C during a backoff
// aborts instead of running it out.
Sleep func(time.Duration)
}
RetryTransport retries transport errors, 5xx responses and 429s, preferring the server's own Retry-After guidance over exponential backoff plus jitter. Implementing it as a RoundTripper means the policy applies uniformly instead of being repeated at every call site.
func NewRetryTransport ¶
func NewRetryTransport(base http.RoundTripper) *RetryTransport
NewRetryTransport wraps base with the retry policy.
type Run ¶
type Run struct {
ID int64 `json:"id"`
Name string `json:"name,omitempty"`
Status RunStatus `json:"status"`
Conclusion Conclusion `json:"conclusion,omitempty"`
Branch string `json:"branch,omitempty"`
HTMLURL string `json:"html_url,omitempty"`
Attempt int `json:"run_attempt,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
HeadSHA string `json:"head_sha,omitempty"`
}
Run is one workflow run, flattened to the fields flow uses.
type Step ¶
type Step struct {
Name string `json:"name"`
Number int `json:"number"`
Status RunStatus `json:"status"`
Conclusion Conclusion `json:"conclusion,omitempty"`
}
Step is one step within a job. The step list is what supplies the human-readable description in the progress display.
type Workflow ¶ added in v0.4.0
type Workflow struct {
// Name is the display name, e.g. "Build And Release".
Name string `json:"name"`
// File is the base name of the workflow file, e.g. "go.yaml". That, not
// the display name, is what every other call here takes.
File string `json:"file"`
}
Workflow is one entry from a repository's Actions workflow list.