forge

package
v0.38.0 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package forge is the binding to a forge's CLI, gh or glab, and the reads more than one command shares: the pull requests a host lists, their commits, the checks on a commit. Every call to either CLI goes through Host: the spelling each wants is picked in one place, the JSON each returns is read into one shape per noun, and a non-zero exit is the CLI's own stderr, verbatim, since it names the cause better than any paraphrase. The command package wraps Host with the nouns only it acts on (issues, merges, reviews); standup and lookaround read through it.

Index

Constants

View Source
const (
	Open   = "open"
	Merged = "merged"
	Closed = "closed"
)

The three states a request can be in, whichever CLI spelled them.

View Source
const (
	OwnFields     = "number,title,state,isDraft,headRefName,baseRefName,url,author,createdAt,mergedAt,changedFiles,mergeCommit"
	ForeignFields = "number,title,state,url,author,mergedAt,mergedBy"
	BoardFields   = "number,title,state,isDraft,headRefName,baseRefName,headRefOid,url,author,assignees," +
		"reviewRequests,reviews,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup," +
		"createdAt,updatedAt,mergedAt,mergedBy,closedAt,body,mergeCommit"
)

The gh field sets: a person's own requests, other people's, and what a board wants to know about every request.

View Source
const (
	Approved         = "approved"
	ChangesRequested = "changes_requested"
	ReviewRequired   = "review_required"
	Commented        = "commented"

	Clean     = "clean"
	Conflicts = "conflicts"
	Blocked   = "blocked"

	Green   = "green"
	Red     = "red"
	Pending = "pending"
)

The vocabularies the host's words are read into.

View Source
const ForcePushesQuery = "query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) " +
	"{ pullRequest(number: $number) { timelineItems(last: 100, itemTypes: [HEAD_REF_FORCE_PUSHED_EVENT]) " +
	"{ nodes { ... on HeadRefForcePushedEvent { createdAt actor { login } beforeCommit { oid } afterCommit { oid } } } } } } }"

ForcePushesQuery is the GraphQL that lists a PR's force-pushes.

View Source
const PRLimit = 1000

PRLimit caps each gh search. Reaching it is an error rather than a report silently missing the rest.

Variables

This section is empty.

Functions

func DecodePages

func DecodePages[T any](ctx context.Context, h Host, path string) ([]T, error)

DecodePages runs a `api --paginate` call and reads every page into one list. gh merges the pages of an array into one array; glab may print one document per page, so every document in the output is read in turn.

func SameLogin

func SameLogin(declared, login string) bool

SameLogin matches a declared identity against a login the host returned, case-insensitive. A bare `claude` also matches `claude[bot]`, but a declared `claude[bot]` never matches a bare `claude`: only an app's login can carry the suffix, so dropping it on the host's side would let a user who registered the bare name post as the declared bot.

func Status

func Status(state string) string

Status normalises a request's state: gh spells them OPEN / MERGED / CLOSED, glab opened / merged / closed / locked.

Types

type CI

type CI struct {
	Red bool
	At  time.Time
}

CI is how the checks on a commit ended: Red when any failed, At the time of the last failure.

type ForcePush

type ForcePush struct {
	At     time.Time
	Before string
	After  string
	// SamePatches is whether every commit kept its patch, nil when git
	// cannot tell; the reader that owns the checkout fills it.
	SamePatches *bool
}

A ForcePush is one force-push to a PR: the head it replaced and the one it set.

type Host

type Host struct {
	Name string // "gh" or "glab"
	Dir  string // the checkout the CLI reads the remote from
	// Repo names the repository when there is no checkout to read it from:
	// `owner/repo`, or `host/owner/repo` off the CLI's default host. Set,
	// every command carries it: a noun command as -R, an api call with its
	// placeholders filled in.
	Repo string
}

A Host is one of the two forge CLIs, bound to the checkout it answers for, or to a repository named outright where no checkout exists.

func (Host) At

func (h Host) At(dir string) Host

At is the same host answering from another checkout of the repo.

func (Host) BranchExists

func (h Host) BranchExists(ctx context.Context, branch string) (bool, error)

BranchExists reports whether the host still has branch: after a merge that deleted it, the answer is false.

func (Host) CommitCI

