Documentation
¶
Overview ¶
Package github wraps the GitHub REST API calls multirunner needs: JIT runner config generation and registration tokens, across repo / org / enterprise scopes, authenticated by either a PAT or a GitHub App.
Index ¶
- Variables
- type Client
- func (c *Client) ActionsEnabled(ctx context.Context) (bool, error)
- func (c *Client) CheckRunnerAccess(ctx context.Context) error
- func (c *Client) ClientFor(repo string) *Client
- func (c *Client) ClientForSlot(int) *Client
- func (c *Client) CreateRegistrationToken(ctx context.Context) (string, error)
- func (c *Client) DeleteRunner(ctx context.Context, runnerID int64) error
- func (c *Client) GenerateJITConfig(ctx context.Context, in JITConfigRequest) (*JITConfig, error)
- func (c *Client) QueuedJobLabels(ctx context.Context) ([][]string, error)
- func (c *Client) QueuedJobs(ctx context.Context) ([]QueuedJob, error)
- func (c *Client) QueuedWorkflowJobs(ctx context.Context) ([]QueuedJob, error)
- func (c *Client) RepoFile(ctx context.Context, p string) ([]byte, error)
- func (c *Client) RepoFilePaths(ctx context.Context) ([]string, error)
- func (c *Client) ResolveQueuedJob(ctx context.Context, repository string, runID int64, labels []string) (QueuedJob, error)
- func (c *Client) RunnerBusy(ctx context.Context, runnerID int64) (bool, error)
- func (c *Client) Scope() config.Scope
- func (c *Client) Target() string
- type ClientProvider
- type JITConfig
- type JITConfigRequest
- type QueuedJob
- type RepoPollError
- type RepoSet
- func (rs *RepoSet) ClientFor(repo string) *Client
- func (rs *RepoSet) ClientForSlot(slot int) *Client
- func (rs *RepoSet) Clients() []*Client
- func (rs *RepoSet) Len() int
- func (rs *RepoSet) QueuedJobs(ctx context.Context) ([]QueuedJob, error)
- func (rs *RepoSet) Repos() []string
- func (rs *RepoSet) Scope() config.Scope
Constants ¶
This section is empty.
Variables ¶
var ErrContentsForbidden = errors.New("contents permission missing")
ErrContentsForbidden marks a tree read the credential could not perform even though it can see the repository: the contents permission is missing.
var ErrRunnerNotFound = errors.New("runner registration not found")
ErrRunnerNotFound reports that a runner registration is already gone. GitHub removes an ephemeral runner itself once it finishes its single job, so any best-effort cleanup races with that and should treat this as success.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to GitHub for a single configured scope.
func New ¶
New builds a Client from config, selecting PAT or App auth and honoring a GHES base URL when github.url is not github.com.
func (*Client) ActionsEnabled ¶
ActionsEnabled reports whether GitHub Actions is enabled on the repo. A repo with Actions switched off accepts runner registrations and reports no queued jobs, exactly like an idle repo, so it is otherwise indistinguishable from one that simply has no work. Requires a repo-scoped client.
func (*Client) CheckRunnerAccess ¶
CheckRunnerAccess lists one runner to prove the configured credential can reach the runner-admin API for this scope. Registration is the first thing that fails when the token is wrong, and it fails on the runner host rather than on the operator's terminal, so proving reachability up front turns a silent misconfiguration into an immediate error. 401/403 and 404 have different fixes (credential/scope versus owner or enterprise slug), so they are reported apart.
func (*Client) ClientForSlot ¶
ClientForSlot returns the client itself (single-scope case).
func (*Client) CreateRegistrationToken ¶
CreateRegistrationToken returns a short-lived registration token (config.sh fallback path when JIT is unavailable).
func (*Client) DeleteRunner ¶
DeleteRunner removes a runner registration from GitHub by ID. Ephemeral runners self-remove after their one job, so this is the cleanup path for runners that exited without consuming their registration. Returns ErrRunnerNotFound if GitHub already removed it.
func (*Client) GenerateJITConfig ¶
GenerateJITConfig requests a single-use JIT config for the configured scope.
func (*Client) QueuedJobLabels ¶
QueuedJobLabels preserves the label-only view for diagnostics and callers that do not make authorization decisions.
func (*Client) QueuedJobs ¶
QueuedJobs returns this client's queued jobs, each paired with the client.
func (*Client) QueuedWorkflowJobs ¶
QueuedWorkflowJobs returns queued jobs with the workflow metadata needed for pool authorization. Org/enterprise scope returns nil because there is no cheap repository workflow-runs endpoint for those scopes.
func (*Client) RepoFile ¶
RepoFile returns the contents of a repo-relative path on the default branch.
func (*Client) RepoFilePaths ¶
RepoFilePaths returns every blob path in the repo's default-branch tree. Used by `multirunner detect --repo` to find language markers without a checkout. Requires the client to be repo-scoped (owner + repo set).
func (*Client) ResolveQueuedJob ¶
func (c *Client) ResolveQueuedJob(ctx context.Context, repository string, runID int64, labels []string) (QueuedJob, error)
ResolveQueuedJob enriches a workflow_job webhook event from the authoritative workflow-run record before a privileged pool can authorize it.
func (*Client) RunnerBusy ¶
RunnerBusy reports whether GitHub currently shows the runner as running a job. Returns ErrRunnerNotFound when the registration is already gone.
type ClientProvider ¶
type ClientProvider interface {
// ClientForSlot returns the registration client for a stable warm-pool slot.
// The same slot must keep the same target across retries and every pool must
// distribute its own slots independently.
ClientForSlot(slot int) *Client
// ClientFor returns the client for "owner/repo", or nil when this provider
// does not manage that repo.
ClientFor(repo string) *Client
// QueuedJobs returns queued jobs across all managed scopes, each paired with
// the client for the repo that queued it.
QueuedJobs(ctx context.Context) ([]QueuedJob, error)
// Scope returns the configured scope.
Scope() config.Scope
}
ClientProvider abstracts access to one or more GitHub API clients for runner registration. Single-scope configs wrap a *Client directly; multi-repo configs use a RepoSet holding one client per repo.
A repo-scoped runner registers to exactly one repo, so the client chosen for a launch decides which repo that runner can ever serve. Demand-driven launches must therefore place the runner on the repo that queued the job (QueuedJobs or ClientFor). Warm capacity, where no job has been queued yet to place against, uses deterministic per-pool slot placement.
Both GenerateJITConfig and DeleteRunner within a single RunOnce call must use the same *Client (the one chosen at the start of that call).
type JITConfig ¶
type JITConfig struct {
EncodedJITConfig string `json:"encoded_jit_config"`
Runner struct {
ID int64 `json:"id"`
Name string `json:"name"`
} `json:"runner"`
}
JITConfig is the relevant part of the generate-jitconfig response.
type JITConfigRequest ¶
JITConfigRequest is the input for generate-jitconfig.
type QueuedJob ¶
type QueuedJob struct {
Client *Client
Repository string
Labels []string
WorkflowPath string
Event string
Actor string
Ref string
Status string
}
QueuedJob is a queued workflow job together with the client for the repo that queued it. Carrying the client is what lets the scaler register the new runner where the work actually is instead of wherever rotation happens to point.
type RepoPollError ¶
RepoPollError reports the repositories that could not be polled. Results from healthy repositories remain usable, but callers can distinguish a partial result from a fully successful poll.
func (*RepoPollError) AllFailed ¶
func (e *RepoPollError) AllFailed() bool
AllFailed reports whether no configured repository could be polled.
func (*RepoPollError) Error ¶
func (e *RepoPollError) Error() string
type RepoSet ¶
type RepoSet struct {
// contains filtered or unexported fields
}
RepoSet wraps multiple per-repo *Clients. Warm-pool placement is stable by slot, while each queued-job poll rotates its starting repo for fairness.
func NewRepoSet ¶
NewRepoSet builds a RepoSet from a list of per-repo clients. The repos slice provides "owner/repo" labels for logging (same length/order as clients).
func (*RepoSet) ClientFor ¶
ClientFor returns the client for "owner/repo", or nil when the repo is not in this set. Matching is case-insensitive because GitHub treats repo names that way, and webhook payloads echo whatever casing the caller used.
func (*RepoSet) ClientForSlot ¶
ClientForSlot maps each warm-pool slot deterministically. Because the slot index is local to a pool, concurrent pools cannot consume each other's placement sequence.
func (*RepoSet) QueuedJobs ¶
QueuedJobs aggregates queued jobs across all repos, rotating the first repo on every call so constrained autoscale capacity cannot perpetually favor earlier config entries.