github

package
v0.0.77 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ReviewEventComment submits a non-blocking review comment (GitHub's
	// default "COMMENT" event) — the only event Pruefer V1 ever submitted.
	ReviewEventComment = ReviewEvent{/* contains filtered or unexported fields */}
	// ReviewEventRequestChanges submits a blocking "REQUEST_CHANGES" review.
	// Pruefer computes this Go-side from parsed finding severities — never
	// from Claude's prose — see pruefer/review.go's decideEvent.
	ReviewEventRequestChanges = ReviewEvent{/* contains filtered or unexported fields */}
)
View Source
var ErrAutoMergeAlreadyClean = errors.New("PR is already in clean status — merge directly")

ErrAutoMergeAlreadyClean is returned by EnablePullRequestAutoMerge when the PR is already in CLEAN status (all checks passed, immediately mergeable). GitHub rejects auto-merge enablement in this state — the caller must merge directly instead. Matched on the string "Pull request is in clean status" from the GitHub GraphQL API (confirmed from production logs).

View Source
var ErrAutoMergeNotEnabled = errors.New("repository has not enabled auto-merge")

ErrAutoMergeNotEnabled is returned by EnablePullRequestAutoMerge when the repository has not enabled the auto-merge feature in its settings.

View Source
var ErrMethodNotAllowed = errors.New("method not allowed")

ErrMethodNotAllowed is returned by REST methods when the server responds with 405. Callers may use errors.Is(err, github.ErrMethodNotAllowed) to detect unsupported operations (e.g. rebase merge not allowed by repo policy).

View Source
var ErrNoRepoConfigured = errors.New("repo must not be empty")

ErrNoRepoConfigured is returned by SeedLabels when repo is empty.

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned by REST methods when the server responds with 404. Callers may use errors.Is(err, github.ErrNotFound) to distinguish "not found" from other failures without fragile string matching.

View Source
var ErrNotMergeable = errors.New("PR is not mergeable")

ErrNotMergeable is returned by MergePR when the PR cannot be merged because GitHub reports mergeable as false or null (not yet computed). Callers may use errors.Is(err, github.ErrNotMergeable) to distinguish this from API failures.

View Source
var ErrNotMergeableCI = errors.New("PR mergeable_state is not CI-clean")

ErrNotMergeableCI is returned by MergePR when the PR has no merge conflicts (mergeable is true) but mergeable_state is not in the MergeableStateAccepted allowlist ({clean, unstable}) — e.g. a required status check is failing or still pending ("blocked"), or GitHub has not finished computing the state ("unknown"/""). This is distinct from ErrNotMergeable: it is a CI-readiness refusal, not a merge conflict, and callers must not route it into the fabrik:rebase-needed / rebase-reinvoke path. Callers should treat it as "not ready yet" and retry on their existing cadence.

View Source
var ErrUnprocessableEntity = errors.New("unprocessable entity")

ErrUnprocessableEntity is returned by REST methods when the server responds with 422. Callers may use errors.Is(err, github.ErrUnprocessableEntity) to detect "already exists" or validation failures without fragile string matching.

View Source
var Logf func(issueNumber int, tag, format string, args ...any)

Logf is an optional package-level logger callback. When non-nil, internal retry/diagnostic warnings (e.g. project board indexer mismatches) are routed here. Engine wires this to its own logf during construction so messages land in fabrik.log; tests that don't set it get silent retries.

Functions

func BuildAppJWT added in v0.0.76

func BuildAppJWT(appID int64, privateKey *rsa.PrivateKey) (string, error)

BuildAppJWT constructs and signs a short-lived (9 minute) RS256 JWT asserting the given GitHub App ID, per GitHub's App-authentication flow (https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app). This JWT authenticates as the App itself — it is exchanged for a per-installation access token via MintInstallationToken, never used directly against ordinary REST/GraphQL endpoints.

Hand-rolled rather than via a JWT library: GitHub's App-auth flow needs exactly one fixed-shape token (header.payload signed with RS256), which stdlib crypto/rsa + encoding/json + encoding/base64 covers directly, consistent with this module's "minimize external dependencies" convention.

func ClassifyCheckRuns added in v0.0.71

func ClassifyCheckRuns(checkRuns []CheckRun) (status CheckRunStatus, pending, failed []CheckRun)

ClassifyCheckRuns reduces checkRuns to the latest run per check name (highest ID wins — GitHub check-run IDs are monotonically increasing, so this discards a stale completed/failed entry left behind when a check is rerun under a new ID) and classifies the result. Any pending run, at any name, takes global precedence over any failed run: a check still running is never outweighed by a different check (or a superseded run of the same check) that has already failed.

This is the single source of truth for check-run classification, shared by settlePRMergeState (engine/pr_settle.go) and checkCIGate (engine/ci.go) so the two call sites cannot drift out of agreement.

func FetchAppSlug added in v0.0.76

func FetchAppSlug(baseURL, jwt string) (string, error)

FetchAppSlug returns the App's own slug (e.g. "my-reviewer") via GET /app, JWT-authenticated. The App's bot identity login on issues/PRs/reviews is always "<slug>[bot]" — used by Pruefer to recognize its own comments and reviews (self-review skip, already-reviewed-at-SHA state).

func FetchInstallationRepositories added in v0.0.76

func FetchInstallationRepositories(baseURL, installationToken string) ([]string, error)

FetchInstallationRepositories lists the repositories an installation actually grants access to, via GET /installation/repositories. Only meaningful (and only ever called) for an installation whose RepositorySelection is "selected" — an "all" installation grants access to every current and future repo on the account, so there is nothing to enumerate. Unlike the App-JWT-authenticated calls above, this endpoint is scoped to the installation's own identity: it must be authenticated with that installation's access token, not the App's JWT.

func IsBotLogin

func IsBotLogin(login string) bool

IsBotLogin returns true if the login matches known bot patterns. Used as a fallback when the GraphQL __typename field is absent or not "Bot".