func (h Host) CommitCI(ctx context.Context, sha string) (*CI, error)

CommitCI is how the checks on a commit ended, nil when it has none. On GitHub that is its check runs and its commit statuses; on GitLab its last pipeline.

func (Host) Decode

func (h Host) Decode(ctx context.Context, v any, args ...string) error

Decode runs one host CLI command and reads its JSON stdout into v.

func (Host) DefaultBranchName

func (h Host) DefaultBranchName(ctx context.Context) (string, error)

DefaultBranchName is the repo's default branch as the host has it.

func (Host) GLab

func (h Host) GLab() bool

GLab reports whether the host is GitLab's CLI.

func (Host) Login

func (h Host) Login(ctx context.Context) (string, error)

Login is who the CLI is signed in as: gh names it login, glab username.

func (Host) MRForcePushes

func (h Host) MRForcePushes(ctx context.Context, iid int, since time.Time) ([]ForcePush, error)

MRForcePushes reads GitLab's MR versions, one per push, since the time: a version whose previous head is not its ancestor replaced commits. GitLab records no pusher, so on the user's own MR each counts as theirs.

func (Host) MRReviews

func (h Host) MRReviews(ctx context.Context, iid int) ([]Review, error)

MRReviews is the notes that count as reviewing: any plain comment, and the system note an approval leaves.

func (Host) PRForcePushes

func (h Host) PRForcePushes(ctx context.Context, number int, login string) ([]ForcePush, error)

PRForcePushes is the force-pushes the user made to a PR, the last 100: GitHub records each with the head before and after.

func (Host) Pick

func (h Host) Pick(gh, glab []string) []string

Pick is this host's spelling of a command: gh's or glab's.

func (Host) PullCommits

func (h Host) PullCommits(ctx context.Context, number int) ([]PRCommit, error)

PullCommits is the commits a request lists, one call per request: asked for inside the list query, gh's GraphQL refuses a node count past its limit.

func (Host) Pulls

func (h Host) Pulls(ctx context.Context, login string, since time.Time) ([]PR, error)

Pulls is every request a person's standup needs: their own, with their commits and force-pushes, and others' they reviewed or merged since since.

func (Host) PullsSince

func (h Host) PullsSince(ctx context.Context, since time.Time) ([]PR, error)

PullsSince is what a board reads: every open request, and every one merged since since, each with the board's fields and no commits.

func (Host) Run

func (h Host) Run(ctx context.Context, args ...string) (string, error)

Run runs one host CLI command and returns its stdout.

func (Host) SearchPRs

func (h Host) SearchPRs(ctx context.Context, query, fields string) ([]PR, error)

SearchPRs is one `gh pr list --search` with the fields named.

type PR

type PR struct {
	Number    int
	Title     string
	URL       string
	Status    string // Open, Merged or Closed
	Draft     bool
	Empty     bool // no changes yet: no changed files on GitHub, no commits on GitLab
	Head      string
	HeadSHA   string
	Base      string
	Author    string
	Assignees []string
	Reviewers []string // reviewers requested and not yet heard from
	CreatedAt time.Time
	UpdatedAt time.Time
	MergedAt  time.Time // zero unless merged
	ClosedAt  time.Time // zero unless closed
	MergedBy  string
	Body      string
	Decision  string     // Approved, ChangesRequested, ReviewRequired or ""
	Mergeable string     // Clean, Conflicts, Blocked or ""
	Checks    string     // Green, Red, Pending or "" with none
	Commits   []PRCommit // the commits the host lists for it, where asked for
	MergeSHA  []string   // the merge and squash commits it landed as
	Reviews   []Review   // where asked for

	ForcePushes []ForcePush // the requester's own, where asked for
}

A PR is a pull or merge request as the host reported it.

type PRCommit

type PRCommit struct {
	SHA     string
	Subject string
	Message string // the whole message, trailers included
	Email   string // the author's email, as the commit records it
	At      time.Time
}

A PRCommit is one commit a PR lists. A rebase merge lands it on the default branch under a new sha, keeping its author date and subject.

type Review

type Review struct {
	Author string
	State  string // Approved, ChangesRequested, Commented or ""
	At     time.Time
}

A Review is one review event on a PR: a submitted review, an approval or a comment, by anyone.

Jump to

Keyboard shortcuts

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