Documentation
¶
Overview ¶
Package forge is the boundary between the engine and a code host. Only adapters under forge/ may talk to a host's API.
Index ¶
- Constants
- Variables
- func HostMessage(err error) string
- func NoreplyEmail(u User) string
- func PairTokenLink(public, shadow string) (link, repos string)
- func SplitName(full string) (string, string, error)
- func TokenLink(name, description, owner string, days int, perms []string) string
- type Check
- type CheckVisibility
- type Forge
- type HostError
- type Installation
- type Installer
- type NewPR
- type PR
- type PermissionError
- type PermissionProber
- type PushAccess
- type PushProber
- type Repo
- type RepoPermissions
- type Run
- type Stack
- type Stacker
- type User
Constants ¶
const ( OwnerOrganization = "Organization" OwnerUser = "User" )
The owner types GitHub reports.
const ( PermMetadataRead = "Metadata: read" PermContentsRead = "Contents: read" PermContentsWrite = "Contents: write" PermPullsRead = "Pull requests: read" PermPullsWrite = "Pull requests: write" PermActionsRead = "Actions: read" PermActionsWrite = "Actions: write" PermStatusesRead = "Commit statuses: read" PermChecksRead = "Checks: read" PermWorkflowsWrite = "Workflows: write" PermAdminWrite = "Administration: write" PermSecretsRead = "Secrets: read" )
The permissions doctor asks about, named as GitHub's fine-grained token settings name them.
const ( AccessYes = "yes" AccessNo = "no" AccessUnknown = "unknown" )
What a probe learned about one permission.
Variables ¶
var ( AgentTokenPermissions = []string{PermContentsWrite, PermPullsWrite, PermWorkflowsWrite, PermActionsRead, PermStatusesRead} PersonTokenPermissions = []string{PermContentsWrite, PermPullsWrite, PermWorkflowsWrite, PermActionsRead, PermStatusesRead, PermAdminWrite} )
AgentTokenPermissions are an agent's shadow-only token (the guide's Strict isolation): what feature start and gate need, and nothing that can publish. PersonTokenPermissions are a person's token for every command, init's shadow creation included.
var ( AgentTokenLinkPermissions = slices.Concat(AgentTokenPermissions, WantedTokenPermissions) PersonTokenLinkPermissions = slices.Concat(PersonTokenPermissions, WantedTokenPermissions) )
AgentTokenLinkPermissions and PersonTokenLinkPermissions are what the pre-filled token links ask for: the needed permissions and the wanted ones.
var ErrConflict = errors.New("conflict")
ErrConflict wraps a 409: the host refused the change in the resource's current state.
var ErrForbidden = errors.New("forbidden")
ErrForbidden wraps a plain permission refusal (a 403 that is not a rate limit): the token may not do this. Every Forge method wraps a plain 403 with it, ListChecks included once its workflow-runs fallback is refused too. A *PermissionError is one whose missing permission the host named.
var ErrNotFound = errors.New("not found")
ErrNotFound wraps any "does not exist" answer from the host.
var ErrRepoExists = errors.New("repo already exists")
ErrRepoExists wraps a creation the host refused because the name is taken (GitHub's 422 "name already exists on this account"): the repo exists even when the token can't see it.
ErrStacksUnavailable means the host won't make a native stack of these PRs: it has no stacks API (a 404), or it refused this list (a 422: the PRs don't chain, one is from a fork, or one is already stacked). Promote then leaves them as plain chained PRs, each based on the branch below.
var ErrTransient = errors.New("transient forge error")
ErrTransient wraps failures worth retrying: 5xx, rate limits, network.
var WantedTokenPermissions = []string{PermChecksRead}
WantedTokenPermissions are wanted, not needed: the token links ask for them, but a token without them still works. Checks: read lets the gate see check runs from apps other than GitHub Actions; without it the gate reads workflow runs instead, and warns.
Functions ¶
func HostMessage ¶
HostMessage is the host's message carried in err's chain, on one line of printable characters (no terminal escapes), or "".
func NoreplyEmail ¶
NoreplyEmail is the user's GitHub noreply address. Public commits use it so real email addresses never go public.
func PairTokenLink ¶ added in v0.1.1
PairTokenLink is TokenLink for a person's token on a pair: every permission the commands need, on the shadow repo's owner, for 90 days. repos are the ones to pick under "Only select repositories": both, when one owner holds them (a token has one resource owner), else the shadow.
func TokenLink ¶ added in v0.1.1
TokenLink is GitHub's new fine-grained token page, pre-filled with name, description, the resource owner, an expiry in days and perms (a write wins over a read of the same permission). GitHub can't pre-fill the repository selection, so wherever the link is shown, also say: choose "Only select repositories", then pick the repos. A value with <...> (a placeholder, for the guide) keeps its angle brackets; GitHub names never contain them.
Types ¶
type Check ¶
type Check struct {
Name string
Status string // queued | in_progress | completed
Conclusion string // success, failure, skipped, neutral, cancelled, timed_out, action_required, …
}
Check is one check run or commit status on a commit.
type CheckVisibility ¶
type CheckVisibility interface {
// ChecksLimited reports whether ListChecks for repo had reduced visibility.
ChecksLimited(repo string) bool
}
CheckVisibility is an optional interface for forges that can see only part of a repo's CI, for example a token that cannot read check runs.
type Forge ¶
type Forge interface {
GetRepo(ctx context.Context, full string) (Repo, error)
CreatePrivateRepo(ctx context.Context, full string) (Repo, error)
SetDefaultBranch(ctx context.Context, full, branch string) error
FindOpenPR(ctx context.Context, full, head, base string) (*PR, error)
CreatePR(ctx context.Context, full string, pr NewPR) (PR, error)
GetPR(ctx context.Context, full string, number int) (PR, error)
ListChecks(ctx context.Context, full, sha string) ([]Check, error)
CurrentUser(ctx context.Context) (User, error)
// SecretNames lists the Actions secret names visible to full: its own
// and the org secrets shared with it. Values are never read.
SecretNames(ctx context.Context, full string) ([]string, error)
// PushRuns lists Actions runs for sha triggered by event "push" (any status).
PushRuns(ctx context.Context, full, sha string) ([]Run, error)
// CancelRun asks to cancel a queued or in-progress run. The host only
// accepts the request: the run may keep going. A run the host won't
// cancel in its current state, finished or not, is ErrConflict.
CancelRun(ctx context.Context, full string, id int64) error
// ForceCancelRun force-cancels a run that ignored CancelRun. Like
// CancelRun, the host only accepts the request (a 202): the run may
// still keep going. A 409 is ErrConflict, a plain permission refusal
// ErrForbidden.
ForceCancelRun(ctx context.Context, full string, id int64) error
// ClosePullRequest closes PR number in full. A PR that is already
// closed is not an error; a missing one is ErrNotFound, and a plain
// permission refusal ErrForbidden.
ClosePullRequest(ctx context.Context, full string, number int) error
// EditPR changes PR number's title and body in full. A nil field is
// left as it is. A missing PR is ErrNotFound, and a plain permission
// refusal ErrForbidden.
EditPR(ctx context.Context, full string, number int, title, body *string) error
}
Forge is everything the engine needs from a code host. Repos are named owner/name; PR heads are branch names in the same repo.
type HostError ¶
HostError carries the host's own message for a failed call (GitHub's "message" field) and nothing else from the response. Its text is Err's.
type Installation ¶ added in v0.2.0
type Installation struct {
ID int64
Account string // login of the user or org it is installed on
AccountType string // "User" | "Organization"
Selection string // "all" | "selected"
}
Installation is one install of the Ghostbranch GitHub App that the signed-in user can see.
func (Installation) ConfigureURL ¶ added in v0.2.0
func (i Installation) ConfigureURL() string
ConfigureURL is the install's settings page: /settings/installations/<id> for a User, /organizations/<org>/settings/installations/<id> for an Organization.
type Installer ¶ added in v0.2.0
type Installer interface {
// UserInstallations: GET /user/installations, every page.
UserInstallations(ctx context.Context) ([]Installation, error)
// InstallationRepos: GET /user/installations/{id}/repositories, every
// page; owner/name of the repos the install covers that the user can
// also access.
InstallationRepos(ctx context.Context, id int64) ([]string, error)
}
Installer is an optional interface for forges that can tell where the app is installed. A token that is not an app login gets ErrForbidden.
type PermissionError ¶
type PermissionError struct {
// Permission is what the token lacks, as GitHub's settings page names
// it: "Workflows: write", or a set joined with " and ". For a classic
// or OAuth token, "OAuth scope: repo".
Permission string
// Repo is the owner/name the refused call was about; "" for none.
Repo string
}
PermissionError is a permission refusal whose missing permission the host named. It unwraps to ErrForbidden, so every errors.Is(err, ErrForbidden) check still holds. Its text never includes a token.
func (*PermissionError) Error ¶
func (e *PermissionError) Error() string
func (*PermissionError) Unwrap ¶
func (e *PermissionError) Unwrap() error
type PermissionProber ¶
type PermissionProber interface {
// ProbePermissions makes only GET requests (and the push probe, which
// pushes nothing) against full. A refusal is an answer, not an error;
// a network failure on the first request is an error wrapping
// ErrTransient, and a later one leaves that permission unknown.
ProbePermissions(ctx context.Context, full string) (RepoPermissions, error)
// OAuthScopes is the token's classic OAuth scopes, from GET /user's
// X-OAuth-Scopes header. ok is false when GitHub sent no such header
// (fine-grained and App tokens).
OAuthScopes(ctx context.Context) (scopes []string, ok bool, err error)
}
PermissionProber is an optional interface for forges that can tell, without writing anything, what the token may do.
type PushAccess ¶
PushAccess is whether the current token may push to a repo, from a probe that pushes nothing. Can is "true", "false" or "unknown".
type PushProber ¶
type PushProber interface {
PushAccess(ctx context.Context, full string) PushAccess
}
PushProber is an optional interface for forges that can tell whether the token may push to a repo without pushing.
type RepoPermissions ¶
RepoPermissions is what read-only probes learned about the token on one repo. Have maps a permission to AccessYes or AccessNo; a permission it doesn't list is unknown. Accepted holds GitHub's X-Accepted-GitHub-Permissions header from each refused probe, by permission.
type Run ¶
type Run struct {
ID int64
Workflow string
Status string // queued | in_progress | waiting | requested | pending | completed
Conclusion string // set once Status is completed: success | failure | cancelled | …
URL string
}
Run is a GitHub Actions workflow run.
type Stack ¶
Stack is a native stack of PRs: its number, from the repo's issue and PR sequence, and its PRs, bottom first. Merged PRs stay in it.
type Stacker ¶
type Stacker interface {
// CreateStack makes a stack of prs, bottom first. Each PR's base must be
// the head of the PR below it.
CreateStack(ctx context.Context, repo string, prs []int) (Stack, error)
// AddToStack appends prs, bottom first, on top of stack number stack. A
// 409 (another change to the stack is in progress) is ErrConflict.
AddToStack(ctx context.Context, repo string, stack int, prs []int) (Stack, error)
// StackOf is the stack PR pr is in, or nil when it isn't stacked, which
// is every PR on a host without native stacks.
StackOf(ctx context.Context, repo string, pr int) (*Stack, error)
}
Stacker is an optional interface for forges with native stacked PRs.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fake is an in-memory Forge whose repos are local bare git repos.
|
Package fake is an in-memory Forge whose repos are local bare git repos. |
|
Package github is the GitHub adapter: the only code in Ghostbranch that imports a GitHub API client.
|
Package github is the GitHub adapter: the only code in Ghostbranch that imports a GitHub API client. |