Originally a reviewer-classification fallback, where a false positive (misclassifying a human as a bot) is harmless. It is now also load-bearing for the fabrik:paused / fabrik:awaiting-input resume gate (engine/comments.go's filterHuman, ADR 069), where a false positive is not harmless: a human login that coincidentally matches one of these suffix/prefix heuristics (e.g. a genuine "data-bot" account) would be silently unable to resume a pause by commenting. Weigh that cost, not just the original fallback use, when adding new patterns here.

func MergeableStateAccepted

func MergeableStateAccepted(mergeableState string) bool

MergeableStateAccepted reports whether GitHub's mergeable_state value indicates the PR is mergeable per branch protection rules. "clean" means fully ready; "unstable" means non-required checks have failed but the PR is still mergeable. Other values ("blocked", "behind", "dirty", "draft", "has_hooks", "unknown", "") fall through to the per-check classification.

"has_hooks" is treated as not-accepted here because pre-merge hooks may modify the merge outcome; conservative to use the per-check path.

func MintInstallationToken added in v0.0.76

func MintInstallationToken(baseURL, jwt string, installationID int64) (token string, expiresAt time.Time, err error)

MintInstallationToken exchanges a JWT for a short-lived (~1 hour) installation access token via POST /app/installations/{installation_id}/access_tokens. The returned token is used as an ordinary Bearer token for REST/GraphQL calls scoped to that installation's repos and permissions; callers must refresh it before expiresAt (see Pruefer's auth.go refresh loop).

func ParseAppPrivateKey added in v0.0.76

func ParseAppPrivateKey(pemBytes []byte) (*rsa.PrivateKey, error)

