githubchecks

package
v0.182.5 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const DefaultCheckPollInterval = 30 * time.Second

DefaultCheckPollInterval deliberately leaves room for other WB operations sharing the authenticated GitHub user budget. A PR receipt still reads every dynamic fact on each observation; only static branch policy is cached within the bounded slice and is fetched again before a pass is returned.

View Source
const MaxForegroundCheckWaitSlice = 9 * time.Minute

MaxForegroundCheckWaitSlice keeps a single agent-tool call under the common ten-minute harness ceiling. Longer CI is observed by explicit re-invocation, never a detached worker or a hidden thirty-minute loop.

Variables

View Source
var DefaultStableRereadDelay = 15 * time.Second

DefaultStableRereadDelay bounds the wait before the confirming reread of a checks-bearing terminal observation. The stability fingerprint exists to catch a check set that is still registering, not to space out load: once every observed and required check is terminal, only this one confirming observation (plus the fresh authority and identity receipts) stands between the campaign and its receipt, so waiting a full quota-aware poll interval there adds DefaultCheckPollInterval of pure latency to every passing PR merge, PR validation, and direct-target receipt. Fifteen seconds sits outside GitHub's usual push-to-registration envelope for lazily created non-required checks (matrix expansion, workflow_run chains) while still cutting half the default cadence. It is a variable, and PullRequestWaitOptions.StableRereadDelay overrides it per wait, so tests and unusual deployments can tune it without recompiling callers.

Two terminal receipts never shorten this wait: the no-applicable-checks receipt (an empty observed set with an enumerated empty policy), whose only time-based guard against a repository whose CI simply has not registered yet IS this gap, and any reread after the previous observation was already terminal — a churning terminal fingerprint (for example a moving target head) falls back to the full poll cadence instead of re-observing on the short delay without bound.

Functions

func ActionsRunAndJob

func ActionsRunAndJob(rawURL string) (runID, jobID string, ok bool)

func ActiveRules

func ActiveRules(ctx context.Context, repository, target string) ([][]ActiveBranchRule, error)

activeBranchRules reads every active rule for one branch, following GitHub's link header. It returns one slice per page so callers keep the page-shaped reading `--slurp` used to give them, with none of its version dependency.

func ContainsTarget

func ContainsTarget(ctx context.Context, repository, target, candidate string) (bool, string)

func PullRequestIdentity

func PullRequestIdentity(ctx context.Context, repository, pullRequest string) (string, string, string)

pullRequestIdentity reads the exact head and target a pull request currently points at, through the one GitHub surface every `gh` this fleet has seen supports. It used to ask `gh pr view --json`, a second dialect for a fact ReadPullRequest already carries.

func PullRequestNumber

func PullRequestNumber(selector string) (string, error)

PullRequestNumber accepts every spelling a caller already has in hand — a bare number, "#12", "owner/repo#12", or the pull request's own URL — and returns the number the API is addressed by. Callers hold whichever form their own source gave them, and making each one normalize it separately is how a URL reaches an endpoint path and produces a 404 that reads like a missing pull request.

func RepositoryFromPullRequestURL

func RepositoryFromPullRequestURL(pullRequestURL string) (string, error)

RepositoryFromPullRequestURL extracts owner/repository from a pull request URL, so a caller holding only the URL can still address the API.

func RunIncludesPullRequest

func RunIncludesPullRequest(run ActionsRun, number int, base string) bool

func SkippedOrNeutralRequiredChecks

func SkippedOrNeutralRequiredChecks(checks []RemoteCheck, required []RequiredRemoteCheck) []string

skippedOrNeutralRequiredChecks reports the names of every required check (matched by name and, when the expectation names one, GitHub App ID) whose matching observed check concluded "skipped" or "neutral" rather than actually running. It never affects landability — GitHub branch protection's own evaluation is the gate (missingRequiredChecks above) — it only backs the non-blocking "deferred-validation-check-skipped" finding the worktree-merge PR route records on its candidate/PR phase for a receipt whose local validation was deferred to CI (sneat-dev/wb#591 round 3 red-team follow-up).

