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

github

package
v0.170.5 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package github reads the person's GitHub budget: the hourly REST core limit and the GraphQL limit every session, every gh call and the person's own developer portal login draw from.

The budget is read from the X-RateLimit headers of a real request, never from /rate_limit: that endpoint is exempt and reported a full budget while real requests were already refused. The REST request is conditional (the ETag of the last answer), so a 304 costs nothing; the GraphQL one is a rateLimit query, one point.

Index

Constants

View Source
const (
	CreateReleasePRWorkflow = ".github/workflows/zz_generated.create_release_pr.yaml"
	CreateReleaseWorkflow   = ".github/workflows/zz_generated.create_release.yaml"
)

The release-PR flow devctl generates in place of Auto-release: CreateReleasePRWorkflow opens a release pull request (head <base>#release#<level>, title "chore(release): vX.Y.Z") on a push of such a branch, and CreateReleaseWorkflow, on a push to a branch its on.push filter names, tags vX.Y.Z when the pushed commit's subject is that title: the merge of the release pull request.

View Source
const (
	CheckMissing = "missing"
	CheckPending = "pending"
	CheckPass    = "pass"
	CheckFail    = "fail"
)

The outcomes of a pull request's check on its head.

View Source
const (
	Member    = "member"
	NotMember = "not a member"
)

The answers of an org membership question.

View Source
const (
	Open   = "OPEN"
	Merged = "MERGED"
	Closed = "CLOSED"
)

The states of a pull request.

View Source
const (
	DirtyState  = "dirty"
	BehindState = "behind"
)

The mergeable_state of a pull request that conflicts with its base (DirtyState), and of one whose head lacks commits of a base whose branch protection requires branches to be up to date (BehindState).

View Source
const (
	FeedbackReview        = "review"
	FeedbackReviewComment = "review_comment"
	FeedbackComment       = "comment"
)

The kinds of feedback the review guard reads, devctl pr merge's own.

View Source
const (
	SquashMerged        = 0
	SquashRed           = 1
	SquashTimeout       = 2
	SquashNotApplicable = 3
	SquashRefused       = 5
	SquashTooling       = 7
)

The plain squash merge's exit codes and verdicts, devctl pr merge's own (docs/pr-merge.md in giantswarm/devctl), so the gate reads either the same.

View Source
const AutoReleaseWorkflow = ".github/workflows/zz_generated.auto_release.yaml"

AutoReleaseWorkflow is the Auto-release workflow devctl generates: on a push to a branch its on.push filter names, it tags the merge commit.

View Source
const InstallationFile = "installation.json"

InstallationFile is the file next to an App's manifest that declares its installation: {"repositories": "all" | ["<name>", …]}.

View Source
const Marketplace = ".claude-plugin/marketplace.json"

Marketplace is a plugin marketplace's manifest, its plugins' names and versions.

View Source
const PluginReleaseWorkflow = ".github/workflows/auto-release.yaml"

PluginReleaseWorkflow is the Auto Release of a plugin marketplace: on a merged pull request it tags every plugin whose version in Marketplace the merge changed, <plugin>/vX.Y.Z (PluginTag).

View Source
const (
	ReadBackoff = 2 * time.Second
)

readTries is how often a read is asked before its last error is returned; ReadBackoff is RunGH's wait before a read's first retry.

View Source
const SquashRoute = "plain squash merge"

SquashRoute names the route in the document and the gate's lines.

Variables

View Source
var ErrPermission = errors.New("permission missing")

ErrPermission is a token that may not read an org's whole membership: it sees the public members only, so its "not a member" would be a guess.

View Source
var RunGH = Retrying(execGH, ReadBackoff)

RunGH is GH through the gh binary, acting on the repository ctx names (ActingOn) through GH_REPO; a read GitHub answers with a 5xx, an empty or a cut-off body is asked again (Retrying).

Functions

func ActingOn added in v0.125.0

func ActingOn(ctx context.Context, repo string) context.Context

ActingOn returns ctx with repo (owner/name) as the repository every gh call under it acts on: RunGH names it in GH_REPO. A gh link that picks its login by the repository's owner (devctl's agent link: the App for the owners it is installed on, the person's own login for every other) then acts with the login that reaches the repository, also on a call that names no repository itself, such as gh api graphql.

func ByOwner added in v0.138.2

func ByOwner[T any](items []T, repo func(T) string) [][]T

ByOwner splits items into groups of one repository owner each, in the order each owner first appears; repo is an item's owner/repo. A query of several repositories acts on one group at a time (ActingOn its first repository), so a gh link that picks its login by the owner reaches every repository of the group, a personal account's as well as an organisation's.

func ClosesInto added in v0.148.0

func ClosesInto(workflow []byte, branch string) (bool, error)

ClosesInto says whether a workflow runs when a pull request into branch closes: its on.pull_request (or pull_request_target) trigger lists the closed type, and its branch filters let branch through.

func HeadPulls added in v0.148.0

func HeadPulls(ctx context.Context, run GH, heads []Head) (map[Head]HeadPull, error)

HeadPulls reads, in GraphQL requests per repository owner (ByOwner) of at most headsPerRequest branches, the newest pull request each branch of heads opened from the repository itself, never a fork's. A branch that heads none, or that GitHub does not answer, is missing from the map.

func JobLog added in v0.139.2

func JobLog(ctx context.Context, run GH, repo string, job int64) (string, error)

JobLog is the log of repo's GitHub Actions job, as GitHub keeps it (terminal escape sequences included).

func ParseInstallation added in v0.151.0

func ParseInstallation(raw []byte) ([]string, error)

ParseInstallation reads an installation file: the repositories by name, nil for "all".

func PluginTag added in v0.148.0

func PluginTag(plugin, version string) string

PluginTag is the tag a plugin marketplace's Auto Release cuts for a plugin's version.

func PluginTags added in v0.148.0

func PluginTags(ctx context.Context, run GH, repo, sha string) ([]string, error)

PluginTags are the tags the PluginReleaseWorkflow cuts for merge commit sha: one per plugin whose version in Marketplace differs from its version in the commit's first parent (a plugin new in it included), in the manifest's order; none when the merge changed no version.

func PublishedCandidate added in v0.148.0

func PublishedCandidate(ctx context.Context, run GH, repo, asset string, since time.Time) (string, error)

PublishedCandidate is the newest release candidate of repo published at or after since whose asset is uploaded: a pre-release, no draft, that carries the binary an install would fetch. "" when there is none.

func PushesBranch added in v0.107.1

func PushesBranch(workflow []byte, branch string) (bool, error)

PushesBranch says whether a workflow runs on a push to branch, by its on: trigger and GitHub's branch filters (branches with ! negations, the last matching pattern deciding; branches-ignore; a tags filter alone leaves branch pushes out).

func RefStates added in v0.69.0

func RefStates(ctx context.Context, run GH, refs []PR) (map[PR]RefState, error)

RefStates reads, in GraphQL requests of at most refsBatch references of one repository owner (ByOwner), the state of each issue or pull request of refs, and for a closed issue the pull request or commit whose closing keyword closed it. A reference GitHub does not answer is missing from the map. Each try of a request is bounded by its batch's size, so run (Retrying) asks a killed one again. A batch that still fails leaves its references out and is named in the error, which joins every failed batch's; the other batches' states are returned with it.

func ReleaseVersion added in v0.150.1

func ReleaseVersion(head, title string) string

ReleaseVersion is the tag the merge of a release pull request with head branch head and title cuts, "" when it is no release pull request.

func Repo added in v0.125.0

func Repo(ctx context.Context) string

Repo is the repository ctx says gh acts on (ActingOn), "" when none.

func TagExists added in v0.148.0

func TagExists(ctx context.Context, run GH, repo, tag string) (bool, error)

TagExists says whether repo has tag.

func Token

func Token(ctx context.Context) (string, error)

Token returns the token of the gh CLI's login.

func TryTimeout added in v0.148.0

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

TryTimeout returns ctx with d as the time each try of a read under it may take (Retrying): a try past d is killed and asked again, where a deadline on ctx itself would kill the read and leave no time for the retry.

func UpdateByRebase added in v0.138.7

func UpdateByRebase(ctx context.Context, run GH, repo string, n int) error

UpdateByRebase rebases repo#n's head onto its base on GitHub's side (the pull request's "Update with rebase"), never a merge of the base into the branch, which a rebase-merge line forbids; an error carries GitHub's sentence (a conflict, a head GitHub may not write).

Types

type AppDeclaration added in v0.125.0

type AppDeclaration struct {
	// Name is the App's name.
	Name string
	// Manifest is the manifest document as declared, a JSON object.
	Manifest map[string]any
	// Repositories are the installation's repositories by name; nil is all
	// of the organisation's, declared or by the file's absence.
	Repositories []string
	// Source is where the manifest was read, <repo>@<commit>:<path>, and
	// Installation where the installation file was, "" when absent.
	Source, Installation string
}

AppDeclaration is a GitHub App's declaration as its creation reads it: the manifest document GitHub's manifest flow takes and the installation it declares.

func ReadAppDeclaration added in v0.125.0

func ReadAppDeclaration(ctx context.Context, run GH, repo, file string) (AppDeclaration, error)

ReadAppDeclaration reads the App manifest at path in repo's default branch, the document itself, and the installation file next to it at the same commit. A manifest that is missing, unreadable or names no App is an error: the App is not declared; so is an installation file of another shape than {"repositories": "all" | ["<name>", …]}.

func (AppDeclaration) Carries added in v0.150.0

func (d AppDeclaration) Carries(placeholder string) bool

Carries reports whether a string of the manifest carries placeholder.

func (AppDeclaration) Render added in v0.150.0

func (d AppDeclaration) Render(vars map[string]string) AppDeclaration

Render is the declaration with every placeholder of vars replaced in each string of the manifest, at any depth, and the name read again; d itself is unchanged.

type AppManifest added in v0.124.0

type AppManifest struct {
	// Name is the App's name.
	Name string
	// Callbacks are the hosts (with a port where the URL has one) of the
	// manifest's callback_urls, lower-case, each once; none for an App
	// without callback URLs, one used through the device flow.
	Callbacks []string
	// Source is where it was read: <repo>@<commit>:<path>.
	Source string
}

AppManifest is a GitHub App's declaration in the organisation's repository: its name and the hosts of its callback URLs, read from the manifest on the default branch.

func ParseAppManifest added in v0.153.0

func ParseAppManifest(raw []byte, src string) (AppManifest, error)

ParseAppManifest reads an App manifest's content, read at src: its name and its callback hosts. A manifest that is no JSON object or names no App is an error: the App is not declared.

func ReadAppManifest added in v0.124.0

func ReadAppManifest(ctx context.Context, run GH, repo, path string) (AppManifest, error)

ReadAppManifest reads the App manifest at path in repo's default branch: its name, its callback hosts and the commit it was read at. A manifest that is missing, unreadable or names no App is an error: the App is not declared.

type BaseChecks added in v0.135.4

type BaseChecks struct {
	Base string
	// Head is the base branch's head the outcomes are read on.
	Head string
	// Required are the contexts branch protection or a ruleset of the base
	// requires.
	Required []string
	// Outcomes are the check runs' and statuses' outcomes on Head by name:
	// CheckPass, CheckFail or CheckPending; a name without one is
	// CheckMissing.
	Outcomes map[string]string
}

BaseChecks is what a red check of a pull request is weighed against: the checks its base branch requires and each check's outcome on the base branch's head.

func ReadBaseChecks added in v0.135.4

func ReadBaseChecks(ctx context.Context, run GH, repo, base string) (BaseChecks, error)

ReadBaseChecks reads repo's base branch: the contexts its branch protection and its rulesets require, its head, and the outcome of every check run (the newest of a name) and status (the latest of a context) on that head; four requests or more (pages). An error is GitHub not answering one of them: nothing is known then.

func (BaseChecks) Outcome added in v0.135.4

func (b BaseChecks) Outcome(name string) string

Outcome is the named check's outcome on the base head, CheckMissing when it has none.

func (BaseChecks) Requires added in v0.135.4

func (b BaseChecks) Requires(name string) bool

Requires says whether the base requires the named check.

type BaseRelease added in v0.107.1

type BaseRelease struct {
	Base      string
	Auto      bool
	Plugins   bool
	ReleasePR bool
	// Version is the tag the merge of the pull request cuts when it is the
	// release pull request of a ReleasePR branch (ReleaseVersion), "" for
	// any other pull request.
	Version string
}

BaseRelease is how a pull request's base branch releases: Auto when the Auto-release workflow on the branch runs on a push to it, so a merge into it is tagged; Plugins when the branch has no such workflow and its PluginReleaseWorkflow tags the merged plugins (PluginTags); ReleasePR when it has neither and releases through the release-PR flow (CreateReleaseWorkflow), whose release pull request's merge tags Version; otherwise its tags are cut by hand (a maintenance branch, a fork line's backport branch).

func ReadBaseRelease added in v0.107.1

func ReadBaseRelease(ctx context.Context, run GH, repo string, n int) (BaseRelease, error)

ReadBaseRelease reads repo#n's base branch and the Auto-release workflow on it, two requests; on a branch without it the PluginReleaseWorkflow, a third; on a branch without either the release-PR flow's two workflows, up to two more. A branch without any has no auto-release; an error is GitHub not answering.

type Budget

type Budget struct {
	Resource  string    `json:"resource"`
	Limit     int       `json:"limit"`
	Remaining int       `json:"remaining"`
	Used      int       `json:"used"`
	Reset     time.Time `json:"reset"`
	// GraphQL is the GraphQL limit; nil when it was not read.
	GraphQL *GraphQL `json:"graphql,omitempty"`
}

Budget is the core rate limit as GitHub reported it, and the GraphQL limit beside it.

func Probe

func Probe(ctx context.Context, client *http.Client, token, repo, etag string) (Budget, string, error)

Probe reads the budget with a conditional GET of repo ("owner/name") and returns it with the ETag to send next time.

type Check added in v0.58.0

type Check struct {
	// State is the pull request's: Open, Merged or Closed.
	State string
	// Outcome is CheckMissing when the head has no check of that name.
	Outcome string
	// URL is the check run's page.
	URL string
	// Annotations are the messages a failed check run annotated with its
	// own name as the title: what it found.
	Annotations []string
}

Check is one named check of a pull request's head and the pull request's state.

func PullCheck added in v0.58.0

func PullCheck(ctx context.Context, run GH, repo string, n int, name string) (Check, error)

PullCheck reads repo#n's state and the newest check run named name on its head (one GraphQL request); a failed one's annotations titled name take a second, which leaves out the runner's own ("Process completed with exit code 1").

type GH added in v0.31.2

type GH func(ctx context.Context, args ...string) ([]byte, error)

GH runs the gh CLI and returns its stdout; err carries its stderr.

func Retrying added in v0.141.1

func Retrying(gh GH, backoff time.Duration) GH

Retrying is gh whose reads retry what GitHub answers transiently: a 5xx, an empty or a cut-off body, and a gh killed, at its TryTimeout or by the machine. Each read is asked at most readTries times, waiting backoff before the first retry and double that before the next; a read still failing returns an error naming the call, what went wrong and the tries. A write (a mutation, a REST call with a body or a non-GET method) is asked once: GitHub may have applied it before the answer broke.

type GraphQL added in v0.97.1

type GraphQL struct {
	Limit     int `json:"limit"`
	Remaining int `json:"remaining"`
	Used      int `json:"used"`
	// Reset is when the refusal ends: the hourly reset of a spent limit,
	// Retry-After of a secondary one; zero when GitHub named no time.
	Reset time.Time `json:"reset,omitzero"`
	// Refused is GitHub's words while it refuses GraphQL calls, empty while
	// it answers them.
	Refused string `json:"refused,omitempty"`
	// Secondary says the refusal is a secondary limit (too many concurrent
	// or too fast calls), not the hourly limit spent.
	Secondary bool `json:"secondary,omitempty"`
	// Err is why the limit could not be read.
	Err string `json:"error,omitempty"`
}

GraphQL is the GraphQL limit as GitHub reported it for a real query.

func ProbeGraphQL added in v0.97.1

func ProbeGraphQL(ctx context.Context, client *http.Client, token string, now time.Time) GraphQL

ProbeGraphQL reads the GraphQL limit with a real query, so a refusal shows even while the counter looks healthy: a secondary limit refuses with headroom left.

func (*GraphQL) Blocks added in v0.97.1

func (g *GraphQL) Blocks(now time.Time) bool

Blocks says the refusal still holds at now: a refusal without a reset holds until a reading says otherwise.

type Head struct {
	Repo   string `json:"repo"`
	Branch string `json:"branch"`
}

Head is a branch of a repository: owner/repo and the branch name.

type HeadPull added in v0.148.0

type HeadPull struct {
	N        int
	State    string
	HeadOid  string
	ClosedAt time.Time
}

HeadPull is the newest pull request a branch of the repository itself heads (a fork's branch of the same name is another branch): its number, its state (OPEN, CLOSED or MERGED), the commit its head was at and when it closed (zero while open).

type PR added in v0.54.0

type PR struct {
	Repo string `json:"repo"`
	N    int    `json:"n"`
}

PR is a pull request: its owner/repo and number.

func Lookup added in v0.54.0

func Lookup(ctx context.Context, run GH, pulls []PR, drafts []string) (map[PR]string, []PR, error)

Lookup reads in one GraphQL request per repository owner (ByOwner) the titles of pulls and the open draft pull requests of the repositories drafts (owner/repo), oldest first within each owner.

type Pull added in v0.8.0

type Pull struct {
	State    string    `json:"state"`
	MergedAt time.Time `json:"mergedAt"`
}

Pull is a pull request's state as the gh CLI reports it.

func PullState added in v0.8.0

func PullState(ctx context.Context, repo string, n int) (Pull, error)

PullState reads repo#n's state with the gh CLI's login (one GraphQL request, retried as RunGH retries a read).

type Rebase added in v0.113.0

type Rebase struct {
	Known      bool
	Rebaseable bool
	// State is GitHub's mergeable_state: clean, dirty, blocked, behind, …
	State string
	// Head is the pull request's head commit.
	Head string
}

Rebase is whether a pull request rebases onto its base as GitHub computed it. Known is false while GitHub has not computed it yet (rebaseable null), which it does in the background after the first read.

func ReadRebase added in v0.113.0

func ReadRebase(ctx context.Context, run GH, repo string, n int) (Rebase, error)

ReadRebase reads repo#n's rebaseable, mergeable_state and head, one request; an error is GitHub not answering.

func (Rebase) Behind added in v0.138.7

func (r Rebase) Behind() bool

Behind says the pull request rebases cleanly but lags a base that requires branches to be up to date: GitHub refuses its merge until it is updated.

func (Rebase) Conflicts added in v0.113.0

func (r Rebase) Conflicts() bool

Conflicts says the pull request cannot be rebase-merged: GitHub reports it not rebaseable, or conflicting with its base.

type RefState added in v0.109.0

type RefState struct {
	State  string
	Closer string
}

RefState is the state of an issue or pull request as GitHub answered: OPEN, CLOSED or MERGED, and for an issue a closing keyword closed, what closed it (Closer): the pull request whose merge did, as owner/repo#n, or a bare commit as "commit <sha>". Empty for a close by hand.

type Roster added in v0.105.0

type Roster struct {
	Org string `json:"org"`
	// Members are the logins, lower case and sorted.
	Members []string  `json:"members"`
	At      time.Time `json:"at"`
}

Roster is an org's members as a token that may read them all saw them.

func ReadRoster added in v0.105.0

func ReadRoster(ctx context.Context, client *http.Client, token, org string, now time.Time) (Roster, error)

ReadRoster reads org's members with token. The token's own membership comes first: only an active member's token, holding the read:org scope (or the App's members permission), lists the private members too; any other answer is ErrPermission, never an empty or public-only roster.

func (Roster) Answer added in v0.105.0

func (r Roster) Answer(login string) string

Answer is login's membership by the roster: Member or NotMember.

type Squash added in v0.31.2

type Squash struct {
	GH       GH
	Repo     string
	Number   int
	Timeout  time.Duration
	Poll     time.Duration
	Progress io.Writer
	Now      func() time.Time
	Sleep    func(time.Duration)
}

Squash is one plain squash merge: the route of a repository devctl does not serve (its GitHub App login reaches the giantswarm organisation and public repositories only), made with the gh CLI's login as the person.

func (Squash) Run added in v0.31.2

func (s Squash) Run(ctx context.Context) SquashDoc

Run waits until the head's checks finished, all green, and squash-merges it through the merge API with that head as the expected one, the subject "<title> (#<n>)", then deletes the head branch. It refuses what devctl refuses before its wait: a draft, a closed, merged or conflicting pull request (3), another human's (5) and one with a reviewer's unanswered feedback (5), devctl's review guard: read before any refusal, so the document carries the review state whatever ends the merge, and again right before the merge call. Its document says what happened; nothing waits for a release.

type SquashDoc added in v0.31.2

type SquashDoc struct {
	Command        string  `json:"command"`
	Route          string  `json:"route"`
	SchemaVersion  int     `json:"schemaVersion"`
	ExitCode       int     `json:"exitCode"`
	Verdict        string  `json:"verdict"`
	Reason         string  `json:"reason"`
	Repo           string  `json:"repository"`
	Number         int     `json:"number"`
	HeadSha        string  `json:"headSha,omitempty"`
	MergeCommitSha string  `json:"mergeCommitSha,omitempty"`
	Release        *string `json:"release"`
	// UnansweredReviews is the feedback the last review read found
	// unanswered, empty when nothing held the merge; null only when gh
	// failed before the first read.
	UnansweredReviews []UnansweredReview `json:"unansweredReviews"`
}

SquashDoc is the plain squash merge's JSON document, shaped as devctl pr merge's: the gate parses mergeCommitSha and release alike.

type UnansweredReview added in v0.125.1

type UnansweredReview struct {
	Kind  string    `json:"kind"`
	Login string    `json:"login"`
	State string    `json:"state,omitempty"`
	At    time.Time `json:"at"`
	URL   string    `json:"url"`
}

UnansweredReview is one piece of a reviewer's feedback the merge waits on, shaped as devctl pr merge's: a review, a comment on the diff or a comment on the conversation, newer than the head and not answered since.

func ReviewGuard added in v0.155.17

func ReviewGuard(ctx context.Context, gh GH, repo string, n int) (string, []UnansweredReview, error)

ReviewGuard reads repo#n's reviews and comments afresh, as the gh login, and returns the refusal's reason while a reviewer's feedback holds the merge, "" with the empty list when nothing does: the gate's own read before devctl pr merge runs, whose guard drops a request for changes once a commit or a reply is newer.

Jump to

Keyboard shortcuts

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