ParseAppPrivateKey parses a PEM-encoded RSA private key as used by a GitHub App (downloaded from the App's settings page). Both PKCS#1 ("BEGIN RSA PRIVATE KEY") and PKCS#8 ("BEGIN PRIVATE KEY") encodings are accepted, since GitHub's own download and common conversions (e.g. via openssl) produce either depending on tooling.

Types

type AppInstallation added in v0.0.76

type AppInstallation struct {
	ID      int64  // Installation ID, needed to mint an installation access token.
	Account string // Login of the org/user the App is installed on.
	// RepositorySelection is "all" or "selected". "selected" means the
	// installation only grants access to a subset of Account's repos — the
	// actual subset is only discoverable via FetchInstallationRepositories,
	// which requires an installation access token (not the App's JWT).
	RepositorySelection string
}

AppInstallation represents a single installation of a GitHub App, as returned by GET /app/installations.

func FetchAppInstallations added in v0.0.76

func FetchAppInstallations(baseURL, jwt string) ([]AppInstallation, error)

FetchAppInstallations lists every installation of the GitHub App authenticated by jwt via GET /app/installations. Used for dynamic installation discovery: Pruefer watches whatever repos the App is installed on, so adding a repo requires only a GitHub-side installation change, not a Pruefer config or code change (see ADR-1113).

type BoardProbeItem

type BoardProbeItem struct {
	ItemID             string
	ContentID          string
	Number             int
	IsPR               bool
	IsClosed           bool
	State              string
	Repo               string
	EffectiveUpdatedAt time.Time
	LinkedPRNumber     int
	LinkedPRUpdatedAt  time.Time
	LinkedPRHeadSHA    string // headRefOid from GraphQL probe query; empty if no linked PR
	Status             string
}

BoardProbeItem is the per-item result from ProbeProjectBoard. It contains only scalar identity fields — no labels or full comment history — to minimise GraphQL cost on idle polls. effectiveUpdatedAt is max(content.updatedAt, projectItem.updatedAt, linkedPR.updatedAt); used for cache staleness checks.

type CheckRun

type CheckRun struct {
	ID         int64 // GitHub check run ID
	Name       string
	Status     string // "queued", "in_progress", "completed"
	Conclusion string // "success", "failure", "neutral", "cancelled", "skipped", "timed_out", "action_required", or ""
}

CheckRun holds the result of a single CI check run.

type CheckRunStatus added in v0.0.71

type CheckRunStatus int

CheckRunStatus is the aggregate classification of a set of check runs.

const (
	// CheckRunsReady means every latest-per-name run completed successfully
	// (or there are no check runs at all).
	CheckRunsReady CheckRunStatus = iota
	// CheckRunsPending means at least one latest-per-name run is still
	// queued/in_progress. Pending always takes precedence over failed —
	// a fresh rerun in progress must never be shadowed by a stale failure
	// of a different check (or of the same check under an older ID).
	CheckRunsPending
	// CheckRunsFailed means at least one latest-per-name run completed with
	// a failing conclusion and none are pending.
	CheckRunsFailed
)

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a GitHub GraphQL API client.

func NewClient

func NewClient(token string) *Client

func NewClientWithBaseURL

func NewClientWithBaseURL(token, baseURL string) *Client

NewClientWithBaseURL creates a client with a custom base URL. An empty baseURL falls back to defaultBaseURL (the production API host), matching NewClient and the appRequest convention — a caller passing "" means "the real GitHub API", not a hostless client. Without this, production callers (e.g. pruefer's mintAuth, which passes "" for the non-test case) built clients whose requests hit "/repos/..." with no scheme/host ("unsupported protocol scheme"). Tests always pass an httptest URL, so they never caught it.

func (*Client) AddBlockedByIssue

func (c *Client) AddBlockedByIssue(issueNodeID, blockerNodeID string) error

AddBlockedByIssue creates a "blocked by" dependency edge: issueNodeID is blocked by blockerNodeID. After this call, blockerNodeID will appear in issueNodeID's blockedBy(first: N) GraphQL field.

NOTE: GitHub's API is asymmetrically named: the read field is Issue.blockedBy but the write mutation is addBlockedBy (not addBlockedByIssue). The input field is blockingIssueId (not blockedById). Verified via schema introspection against api.github.com/graphql on 2026-05-24.

func (*Client) AddComment

func (c *Client) AddComment(owner, repo string, issueNumber int, body string) (int, error)

AddComment posts a comment on an issue and returns the comment's database ID.

func (*Client) AddCommentReaction

func (c *Client) AddCommentReaction(owner, repo string, commentDatabaseID int, content string) error

AddCommentReaction adds a reaction to an issue comment (or issue-level PR comment). Content can be "+1", "-1", "eyes", etc. For PR review thread (inline) comments, use AddPRReviewCommentReaction instead — they live at a different endpoint.

func (*Client) AddLabelToIssue

func (c *Client) AddLabelToIssue(owner, repo string, issueNumber int, labelName string) error

AddLabelToIssue adds a label to an issue. Creates the label if it doesn't exist.

func (*Client) AddPRReviewCommentReaction

func (c *Client) AddPRReviewCommentReaction(owner, repo string, commentDatabaseID int, content string) error

AddPRReviewCommentReaction adds a reaction to a PR review thread (inline) comment. These live at /repos/.../pulls/comments/{id}/reactions rather than /repos/.../issues/comments/{id}/reactions.

func (*Client) AddProjectV2ItemById

func (c *Client) AddProjectV2ItemById(projectID, contentNodeID string) (string, error)

AddProjectV2ItemById adds an issue or PR (identified by its GraphQL node ID) to a GitHub Projects v2 board. Returns the new project item's node ID.

func (*Client) AddReviewRequest

func (c *Client) AddReviewRequest(owner, repo string, prNumber int, reviewers []string) error

AddReviewRequest adds one or more reviewer requests to a pull request.

func (*Client) ArchiveProjectItem

func (c *Client) ArchiveProjectItem(projectID, itemID string) error

ArchiveProjectItem archives a project item so it no longer appears in paginated board results. Archiving is idempotent — calling it on an already-archived item is a no-op.

func (*Client) CloseIssue

func (c *Client) CloseIssue(owner, repo string, issueNumber int) error

CloseIssue closes a GitHub issue via the REST API.

func (*Client) CreateDraftPR

func (c *Client) CreateDraftPR(owner, repo, title, head, base, body string, _ int) (int, error)

CreateDraftPR creates a draft pull request for the given issue branch. Returns the PR number. Callers should first call FindPRForIssue to avoid duplicates. The body parameter is the full PR body; callers are responsible for including "Closes #N".

func (*Client) CreateIssue

func (c *Client) CreateIssue(owner, repo, title, body string) (number int, nodeID string, err error)

CreateIssue creates a new GitHub issue via the REST API and returns the issue number and GraphQL node ID. The node ID is required for project board and blockedBy mutations.

func (*Client) CreatePR added in v0.0.71

func (c *Client) CreatePR(owner, repo, title, head, base, body string) (int, error)

CreatePR creates a non-draft pull request. Returns the PR number. Unlike CreateDraftPR, the PR is immediately ready for review and CI.

func (*Client) DeleteForwardingHooks

func (c *Client) DeleteForwardingHooks(owner, repo string) error

DeleteForwardingHooks deletes repo hooks matching webhookForwarderURL; 404 on DELETE is success.

func (*Client) DeleteReviewRequest

func (c *Client) DeleteReviewRequest(owner, repo string, prNumber int, reviewers []string) error

DeleteReviewRequest removes one or more reviewer requests from a pull request. GitHub's DELETE endpoint requires a JSON body with the reviewer list, so this uses restRequest("DELETE", ...) rather than restDelete (which sends no body).

func (*Client) DequeuePullRequest added in v0.0.71

func (c *Client) DequeuePullRequest(owner, repo string, prNumber int) error

DequeuePullRequest removes a pull request from the repository's merge queue.

Uses the same two-step pattern as MarkPRReady: fetch the PR node ID via GraphQL, then call the dequeuePullRequest mutation.

func (*Client) DisablePullRequestAutoMerge added in v0.0.76

func (c *Client) DisablePullRequestAutoMerge(owner, repo string, prNumber int) error

DisablePullRequestAutoMerge disables GitHub's native auto-merge on a pull request that previously had it enabled via EnablePullRequestAutoMerge. Used to stop GitHub from merging underneath Fabrik's review-reinvoke loop when an unresolved review thread appears on the current head during the convergence window (#1207).

Uses the same two-step pattern as EnablePullRequestAutoMerge: fetch the PR node ID via GraphQL, then call the disablePullRequestAutoMerge mutation.

func (*Client) EnablePullRequestAutoMerge added in v0.0.68

func (c *Client) EnablePullRequestAutoMerge(owner, repo string, prNumber int, strategy string) error

EnablePullRequestAutoMerge enables GitHub's native auto-merge on a pull request. strategy must be one of "MERGE", "SQUASH", or "REBASE". GitHub merges the PR atomically when all branch-protection requirements are satisfied.

Returns ErrAutoMergeNotEnabled when the repository setting is disabled.

func (*Client) EnqueuePullRequest added in v0.0.71

func (c *Client) EnqueuePullRequest(owner, repo string, prNumber int, expectedHeadOID string) error

EnqueuePullRequest adds a pull request to the repository's merge queue. expectedHeadOID is the current head SHA of the PR; if the PR has been force-pushed since the caller read the SHA, the mutation fails safely (optimistic concurrency).

Uses the same two-step pattern as MarkPRReady: fetch the PR node ID via GraphQL, then call the enqueuePullRequest mutation.

func (*Client) FetchCheckRuns

func (c *Client) FetchCheckRuns(owner, repo, sha string) ([]CheckRun, error)

FetchCheckRuns retrieves check runs for a given commit SHA via the REST API.

func (*Client) FetchCombinedStatus added in v0.0.76

func (c *Client) FetchCombinedStatus(owner, repo, ref string) ([]CommitStatus, error)

FetchCombinedStatus retrieves classic commit statuses for a ref via the combined-status REST endpoint. This is the only Fabrik-side visibility into a required status posted via the classic Statuses API rather than a GitHub Actions check run (e.g. a local-CI-takeover repo's own commit-status producer) — see #933. Needs only pull access (the same `repo` scope Fabrik already requires), unlike reading branch protection directly.

func (*Client) FetchCommitsBehind added in v0.0.68

func (c *Client) FetchCommitsBehind(owner, repo, base, head string) (int, error)

FetchCommitsBehind returns how many commits base is ahead of head using the GitHub compare API. A positive result means head is that many commits behind base. Returns 0, nil when head is up to date.

func (*Client) FetchIssue

func (c *Client) FetchIssue(owner, repo string, issueNumber int) (*IssueData, error)

FetchIssue retrieves a single issue via the REST API.

func (*Client) FetchIssueComments added in v0.0.76

func (c *Client) FetchIssueComments(owner, repo string, issueNumber int) ([]Comment, error)

FetchIssueComments fetches the comments on an issue (or PR, since PRs are issues on the REST API) via GET /issues/{n}/comments, including each comment's reaction summary. Used by Pruefer to detect on-demand "/pruefer review" comment commands and apply 👀/🚀 reaction idempotency. Returns nil, nil on 404.

func (*Client) FetchItemDetails

func (c *Client) FetchItemDetails(item *ProjectItem) error

FetchItemDetails populates the Comments, Labels, Body, URL, Author, Assignees, BlockedBy, and (Issue-typed items only) IsClosed fields of a ProjectItem by fetching full item data via individual node queries. This is the "deep" phase of the two-phase fetch approach. If item.Number is zero (e.g., for projects_v2_item.created with only a node_id), it is populated from the GraphQL response.

func (*Client) FetchLabelAppliedAt

func (c *Client) FetchLabelAppliedAt(owner, repo string, issueNumber int, labelName string) (time.Time, error)

FetchLabelAppliedAt returns the time when labelName was last applied to the given issue, using the GitHub issue events API. Returns time.Time{} (zero) without error if the event is not found (fail-open: timeout will not fire). Pages through all events to find the most recent application.

func (*Client) FetchLabels

func (c *Client) FetchLabels(owner, repo string, issueNumber int) ([]string, error)

FetchLabels returns the current labels on an issue.

func (*Client) FetchLatestRelease

func (c *Client) FetchLatestRelease(owner, repo string) (*LatestRelease, error)

FetchLatestRelease calls GET /repos/{owner}/{repo}/releases/latest and returns the tag name and asset list. Returns an error if the request fails or returns a non-2xx status.

func (*Client) FetchLinkedPR

func (c *Client) FetchLinkedPR(owner, repo string, issueNumber int) (*PRDetails, error)

FetchLinkedPR finds the PR linked to an issue by searching for a PR with the head branch fabrik/issue-N (Fabrik's naming convention). Returns nil, nil if no PR is found.

func (*Client) FetchPRClosingIssues

func (c *Client) FetchPRClosingIssues(owner, repo string, prNumber int) ([]int, error)

FetchPRClosingIssues returns the issue numbers referenced by GitHub closing keywords (Closes, Fixes, Resolves + #N) in the body of the given pull request. Only same-repo references are returned; cross-repo references are out of scope. Returns nil, nil on 404 or when the PR body contains no recognized closing references.

func (*Client) FetchPRDetails

func (c *Client) FetchPRDetails(owner, repo string, prNumber int) (*PRDetails, error)

FetchPRDetails retrieves a single pull request via the REST API.

func (*Client) FetchPRDiff added in v0.0.76

func (c *Client) FetchPRDiff(owner, repo string, prNumber int) (string, error)

FetchPRDiff fetches the raw unified diff for a pull request via GitHub's diff media type, avoiding a local clone just to measure or inspect diff size. Returns the diff as plain text.

func (*Client) FetchPRMergeable

func (c *Client) FetchPRMergeable(owner, repo string, prNumber int) (*bool, error)

FetchPRMergeable returns GitHub's mergeable flag for a single PR.

The returned pointer is nil when GitHub has not yet computed mergeability (the field is null on the REST response); callers should treat this as "unknown — try again on the next poll". A non-nil *false indicates a confirmed conflict with the base branch.

Only the single-PR endpoint (/pulls/{number}) returns this field reliably; the list endpoint used by FetchLinkedPR does not.

func (*Client) FetchPRMergeableFields added in v0.0.70

func (c *Client) FetchPRMergeableFields(owner, repo string, prNumber int) (mergeable *bool, mergeableState string, err error)

FetchPRMergeableFields fetches both the mergeable flag and mergeable_state for a single PR in one REST call, eliminating the read-after-write window that existed when the two fields were fetched separately by different gate functions.

Returns (nil, "", nil) when mergeable is null (GitHub still computing).

func (*Client) FetchPRMergeableState

func (c *Client) FetchPRMergeableState(owner, repo string, prNumber int) (string, error)

FetchPRMergeableState returns GitHub's branch-protection-aware mergeable_state for a single PR (e.g. "clean", "unstable", "blocked", "behind", "dirty", "draft", "has_hooks", "unknown"). Used by Fabrik's CI gate as the authoritative signal for whether non-required check_run failures should block a merge.

Returns "" when GitHub has not yet computed it. Only the single-PR endpoint returns this field reliably; the list endpoint used by FetchLinkedPR omits it (returns null).

func (*Client) FetchPRMerged added in v0.0.70

func (c *Client) FetchPRMerged(owner, repo string, prNumber int) (bool, error)

FetchPRMerged returns GitHub's authoritative `merged` flag for a single PR.

Only the single-PR endpoint (/pulls/{number}) reports `merged` reliably. The list endpoint used by FetchLinkedPR returns merged=false for several seconds after a merge (and is generally unreliable for this field), so a PR the engine just merged briefly looks like state=closed, merged=false there. Use this to confirm whether a PR observed as closed was actually merged before treating it as "closed without merging".

func (*Client) FetchPRReviewDecision added in v0.0.76

func (c *Client) FetchPRReviewDecision(owner, repo string, prNumber int) (string, error)

FetchPRReviewDecision returns GitHub's computed review-decision verdict for a pull request via GraphQL, keyed on PR number — mirroring prNodeID's single-field-by-number query shape rather than closedByPullRequestsReferences, so it works identically for default-branch and base:<branch> PRs (GitHub's REST API has no equivalent field; reviewDecision is GraphQL-only).

Returns one of "APPROVED", "CHANGES_REQUESTED", "REVIEW_REQUIRED" when the repository has a branch-protection review requirement configured for this PR, or "" when GitHub reports no such requirement (reviewDecision is null) — callers must treat "" as "no real verdict available", not as a satisfied gate. Returns an error (rather than "") when the query resolves with no pullRequest object at all (bad prNumber, or an app-token permission gap) — that is "unknown state", distinct from a legitimate null reviewDecision, and must not be folded into the same "" the no-branch-protection fallback treats as meaningful data.

func (*Client) FetchPRReviewRequests added in v0.0.75

func (c *Client) FetchPRReviewRequests(owner, repo string, prNumber int) ([]ReviewRequest, error)

FetchPRReviewRequests returns the outstanding requested reviewers for a pull request via the REST API, keyed on PR number — the base-independent counterpart to the GraphQL-nested reviewRequests field. Team review requests are ignored, matching the GraphQL path's existing behavior (only individual reviewers map to ReviewRequest). IsBot reproduces the GraphQL path's dual signal: REST's user.type == "Bot" field, with the isBotLogin pattern fallback for reviewers (e.g. dependabot) that GitHub doesn't mark with type "Bot". Returns nil, nil on 404.

func (*Client) FetchPRReviews added in v0.0.75

func (c *Client) FetchPRReviews(owner, repo string, prNumber int) ([]PRReview, error)

FetchPRReviews returns the latest submitted review per author for a pull request via the REST API, keyed on PR number rather than closedByPullRequestsReferences — the field GitHub leaves structurally empty for PRs targeting a non-default base branch. This is the base-independent counterpart to the GraphQL-nested latestReviews field, mirroring FetchPRClosingIssues's REST-by-PR-number precedent (see #1047). The REST endpoint returns the full review history — every submission, unlimited per author — so results are collapsed to one entry per author (the most recent submission, per GitHub's chronological response order) to match latestReviews' semantics; otherwise an author's earlier non-DISMISSED review (e.g. a stale COMMENTED review) could outlive a later dismissal of their actual current review and falsely satisfy the review-gate's hasReviews check.

A COMMENTED submission never supersedes a prior formal verdict (APPROVED, CHANGES_REQUESTED, or DISMISSED) from the same author — GitHub's own reviewDecision computation treats COMMENTED as informational, not a state transition, so a reviewer who requests changes and later leaves a comment-only follow-up (without re-approving or dismissing) still has an active CHANGES_REQUESTED verdict. Only when an author's *first* submission is COMMENTED (no verdict established yet) does it become their collapsed entry. Returns nil, nil on 404.

func (*Client) FetchPRsForSHA

func (c *Client) FetchPRsForSHA(owner, repo, sha string) ([]int, error)

FetchPRsForSHA returns the PR numbers associated with the given commit SHA via GET /repos/{owner}/{repo}/commits/{sha}/pulls. Returns nil, nil on 404 or empty.

func (*Client) FetchProjectBoard

func (c *Client) FetchProjectBoard(owner, repo string, projectNum int, ownerType string) (*ProjectBoard, error)

FetchProjectBoard pulls the project board with shallow item data (no comments or linked PRs). Use FetchItemDetails to populate comments for specific items. This two-phase approach dramatically reduces GraphQL rate limit cost.

When ownerType is non-empty ("user" or "organization"), the board is fetched directly using that type, skipping the try-org-then-user fallback. When ownerType is empty, the original fallback behavior is preserved.

func (*Client) FetchProjectItem

func (c *Client) FetchProjectItem(owner, repo string, issueNumber int) (*ProjectItem, error)

FetchProjectItem fetches a minimal ProjectItem for an issue via REST GET /repos/{owner}/{repo}/issues/{number}. Used by the boardcache fallback path when a webhook event arrives for an issue not yet in the cache.

func (*Client) FetchProjectItemStatus

func (c *Client) FetchProjectItemStatus(itemID string) (string, error)

FetchProjectItemStatus fetches only the Status field value for a single project item identified by its node ID (PVTI_...). Returns "" when no status is set.

func (*Client) FetchProjectItemStatusBatch

func (c *Client) FetchProjectItemStatusBatch(projectID string) (map[string]string, error)

FetchProjectItemStatusBatch fetches a map of projectItemNodeID → statusName for every item in the project. Dramatically cheaper than FetchProjectBoard because it fetches no nested fields. Paginates identically to fetchProjectBoardOnce.

func (*Client) FetchProjectUpdatedAt

func (c *Client) FetchProjectUpdatedAt(projectID string) (time.Time, error)

FetchProjectUpdatedAt returns the updatedAt timestamp for the given project node ID. Used as a cheap gate in the poll loop to skip the full status batch when the project hasn't changed since the last cycle.

func (*Client) FetchRepoAccess added in v0.0.77

func (c *Client) FetchRepoAccess(owner, repo string) (RepoAccess, error)

FetchRepoAccess calls GET /repos/{owner}/{repo} and returns the allow_auto_merge setting alongside the authenticated token's push access (permissions.push) — both decoded from the same response, so this adds no extra API round-trip beyond what the allow_auto_merge check already required. Returns an error if the request fails.

func (*Client) FetchStatusField

func (c *Client) FetchStatusField(projectID string) (*StatusField, error)

FetchStatusField retrieves the Status field ID and its option IDs for a project.

func (*Client) FindPRForIssue

func (c *Client) FindPRForIssue(owner, repo string, issueNumber int) (int, error)

FindPRForIssue finds the PR associated with an issue by looking for a PR whose head branch matches the fabrik/issue-N convention. Returns the PR number, or 0 if no matching PR is found.

Uses FetchLinkedPR internally, which hits the core REST pulls endpoint (/repos/{owner}/{repo}/pulls?head=...). Previously this used the GitHub search API (/search/issues) which has a 30/minute rate limit — heavy polling exhausted that quota. Core REST has a 5000/hour limit, ~167x more headroom.

func (*Client) GetIssueBody

func (c *Client) GetIssueBody(owner, repo string, issueNumber int) (string, error)

GetIssueBody fetches the body of an issue (or PR, since PRs are issues on the REST API).

func (*Client) GetPRBase

func (c *Client) GetPRBase(owner, repo string, prNumber int) (string, error)

GetPRBase fetches the current base branch reference of an open pull request. Returns the base branch name (e.g. "main" or "feature/foo"), or an error if the API call fails.

func (*Client) ListOpenPRs added in v0.0.76

func (c *Client) ListOpenPRs(owner, repo string) ([]PRDetails, error)

ListOpenPRs returns all open pull requests for a repository (draft and non-draft), including author and label metadata needed for Pruefer's PR selection logic. Capped at 100 results (GitHub's max per_page); a warning is logged (not silently truncated) when exactly 100 are returned, since more open PRs may exist.

func (*Client) ListPRs added in v0.0.71

func (c *Client) ListPRs(owner, repo string) ([]PRDetails, error)

ListPRs returns recent pull requests (open and closed) for a repository, including their body text. Capped at the 50 most-recently-updated PRs. Used for idempotency detection (e.g. finding an existing integration PR).

func (*Client) LookupIssueProjectItem

func (c *Client) LookupIssueProjectItem(projectID, repo string, issueNumber int) (itemID string, status string, err error)

LookupIssueProjectItem fetches the project-item node ID and current Status for a given issue, filtered to the specified projectID. It queries repository.issue.projectItems (first: 20), iterating nodes until one whose project.id matches projectID is found. Returns ("", "", nil) when the issue is not in the specified project. Returns an error on any GraphQL failure.

Note: first:20 covers issues in up to 20 GitHub Projects. Issues belonging to more than 20 projects are not supported (vanishingly rare in practice).

func (*Client) MarkPRReady

func (c *Client) MarkPRReady(owner, repo string, prNumber int) error

MarkPRReady transitions a draft PR to ready-for-review. Uses the GraphQL markPullRequestReadyForReview mutation, which is the supported path — REST PATCH does not reliably support draft→ready transitions.

func (*Client) MergePR

func (c *Client) MergePR(owner, repo string, prNumber int) error

MergePR merges the pull request identified by prNumber. It first checks GitHub's mergeable status: if null (not yet computed) or false, it returns ErrNotMergeable. It then self-gates on CI readiness — regardless of what branch protection would otherwise allow (e.g. enforce_admins: false) — by fetching mergeable_state via FetchPRMergeableFields and refusing with ErrNotMergeableCI unless the state is in the MergeableStateAccepted allowlist ({clean, unstable}); see ADR-072. Only then does it attempt the configured merge strategy (see SetMergeStrategy) first; if the repository does not allow that method (405), it falls back through the remaining methods (merge, squash, rebase, minus the one already tried) until one succeeds or a non-405 error occurs.

func (*Client) MergeStrategy added in v0.0.76

func (c *Client) MergeStrategy() string

MergeStrategy returns the currently configured merge strategy, safe for concurrent use alongside SetMergeStrategy.

func (*Client) ProbeProjectBoard

func (c *Client) ProbeProjectBoard(owner, repo string, projectNum int, ownerType string) ([]BoardProbeItem, string, error)

ProbeProjectBoard fetches a minimal probe of the project board — only scalar identity fields and one linked-PR node per item, no labels. Used by the per-poll refresh path to detect updatedAt drift without the GraphQL cost of labels(first:30) and closedByPullRequestsReferences(first:5).

Returns []BoardProbeItem (one per non-draft item), the projectID string, and any error. Items whose content node ID is empty (draft issues) are skipped.

When ownerType is non-empty ("user" or "organization"), the board is fetched directly using that type, skipping the try-org-then-user fallback.

func (*Client) RateLimitStats

func (c *Client) RateLimitStats() (rest, graphql RateLimitStats)

RateLimitStats returns the most recently observed REST and GraphQL rate limit stats.

func (*Client) RemoveLabelFromIssue

func (c *Client) RemoveLabelFromIssue(owner, repo string, issueNumber int, labelName string) error

RemoveLabelFromIssue removes a label from an issue.

func (*Client) ResolveReviewThread

func (c *Client) ResolveReviewThread(threadID string) error

ResolveReviewThread marks a PR review thread as resolved ("Resolve conversation" in the GitHub UI). threadID is the GraphQL node ID of the thread (available via ProjectItem.LinkedPRReviewThreadComments[*].ReviewThreadID).

func (*Client) SeedLabels

func (c *Client) SeedLabels(owner, repo string, stageNames []string, lockedUser string) error

SeedLabels ensures all known Fabrik labels exist on the given repo. It enforces the correct color on existing labels and backfills empty descriptions. Non-empty descriptions are never overwritten. stageNames is the list of stage names from the loaded config; lockedUser is the current Fabrik user. Returns ErrNoRepoConfigured when repo is empty. Per-label failures are logged internally and do not cause an early return.

func (*Client) SetMergeStrategy added in v0.0.76

func (c *Client) SetMergeStrategy(strategy string)

SetMergeStrategy configures the merge method MergePR attempts first ("MERGE", "SQUASH", or "REBASE", case-insensitive). An empty string leaves MergePR defaulting to "merge". Safe to call concurrently with MergePR.

func (*Client) SetToken added in v0.0.76

func (c *Client) SetToken(token string)

SetToken replaces the client's bearer token. Safe to call concurrently with in-flight requests. Needed by Pruefer's GitHub App installation-token refresh loop, where the token expires roughly hourly and must be swapped in place without reconstructing the client (see ADR-1113).

func (*Client) SubmitPRReview added in v0.0.76

func (c *Client) SubmitPRReview(owner, repo string, prNumber int, commitSHA, body string, event ReviewEvent, comments []ReviewComment) (int, error)

SubmitPRReview submits a formal pull_request_review comment against the given commit SHA, optionally with line-anchored inline comments posted in the same request. event selects COMMENT vs REQUEST_CHANGES — computed Go-side by the caller (see ReviewEvent's doc comment), never derived from Claude's output text. There is no APPROVE path: only a ReviewEvent whose internal string is exactly "REQUEST_CHANGES" escapes the "COMMENT" default below, so even an unexpected/zero ReviewEvent value degrades to the non-blocking event rather than approving or erroring. Each comment's side is likewise hardcoded to "RIGHT" — V1 supports only single-line, post-change-side anchors (see adrs/1189-pruefer-inline-review-comments.md). The "comments" key is omitted entirely when comments is empty, preserving the exact body-only wire shape callers relied on before that parameter existed. Returns the numeric review ID.

func (*Client) Token added in v0.0.76

func (c *Client) Token() string

Token returns the client's current bearer token, safe for concurrent use alongside SetToken.

func (*Client) UpdateComment

func (c *Client) UpdateComment(owner, repo string, commentDatabaseID int, body string) error

UpdateComment replaces the body of an existing issue comment.

func (*Client) UpdateIssueBody

func (c *Client) UpdateIssueBody(owner, repo string, issueNumber int, body string) error

UpdateIssueBody updates the body of an issue.

func (*Client) UpdatePRBase

func (c *Client) UpdatePRBase(owner, repo string, prNumber int, newBase string) error

UpdatePRBase changes the base branch of an open pull request via the GitHub REST API. GitHub accepts base-branch changes on open PRs; the PR may become unmergeable if the head and new base have diverged, but the API call itself succeeds.

func (*Client) UpdateProjectItemStatus

func (c *Client) UpdateProjectItemStatus(projectID, itemID, statusFieldID, statusOptionID string) error

UpdateProjectItemStatus moves an item to a different status column on the project board.

type Comment

type Comment struct {
	ID         string
	DatabaseID int // Numeric ID needed for REST API (reactions, etc.)
	Author     string
	Body       string
	CreatedAt  time.Time
	Reactions  []ReactionGroup
	FromPR     int // Non-zero if this comment is from a linked PR
	// ReviewThreadID is the GraphQL node ID of the PR review thread this
	// comment belongs to. Empty for non-review-thread comments. Needed to
	// call resolveReviewThread after the feedback is addressed.
	ReviewThreadID string
	// Path is the file path targeted by the PR review thread comment.
	// Empty for regular issue and PR body comments.
	Path string
	// Line is the line number in the current diff. Zero when not applicable
	// (e.g., regular comments) or when the comment targets a deleted line.
	Line int
	// OriginalLine is the line number in the original base diff. Used as a
	// fallback when Line is 0. Zero when not applicable.
	OriginalLine int
	// DiffHunk is the diff context hunk surrounding the comment. Empty for
	// regular issue and PR body comments.
	DiffHunk string
	// IsOutdated mirrors the parent review thread's GitHub-computed isOutdated
	// field: true when the commented lines have been superseded by a later
	// push to the PR (the thread's diff no longer matches the current head).
	// Only meaningful for review-thread comments (ReviewThreadID non-empty).
	IsOutdated bool
}

Comment represents a comment on an issue or linked PR.

func (Comment) HasReaction

func (c Comment) HasReaction(content string) bool

HasReaction returns true if the comment has at least one reaction of the given type.

type CommitStatus added in v0.0.76

type CommitStatus struct {
	Context string
	State   string // "success", "pending", "failure", "error"
}

CommitStatus is a single classic Commit Status (Statuses API) entry, as reduced by the combined-status endpoint to one entry per distinct context (GitHub itself keeps only the most recent status per context there — no client-side dedup is needed, unlike check runs).

type Dependency

type Dependency struct {
	Number int    // Issue number of the blocking issue
	State  string // "OPEN" or "CLOSED" (GitHub GraphQL enum)
	Repo   string // "owner/repo" of the blocking issue; empty if same repo
}

Dependency represents a blocking issue relationship fetched from the GitHub API.

type IssueData

type IssueData struct {
	Number   int
	Title    string
	State    string
	Labels   []string
	Comments int
}

IssueData holds the fields from a GitHub issue needed by fabrik watch.

type LatestRelease

type LatestRelease struct {
	TagName string         `json:"tag_name"`
	Assets  []ReleaseAsset `json:"assets"`
}

LatestRelease represents the response from GET /repos/{owner}/{repo}/releases/latest.

type MergeQueueEntry added in v0.0.71

type MergeQueueEntry struct {
	State         string // e.g. "QUEUED", "AWAITING_CHECKS", "MERGEABLE", "UNMERGEABLE"
	Position      int    // 1-indexed position in the queue; 0 when not yet positioned
	EnqueuerLogin string // GitHub login of the user who enqueued the PR
}

MergeQueueEntry holds the merge-queue position and state for a pull request. The pointer on ProjectItem and PRDetails is nil when no merge queue entry exists.

type PRDetails

type PRDetails struct {
	Number  int
	Title   string
	State   string // "open", "closed"
	Merged  bool
	Draft   bool
	HeadSHA string
	// HeadRefName is the PR's head branch name (e.g. "fabrik/merge-train/…").
	// Populated by ListPRs (from head.ref); other constructors may leave it empty.
	HeadRefName string
	Body        string
	// MergeableState reflects GitHub's branch-protection-aware mergeable
	// status: "clean" (ready to merge), "unstable" (non-required checks
	// failing but still mergeable), "blocked" (required checks pending or
	// failing), "behind" (head is out of date with base), "dirty" (merge
	// conflict), "draft" (PR is a draft), "has_hooks" (clean but hooks
	// will run on merge), "unknown" (not yet computed). Used by Fabrik's
	// CI gate as the authoritative signal — non-required check_run
	// failures (e.g., workflow cleanup jobs) do not block "clean"/"unstable".
	MergeableState string
	// AutoMergeEnabled is true when GitHub's native auto-merge is enabled on
	// the PR (auto_merge field is non-null). False when the user or engine
	// has disabled it, or when it was never enabled.
	AutoMergeEnabled bool

	// IsMergeQueueEnabled is true when the repository has the merge queue feature
	// enabled. Always false when populated via REST (GraphQL-only field).
	IsMergeQueueEnabled bool
	// IsInMergeQueue is true when the PR is currently in the merge queue.
	// Always false when populated via REST (GraphQL-only field).
	IsInMergeQueue bool
	// MergeQueueEntry holds the queue position and state when the PR is enqueued.
	// Nil when not in queue or populated via REST. Pointer because GitHub returns
	// null after dequeueing and Go's json decoder maps null to nil only on pointers.
	MergeQueueEntry *MergeQueueEntry

	// Author is the GitHub login of the PR's author. Populated by ListPRs and
	// ListOpenPRs; other constructors may leave it empty.
	Author string
	// Labels is the list of label names applied to the PR. Populated by ListPRs
	// and ListOpenPRs; other constructors may leave it empty.
	Labels []string
	// BaseRef is the PR's base branch name (e.g. "main"). Populated by
	// ListOpenPRs; other constructors may leave it empty.
	BaseRef string
}

PRDetails holds the fields from a GitHub pull request needed by fabrik watch.

type PRReview

type PRReview struct {
	Author     string // GitHub login of the reviewer
	State      string // "APPROVED", "CHANGES_REQUESTED", or "COMMENTED"
	Body       string // Review summary body (may be empty for comment-only reviews)
	DatabaseID int    // Numeric PR review ID (0 if not fetched or unavailable)
	// CommitID is the SHA the review was submitted against (GitHub's REST
	// "commit_id" field). Needed to determine whether a review targets the
	// PR's current head SHA or a stale one (Pruefer's GitHub-derived
	// review-state mechanism; see ADR-1113).
	CommitID string
	// SubmittedAt is when the review was submitted (GraphQL "submittedAt" /
	// REST "submitted_at"). Zero value if unparseable or absent — callers
	// needing a display timestamp (e.g. buildReviewBodyComments, #1375) must
	// fall back rather than assume this is always populated.
	SubmittedAt time.Time
}

PRReview represents a submitted review on a pull request.

type ProjectBoard

type ProjectBoard struct {
	ProjectID string
	Title     string // display name of the project board (from projectV2.title)
	OwnerType string // "organization" or "user", resolved by FetchProjectBoard
	Items     []ProjectItem
}

ProjectBoard represents the full state of a GitHub Project (v2) board.

type ProjectItem

type ProjectItem struct {
	ID             string
	ItemID         string // The project item ID (needed for mutations)
	Number         int
	Title          string
	Body           string
	Status         string // The column/status on the board
	URL            string
	Repo           string // "owner/repo" (e.g., "acme/widgets")
	IsPR           bool   // True if this item is a Pull Request (vs an Issue)
	IsClosed       bool   // True if the underlying GitHub Issue is closed (always false for PRs)
	UpdatedAt      time.Time
	Labels         []string
	Assignees      []string
	Comments       []Comment
	Author         string
	BlockedBy      []Dependency // Issues that must be closed before this one can advance
	LinkedPRNumber int          // PR number of the first linked PR (0 if none); for REST re-request calls
	// LinkedPRNumberShallow is the PR number of the first linked PR from the shallow board query (0 if none).
	// Populated only during shallow board parse. Linkage drift detection was previously performed
	// by Reconcile using this field; that responsibility has moved to the probe loop
	// (runProbeAndDeepFetch via BoardProbeItem.LinkedPRNumber). Retained for compatibility; no longer
	// read by Reconcile.
	LinkedPRNumberShallow  int
	LinkedPRHeadSHA        string          // HeadSHA from headRefOid in the GraphQL query (empty if not fetched)
	LinkedPRReviewRequests []ReviewRequest // Outstanding reviewer requests on the linked PR
	LinkedPRReviews        []PRReview      // Reviews already submitted on the linked PR
	// LinkedPRReviewThreadComments holds the inline (per-line) comments from
	// unresolved review threads on the linked PR. These are real GitHub
	// comments with DatabaseIDs and can be reacted to / resolved.
	LinkedPRReviewThreadComments []Comment
	// LinkedPRResolvedThreadCount is the number of review threads on the linked PR
	// that are currently resolved. Used by progress detection during turn extension.
	LinkedPRResolvedThreadCount int

	// LinkedPRIsMergeQueueEnabled is true when the repository has the merge queue
	// feature enabled. Zero (false) when no queue exists or the field was not fetched.
	LinkedPRIsMergeQueueEnabled bool
	// LinkedPRIsInMergeQueue is true when the linked PR is currently in the merge queue.
	LinkedPRIsInMergeQueue bool
	// LinkedPRMergeQueueEntry holds the queue position and state when the PR is
	// enqueued. Nil when the PR is not in the queue or mergeQueueEntry was null.
	LinkedPRMergeQueueEntry *MergeQueueEntry
}

ProjectItem represents an issue or pull request card on the project board.

type RateLimitStats

type RateLimitStats struct {
	Limit     int
	Remaining int
	Used      int
	Reset     time.Time
	UpdatedAt time.Time
}

RateLimitStats holds the latest GitHub API rate limit values parsed from response headers.

type ReactionGroup

type ReactionGroup struct {
	Content string // e.g. "THUMBS_UP", "EYES", etc.
	Count   int
}

ReactionGroup represents a reaction type and its count on a comment.

type ReleaseAsset

type ReleaseAsset struct {
	Name               string `json:"name"`
	BrowserDownloadURL string `json:"browser_download_url"`
	APIURL             string `json:"url"` // API URL for downloading with Accept: application/octet-stream
	Size               int64  `json:"size"`
}

ReleaseAsset represents a single downloadable asset in a GitHub release.

type RepoAccess added in v0.0.77

type RepoAccess struct {
	AllowAutoMerge bool
	CanPush        bool
}

RepoAccess captures the write-access-relevant fields from GET /repos/{owner}/{repo} for the authenticated token. CanPush reflects permissions.push on that response.

type RequiredContextStatus added in v0.0.76

type RequiredContextStatus int

RequiredContextStatus classifies whether every configured required status context has been confirmed successful on a given head SHA.

const (
	// RequiredContextsSatisfied means every configured required context name
	// resolved to a confirmed success on the head SHA — or no required
	// contexts are configured for the repo at all (the zero value, so every
	// caller that never touches required-context config gets this for free).
	RequiredContextsSatisfied RequiredContextStatus = iota
	// RequiredContextsPending means at least one required context has not yet
	// reported a confirmed outcome: missing entirely, still queued/in_progress/
	// pending, or reported skipped/neutral. None of these are a regression —
	// they just haven't produced a confirmed pass yet.
	RequiredContextsPending
	// RequiredContextsFailed means at least one required context reported a
	// confirmed failure (a check run conclusion of failure/timed_out/
	// action_required, or a commit status state of failure/error).
	RequiredContextsFailed
)

func ClassifyRequiredContexts added in v0.0.76

func ClassifyRequiredContexts(required []string, checkRuns []CheckRun, statuses []CommitStatus) (status RequiredContextStatus, missing, pending, failed []string)

ClassifyRequiredContexts checks each name in required against the union of check-run names and commit-status contexts observed on the exact head SHA the caller fetched checkRuns/statuses for. Only a confirmed success (a check-run conclusion of "success", or a commit-status state of "success") counts as satisfied for that name — a skipped/neutral/absent/pending producer never does, even though ClassifyCheckRuns alone would treat skipped/neutral as "ready". This is what closes the local-CI-takeover hole: a required classic commit status that never posted for the new head must block, not silently pass.

required with no configured entries always resolves to RequiredContextsSatisfied — this function is a no-op for repos that have not configured required_status_contexts, preserving today's permissive behavior for the common vanilla-GHA case.

type ReviewComment added in v0.0.76

type ReviewComment struct {
	Path string
	Line int
	Body string
}

ReviewComment is a single line-anchored inline comment to submit as part of a pull_request_review's comments[] array (outbound request shape only — narrower than Comment, which carries response-only fields like ID/Author/ ReviewThreadID that don't apply to a submission). Line anchors the RIGHT (post-change) side only; SubmitPRReview hardcodes "side": "RIGHT" — see adrs/1189-pruefer-inline-review-comments.md.

type ReviewEvent added in v0.0.76

type ReviewEvent struct {
	// contains filtered or unexported fields
}

ReviewEvent selects the wire "event" value SubmitPRReview submits. Its field is unexported so no package outside github can construct an arbitrary value — the only way to obtain a ReviewEvent is to copy one of the two values below (or receive the zero value). This is what makes "no APPROVE, ever" a compile-time property rather than a convention: even a future in-package mistake can't smuggle an arbitrary string through, and SubmitPRReview itself additionally normalizes defensively (see below), so the guarantee holds even against a hypothetical bug in this very type's definition. See adrs/1251-pruefer-severity-gated-request-changes.md.

type ReviewRequest

type ReviewRequest struct {
	Login string // GitHub login of the requested reviewer (user or bot)
	IsBot bool   // True if the reviewer is a bot (from __typename or login-pattern fallback)
}

ReviewRequest represents a pending review request on a pull request.

type SearchResult

type SearchResult struct {
	Items []struct {
		Number int `json:"number"`
	} `json:"items"`
}

SearchResult represents the response from GitHub's search API.

type StatusField

type StatusField struct {
	FieldID            string
	Options            map[string]string // status name -> option ID
	OrderedOptionNames []string          // option names in API-returned order (first = leftmost column)
}

StatusField holds the Status field metadata for a project.

Jump to

Keyboard shortcuts

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