func SummarizeFailures

func SummarizeFailures(details []CIFailureDetail) string

summarizeCheckFailures composes the bounded, sanitized "which check, which line" text a checks-failed refusal or finding names (#600): up to maxFailureFindingChecks checks, each with its first available diagnosis line (a check-run annotation, or the job log's first "##[error]" line, or its first nonblank line) capped at maxFailureFindingLineLength characters. A check with no annotation or log excerpt available at all names only itself. An empty details slice - a refusal that observed no FailureDetails, e.g. because the failure was a policy gap rather than a red check - yields an empty string, leaving the caller's existing reason untouched.

func TargetHead

func TargetHead(ctx context.Context, repository, target string) (string, string)

Types

type ActionsRun

type ActionsRun struct {
	ID           int64  `json:"id"`
	WorkflowID   int64  `json:"workflow_id"`
	HeadSHA      string `json:"head_sha"`
	HeadBranch   string `json:"head_branch"`
	PullRequests []struct {
		Number int `json:"number"`
		Base   struct {
			Ref string `json:"ref"`
		} `json:"base"`
	} `json:"pull_requests"`
	RunAttempt   int       `json:"run_attempt"`
	Event        string    `json:"event"`
	Status       string    `json:"status"`
	Conclusion   string    `json:"conclusion"`
	CreatedAt    time.Time `json:"created_at"`
	HTMLURL      string    `json:"html_url"`
	CheckSuiteID int64     `json:"check_suite_id"`
}

func ActionsRunsForHead

func ActionsRunsForHead(ctx context.Context, options PullRequestWaitOptions) (map[int64]ActionsRun, []ActionsRun, string)

type ActiveBranchRule

type ActiveBranchRule struct {
	Type              string `json:"type"`
	RulesetSourceType string `json:"ruleset_source_type"`
	RulesetSource     string `json:"ruleset_source"`
	RulesetID         int64  `json:"ruleset_id"`
	Parameters        struct {
		StrictRequiredStatusChecksPolicy *bool `json:"strict_required_status_checks_policy"`
		RequiredStatusChecks             []struct {
			Context       string `json:"context"`
			IntegrationID int64  `json:"integration_id"`
		} `json:"required_status_checks"`
	} `json:"parameters"`
}

type CIFailureAnnotation

type CIFailureAnnotation struct {
	Path      string `json:"path" yaml:"path"`
	StartLine int    `json:"start_line" yaml:"start_line"`
	EndLine   int    `json:"end_line,omitempty" yaml:"end_line,omitempty"`
	Message   string `json:"message" yaml:"message"`
}

CIFailureAnnotation is a compact, deduplicated GitHub check-run finding. It is deliberately narrower than GitHub's annotation payload so CI receipts remain useful to machines without becoming a copy of the Actions log.

type CIFailureDetail

type CIFailureDetail struct {
	Check       string                `json:"check" yaml:"check"`
	RunURL      string                `json:"run_url,omitempty" yaml:"run_url,omitempty"`
	JobURL      string                `json:"job_url,omitempty" yaml:"job_url,omitempty"`
	Annotations []CIFailureAnnotation `json:"annotations,omitempty" yaml:"annotations,omitempty"`
	Excerpt     string                `json:"excerpt,omitempty" yaml:"excerpt,omitempty"`
	Reason      string                `json:"reason,omitempty" yaml:"reason,omitempty"`
}

CIFailureDetail is a bounded diagnostic for one failed GitHub Actions job. It deliberately carries an excerpt rather than the raw job log so a machine receipt remains compact and does not become an accidental log archive.

func PullRequestFailureDetails

func PullRequestFailureDetails(ctx context.Context, repository, selector string) ([]CIFailureDetail, error)

PullRequestFailureDetails reports why a pull request's head is red, in the form a machine can act on: the failing check, its job URL, GitHub's own deduplicated annotations (path, line, message), and a bounded log excerpt when no annotation exists.

It exists so a caller that has just observed a red head does not have to download the Actions log and grep it. WB already extracts this for landing receipts; the only thing missing was a way to ask for it without asking to merge. The result is deliberately bounded — it is the failure, not a copy of the run's output.

type ExpectedActionChecks

type ExpectedActionChecks struct {
	WorkflowID        int64
	Event             string
	PullRequestNumber int
	PullRequestBase   string
	Names             []string
}

type HeadCheck

type HeadCheck struct {
	Name   string
	Bucket string
}

HeadCheck is one observed check on a commit, in the shape a caller outside this package needs: a name and a normalized bucket.

func PullRequestHeadChecks

func PullRequestHeadChecks(ctx context.Context, repository, selector string) ([]HeadCheck, bool, error)

PullRequestHeadChecks reads every check GitHub has for a pull request's current head, and reports whether they have all passed.

It exists so there is exactly one implementation of "are this pull request's checks green?" in WB, reachable from outside this package. The alternative — `gh pr checks --json` — is unavailable on the installed client, and even where it works it is a second dialect for a fact the API already answers.

func PullRequestHeadChecksOf

func PullRequestHeadChecksOf(ctx context.Context, repository string, view PullRequestView) ([]HeadCheck, bool, error)

PullRequestHeadChecksOf is PullRequestHeadChecks for a caller that has just read the pull request itself: it does not read it a second time.

type HeadObservation

type HeadObservation struct {
	Checks  []HeadCheck
	Green   bool
	Blocked []string
}

HeadObservation is what one read of a pull request's head says: every check, whether they all passed under the target's required-check policy, and the required checks that no producer has passed on this head (the renamed-workflow trap: such a check is absent from the observed set, not pending in it).

func ObservePullRequestHead

func ObservePullRequestHead(ctx context.Context, repository string, view PullRequestView) (HeadObservation, error)

ObservePullRequestHead reads a head's check runs, its workflow runs, its commit statuses and the target's branch policy and active rules, once each, and derives both the verdict and the missing required checks from those same reads: naming the gap costs no further read.

type PullRequestView

type PullRequestView struct {
	Number         int        `json:"number"`
	State          string     `json:"state"`
	Draft          bool       `json:"draft"`
	Locked         bool       `json:"locked"`
	Title          string     `json:"title"`
	Body           string     `json:"body"`
	HTMLURL        string     `json:"html_url"`
	Merged         bool       `json:"merged"`
	MergedAt       *time.Time `json:"merged_at"`
	MergeCommitSHA string     `json:"merge_commit_sha"`
	// Mergeable is nil while GitHub is still computing the merge state. A nil
	// is not a "no": it is "ask again", and a verb must not read it as either
	// mergeable or conflicted.
	Mergeable      *bool  `json:"mergeable"`
	MergeableState string `json:"mergeable_state"`
	Head           struct {
		Ref  string `json:"ref"`
		SHA  string `json:"sha"`
		Repo *struct {
			FullName string `json:"full_name"`
		} `json:"repo"`
	} `json:"head"`
	Base struct {
		Ref  string `json:"ref"`
		SHA  string `json:"sha"`
		Repo *struct {
			FullName string `json:"full_name"`
		} `json:"repo"`
	} `json:"base"`
}

PullRequestView is the pull-request state the land and merge verbs branch on. It is deliberately small: every field here is one a verb actually reads.

func ReadPullRequest

func ReadPullRequest(ctx context.Context, repository, selector string) (PullRequestView, error)

ReadPullRequest reads one pull request. It replaces `gh pr view --json`, which the installed client supports but which would still be a second dialect for the same fact.

type PullRequestWaitOptions

type PullRequestWaitOptions struct {
	Repository  string
	PullRequest string
	Target      string
	Head        string
	// ExpectedActionChecks makes an opt-in CI wait require executed jobs from
	// one exact GitHub Actions workflow and event, even on an unprotected target.
	ExpectedActionChecks *ExpectedActionChecks
	// AllowTargetDescendant is only for post-landing target CI: the exact
	// landed Head must remain an ancestor of the observed target. Pre-landing
	// candidate and pull-request waits retain exact target-head freshness.
	AllowTargetDescendant bool
	// AllowUnfenced permits a validation-only PR check receipt when the target
	// branch has no server-enforced strict freshness fence. Merge callers leave
	// this false; it is an explicit opt-in for wait-only validation.
	AllowUnfenced     bool
	Slice             time.Duration
	CheckPollInterval time.Duration
	// StableRereadDelay overrides the shortened wait before the confirming
	// reread of a checks-bearing terminal observation. A zero value uses
	// DefaultStableRereadDelay, and the delay never exceeds
	// CheckPollInterval. The no-applicable-checks receipt and any reread
	// after fingerprint churn always wait the full CheckPollInterval.
	StableRereadDelay time.Duration
	// Progress receives completed GitHub observations. It is diagnostic only;
	// callers must use the returned result as the authoritative receipt.
	Progress          func(PullRequestWaitProgress)
	OperationProgress progress.Reporter
}

PullRequestWaitOptions identifies exactly one direct-push or pull-request head whose observed checks are read by a bounded foreground invocation. A caller resumes a pending result with the same repository, target, PR (when supplied), and head; any later head is a distinct integration candidate.

type PullRequestWaitProgress

type PullRequestWaitProgress struct {
	Observation int
	Result      PullRequestWaitResult
	NextPoll    time.Duration
}

PullRequestWaitProgress is one completed observation inside a bounded wait.

type PullRequestWaitResult

type PullRequestWaitResult struct {
	Status                     PullRequestWaitStatus `json:"status" yaml:"status"`
	Repository                 string                `json:"repository" yaml:"repository"`
	PullRequest                string                `json:"pull_request,omitempty" yaml:"pull_request,omitempty"`
	Target                     string                `json:"target" yaml:"target"`
	Head                       string                `json:"head" yaml:"head"`
	ObservedHead               string                `json:"observed_head,omitempty" yaml:"observed_head,omitempty"`
	ObservedTargetHead         string                `json:"observed_target_head,omitempty" yaml:"observed_target_head,omitempty"`
	CandidateContainsTarget    bool                  `json:"candidate_contains_target,omitempty" yaml:"candidate_contains_target,omitempty"`
	TargetContainsHead         bool                  `json:"target_contains_head,omitempty" yaml:"target_contains_head,omitempty"`
	TargetFreshnessAuthority   string                `json:"target_freshness_authority,omitempty" yaml:"target_freshness_authority,omitempty"`
	Checks                     []RemoteCheck         `json:"checks,omitempty" yaml:"checks,omitempty"`
	FailureDetails             []CIFailureDetail     `json:"failure_details,omitempty" yaml:"failure_details,omitempty"`
	RequiredChecks             []RequiredRemoteCheck `json:"required_checks,omitempty" yaml:"required_checks,omitempty"`
	RequiredChecksAuthority    string                `json:"required_checks_authority,omitempty" yaml:"required_checks_authority,omitempty"`
	PolicyAuthorityUnavailable string                `json:"policy_authority_unavailable,omitempty" yaml:"policy_authority_unavailable,omitempty"`
	UnfencedValidation         bool                  `json:"unfenced_validation,omitempty" yaml:"unfenced_validation,omitempty"`
	StableObservations         int                   `json:"stable_observations" yaml:"stable_observations"`
	Reason                     string                `json:"reason,omitempty" yaml:"reason,omitempty"`
	// Evidence carries auxiliary receipt facts that are not part of the wait
	// outcome itself. "github_read_retries" mirrors the same key on
	// PullRequestLandResult: the count and last cause of in-process transient
	// GitHub read recoveries absorbed while producing this result.
	Evidence map[string]string `json:"evidence,omitempty" yaml:"evidence,omitempty"`
}

PullRequestWaitResult is one terminating foreground observation slice. Pending means resume is required, not that the merger is finished.

func WaitForCommitChecks

func WaitForCommitChecks(ctx context.Context, options PullRequestWaitOptions) (PullRequestWaitResult, error)

WaitForCommitChecks observes checks for one exact target commit. PullRequest is optional: when present it corroborates that exact PR head and target and augments the exact-head check-run/status receipt with GitHub's PR view. Every mode observes the exact commit through producer-aware APIs. Pending is an intermediate terminal result that callers resume with the same identity, not successful completion.

func WaitForPullRequestChecks

func WaitForPullRequestChecks(ctx context.Context, options PullRequestWaitOptions) (PullRequestWaitResult, error)

WaitForPullRequestChecks retains the original internal seam for existing orchestrated PR flows while using the exact-commit waiter above.

type PullRequestWaitStatus

type PullRequestWaitStatus string

PullRequestWaitStatus is intentionally small so callers can branch on a machine result instead of parsing human GitHub CLI output.

const (
	PullRequestWaitPassed  PullRequestWaitStatus = "passed"
	PullRequestWaitPending PullRequestWaitStatus = "pending"
	PullRequestWaitFailed  PullRequestWaitStatus = "failed"
)

type RemoteCheck

type RemoteCheck struct {
	Name              string `json:"name" yaml:"name"`
	Bucket            string `json:"bucket" yaml:"bucket"`
	WorkflowID        int64  `json:"workflow_id,omitempty" yaml:"workflow_id,omitempty"`
	WorkflowRunID     int64  `json:"workflow_run_id,omitempty" yaml:"workflow_run_id,omitempty"`
	WorkflowEvent     string `json:"workflow_event,omitempty" yaml:"workflow_event,omitempty"`
	PullRequestNumber int    `json:"pull_request_number,omitempty" yaml:"pull_request_number,omitempty"`
	PullRequestBase   string `json:"pull_request_base,omitempty" yaml:"pull_request_base,omitempty"`
	// Conclusion is the raw GitHub check-run/workflow-run conclusion (e.g.
	// "success", "skipped", "neutral", "failure"), kept alongside Bucket so a
	// strict deferral-satisfaction check (sneat-dev/wb#591 red-team finding
	// X2) can tell an actually-executed pass ("success") apart from a check
	// that never ran ("skipped" or "neutral") even though checkRunBucket
	// buckets both "success" and "neutral" the same, as an ordinary "pass"
	// (only "skipped" gets its own "skipping" bucket) for the overall
	// pass/fail loop. Empty for a commit-status-derived check, which has no
	// conclusion.
	Conclusion string `json:"conclusion,omitempty" yaml:"conclusion,omitempty"`
	Link       string `json:"link,omitempty" yaml:"link,omitempty"`
	AppID      int64  `json:"app_id,omitempty" yaml:"app_id,omitempty"`
	CheckRunID int64  `json:"check_run_id,omitempty" yaml:"check_run_id,omitempty"`
}

RemoteCheck is the normalized GitHub check state observed before merge.

type RequiredRemoteCheck

type RequiredRemoteCheck struct {
	Name          string `json:"name" yaml:"name"`
	IntegrationID int64  `json:"integration_id,omitempty" yaml:"integration_id,omitempty"`
}

RequiredRemoteCheck is GitHub's target-policy expectation. IntegrationID is non-zero when a ruleset pins the context to one GitHub App; every receipt must then observe the matching exact-head check-run producer, not merely a same-named PR summary or legacy status from another actor.

func RequiredChecks

func RequiredChecks(ctx context.Context, repository, target string, requireServerFreshness bool) ([]RequiredRemoteCheck, string, string)

Jump to

Keyboard shortcuts

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