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
- func DecodePages[T any](ctx context.Context, h Host, path string) ([]T, error)
- func SameLogin(declared, login string) bool
- func Status(state string) string
- type Activity
- type CI
- type Event
- type ForcePush
- type Host
- func (h Host) Activity(ctx context.Context, since time.Time) (Activity, error)
- func (h Host) At(dir string) Host
- func (h Host) Branches(ctx context.Context) (map[string]bool, error)
- func (h Host) CommitCI(ctx context.Context, sha string) (*CI, error)
- func (h Host) Decode(ctx context.Context, v any, args ...string) error
- func (h Host) DefaultBranchName(ctx context.Context) (string, error)
- func (h Host) EarlierRequests(ctx context.Context, ids []string) (map[string][]PR, error)
- func (h Host) GLab() bool
- func (h Host) Login(ctx context.Context) (string, error)
- func (h Host) MRForcePushes(ctx context.Context, iid int, since time.Time) ([]ForcePush, error)
- func (h Host) MRReviews(ctx context.Context, iid int) ([]Review, error)
- func (h Host) PRForcePushes(ctx context.Context, number int, login string) ([]ForcePush, error)
- func (h Host) Pick(gh, glab []string) []string
- func (h Host) PullCommits(ctx context.Context, number int) ([]PRCommit, error)
- func (h Host) Pulls(ctx context.Context, login string, since time.Time) ([]PR, error)
- func (h Host) PullsSince(ctx context.Context, since time.Time) ([]PR, error)
- func (h Host) Run(ctx context.Context, args ...string) (string, error)
- func (h Host) SearchPRs(ctx context.Context, query, fields string) ([]PR, error)
- type PR
- type PRCommit
- type Review
- type Touched
Constants ¶
const ( EventOpened = "opened" EventReady = "ready" // out of draft EventCommit = "commit" EventMergeFromBase = "merge-from-base" // a commit with more than one parent EventForcePush = "force-push" EventReview = "review" EventReviewRequested = "review-requested" EventMerged = "merged" EventClosed = "closed" )
What happened to a request in a window, one kind per event. Opened is read off the request's creation time; the rest are timeline events.
const ( Open = "open" Merged = "merged" Closed = "closed" )
The three states a request can be in, whichever CLI spelled them.
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.
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.
const ActivityQuery = `` /* 1365-byte string literal not displayed */
ActivityQuery is the GraphQL a GitHub feed reads: every request updated since the window's start with its timeline since then, and the open requests nobody touched, counted, the oldest first. gh pages it on the main search's cursor; a timeline keeps its newest 100 events, which a request rarely passes within a window.
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.
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 ¶
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 ¶
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.
Types ¶
type Activity ¶ added in v0.39.0
type Activity struct {
Requests []Touched
QuietCount int
QuietOldest time.Time // the oldest quiet request's creation time
}
Activity is what a repository did since a time: every request touched, and how many open ones nobody touched, with the oldest of them.
type CI ¶
CI is how the checks on a commit ended: Red when any failed, At the time of the last failure.
type Event ¶ added in v0.39.0
type Event struct {
Kind string
At time.Time
Actor string
Message string // a commit's whole message, trailers included
State string // a review's: Approved, ChangesRequested or Commented
}
An Event is one thing that happened to a request.
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) Activity ¶ added in v0.39.0
Activity reads what the repository did since since: one paged query on GitHub; on GitLab one list of the merge requests updated since, then the commits, notes and versions of those alone, and one list of the open ones nobody touched.
func (Host) Branches ¶ added in v0.39.0
Branches is every branch the host has, one paged listing: what the board asks of every merged request at once.
func (Host) CommitCI ¶
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) DefaultBranchName ¶
DefaultBranchName is the repo's default branch as the host has it.
func (Host) EarlierRequests ¶ added in v0.39.0
EarlierRequests is every request whose title or branch may name each id, read to tell a task's first request from a follow-up: one GraphQL call on GitHub for every id at once, a search on the text and one on the head branch per id; on GitLab, whose search reads titles alone, one list per id, a few at a time. The caller matches each request's branch and title against the id; the searches only narrow.
func (Host) MRForcePushes ¶
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 ¶
MRReviews is the notes that count as reviewing: any plain comment, and the system note an approval leaves.
func (Host) PRForcePushes ¶
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) PullCommits ¶
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 ¶
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 ¶
PullsSince is what a board reads: every open request, and every one merged since since, each with the board's fields and no commits.
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
Parents int // more than one is a merge
}
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.