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

github

package
v0.1.0 Latest Latest
Warning

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

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

Documentation

Overview

Package github implements pkg/forge.Forge against the real GitHub REST API, using github.com/cli/go-gh/v2 (AGENTS.md §4.7's one sanctioned new dependency for M3 — not google/go-github, not a hand-rolled REST client, not the full gh CLI as a library). New resolves credentials exactly the way the gh CLI itself would (its own keyring/config, via go-gh's api.DefaultRESTClient): this package never reads a token from a flag or an environment variable of its own invention, and never sees the token value directly — go-gh sets the Authorization header inside its own HTTP transport (AGENTS.md §4.3, R-002).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

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

Client implements forge.Forge against api.github.com (or a GitHub Enterprise host, via the gh environment's own resolution — this package does not special-case it).

func New

func New(ownerRepo string) (*Client, error)

New builds a Client for ownerRepo ("owner/name", RepoConfig.GitHub), authenticating through the user's own `gh` login exactly as the gh CLI would.

func (*Client) BlameLines

func (c *Client) BlameLines(ctx context.Context, ref, path string, lines []int) (map[int]forge.LineOrigin, error)

BlameLines implements forge.Forge via GraphQL. A nil object means ref does not resolve in this repo; that is reported as forge.ErrUnknownRef so pkg/migrate can fall back to the base branch and mark the age approximate, rather than as a scope failure. Requires a GraphQL client: a Client built through newWithClient alone (the M3 test seam) reports that it has none rather than dereferencing nil.

func (*Client) Checks

func (c *Client) Checks(ctx context.Context, sha string) (forge.CheckSummary, error)

Checks implements forge.Forge: the check-run rollup CIGreenStep gates on (M4), paged through every page of check-runs GitHub reports for sha (Known bug classes: "only page 1 of a check-run set is fetched" — a commit with more than 100 check runs would otherwise silently hide a pending or failed run past the first page, and CI could appear green when it isn't). FailedNames names every check-run that concluded in something other than success/neutral/skipped; SkippedNames separately names every run that concluded `skipped`, which forge.CheckSummary's own doc comment explains is never folded into Success. A run's own name is upstream text nothing here wrote (a CI system can name a job anything), so both name lists go through redact.Strings at this adaptor boundary the same way translateErr already does for GitHub's own free-form error messages (AGENTS.md invariant 6).

func (*Client) Comments

func (c *Client) Comments(ctx context.Context, prNumber int, since time.Time) ([]forge.Comment, error)

Comments implements forge.Forge: PR conversation comments (GitHub models these as issue comments), newer than since, with AuthorType carrying the API's own account "type" through (M4: internal/engine.ApprovedStep is what actually enforces R-001's author check against it, against the API's login field, never the comment body — see that package's doc comment for why enforcement lives there and not here). Bots (Type == "Bot") are additionally excluded here too, as a politeness layer only (AGENTS.md §8 "layered checks": deleting this filter would not change what a correctly-written ApprovedStep accepts, only which layer reports it). This deliberately excludes only "Bot", not "anything other than User": GitHub's account "type" field also has legitimate non-"User" values such as "Organization" (an org-owned account, not a bot), and the set of values isn't closed, so filtering on Type != "User" would silently drop a real, non-bot commenter along with actual bots.

Paged through every page GitHub reports (Known bug classes: "only page 1 of a PR's comments is fetched" — a PR with more than 100 comments could otherwise hide an approval or a later reject past the first page, so ApprovedStep's newest-match scan would never see it).

func (*Client) CommitFiles

func (c *Client) CommitFiles(ctx context.Context, sha string) ([]string, bool, error)

CommitFiles implements forge.Forge: GET .../commits/{sha}, whose files[] pages at 100 like everything else here and is capped by GitHub at githubFilesCap in total.

func (*Client) CommitsTouching

func (c *Client) CommitsTouching(ctx context.Context, ref, path string, since time.Time) ([]string, error)

CommitsTouching implements forge.Forge: GET .../commits?sha={ref}&path={path}&since=…, newest first as GitHub orders it, paged to the same bound.

func (*Client) Compare

func (c *Client) Compare(ctx context.Context, base, head string) (forge.Comparison, error)

Compare implements forge.Forge: GET .../compare/{base}...{head}, paged. GitHub's total_commits is authoritative for the whole range regardless of paging, so Truncated is len(commits) < total rather than a sentinel request. The file list is only ever on page 1 and GitHub caps it at githubFilesCap; a full list is reported FilesTruncated. A 404 is forge.ErrUnknownRef, wrapped with the same scope hint translateErr gives — an unknown ref and a private repo the token cannot see are the same status code.

func (*Client) CreatePR

func (c *Client) CreatePR(ctx context.Context, spec forge.PRSpec) (forge.PR, error)

CreatePR implements forge.Forge.

func (*Client) FindPR

func (c *Client) FindPR(ctx context.Context, headBranch, bodyMarker string) (forge.PR, bool, error)

FindPR implements forge.Forge: first the exact head-branch match GitHub's own "head" filter gives for free, then — when a branch was renamed or recreated, so nothing shares its name anymore — a bounded scan of open, then closed, PRs for the body marker (Known bug classes: "Finding an existing PR only by branch name and missing one whose branch was renamed").

func (*Client) GetPR

func (c *Client) GetPR(ctx context.Context, number int) (forge.PR, bool, error)

GetPR implements forge.Forge: getPR with a 404 reported as ok=false rather than an error, since "no such PR" is an answer the caller falls back from, not a failure.

func (*Client) IsAllowedAuthor

func (c *Client) IsAllowedAuthor(ctx context.Context, login string) (bool, error)

IsAllowedAuthor implements forge.Forge: true for "admin", "maintain" or "write" — R-001's stated bar is "collaborator with write (or higher) permission" (forge.Forge's own doc comment), and GitHub ranks maintain strictly above write (admin > maintain > write > triage > read), so a maintain-level collaborator qualifies exactly like write and admin do; only "triage" and "read" fall below the bar. A 404 (login is not a collaborator — the ordinary case for a drive-by commenter on a public PR) is folded into (false, nil) rather than propagated as an error: treating it as fatal would make any non-collaborator's comment error and block the whole promotion whenever collaborators=true, rather than simply not counting as an approval.

func (*Client) MergePR

func (c *Client) MergePR(ctx context.Context, prNumber int, expectedHeadSHA string) (forge.PR, error)

MergePR implements forge.Forge: a squash merge, gated atomically on the server's own "sha" parameter (Known bug classes: "don't roll your own check-then-merge race") — a head that has moved since expectedHeadSHA was observed is refused with a 409, translated to forge.ErrStaleHead. Squash is always used, so a multi-commit branch's title would normally concatenate every commit subject; this promotion is guaranteed exactly one commit (M3), so that default composes to that one commit's own message, never a leak of unrelated history (Known bug classes, confirmed here rather than assumed).

func (*Client) ReadFile

func (c *Client) ReadFile(ctx context.Context, ref, path string) ([]byte, bool, error)

ReadFile implements forge.Forge: GET .../contents/{path}?ref=…, base64-decoded. A 404 is ok=false (the file is simply not there); a directory at that path is an error, since the caller asked for a file.

func (*Client) ResolveRef

func (c *Client) ResolveRef(ctx context.Context, ref string) (string, bool, error)

ResolveRef implements forge.Forge: GET .../commits/{ref}, the same endpoint Tags already uses to date a tag, which accepts a tag, a branch, or a sha prefix. 404 (no such ref) and 422 (an ambiguous prefix) are ok=false; anything else — a 403 in particular, the scope-gap signature — is an error, per the interface's own contract.

func (*Client) Tags

func (c *Client) Tags(ctx context.Context) ([]forge.GitTag, error)

Tags implements forge.Forge: every tag on the repo, with the date of the commit it points to. This is N+1 requests (one to list tags, one per tag to read its commit date — GitHub's tag-list endpoint reports a commit SHA but no date, and the M6 brief's own case for this method is exactly "the registry has no dates, the git history does") — acceptable for a single-operator tool's own app repos, bounded by maxTagPages, and only ever called when the tag picker actually needs ordering for a mapped image repo, not on every plan.

Jump to

Keyboard shortcuts

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