Documentation
¶
Index ¶
- Constants
- Variables
- func ActionsRunAndJob(rawURL string) (runID, jobID string, ok bool)
- func ActiveRules(ctx context.Context, repository, target string) ([][]ActiveBranchRule, error)
- func ContainsTarget(ctx context.Context, repository, target, candidate string) (bool, string)
- func PullRequestIdentity(ctx context.Context, repository, pullRequest string) (string, string, string)
- func PullRequestNumber(selector string) (string, error)
- func RepositoryFromPullRequestURL(pullRequestURL string) (string, error)
- func RunIncludesPullRequest(run ActionsRun, number int, base string) bool
- func SkippedOrNeutralRequiredChecks(checks []RemoteCheck, required []RequiredRemoteCheck) []string
- func SummarizeFailures(details []CIFailureDetail) string
- func TargetHead(ctx context.Context, repository, target string) (string, string)
- type ActionsRun
- type ActiveBranchRule
- type CIFailureAnnotation
- type CIFailureDetail
- type ExpectedActionChecks
- type HeadCheck
- type HeadObservation
- type PullRequestView
- type PullRequestWaitOptions
- type PullRequestWaitProgress
- type PullRequestWaitResult
- type PullRequestWaitStatus
- type RemoteCheck
- type RequiredRemoteCheck
Constants ¶
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.
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 ¶
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 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 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 ¶
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 ¶
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.
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 HeadCheck ¶
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 ¶
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"`
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 PendingResult ¶
func PendingResult(result PullRequestWaitResult) PullRequestWaitResult
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.