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

forge

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

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

View Source
const (
	OwnerOrganization = "Organization"
	OwnerUser         = "User"
)

The owner types GitHub reports.

View Source
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.

View Source
const (
	AccessYes     = "yes"
	AccessNo      = "no"
	AccessUnknown = "unknown"
)

What a probe learned about one permission.

Variables

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.

AgentTokenLinkPermissions and PersonTokenLinkPermissions are what the pre-filled token links ask for: the needed permissions and the wanted ones.

View Source
var ErrConflict = errors.New("conflict")

ErrConflict wraps a 409: the host refused the change in the resource's current state.

View Source
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.

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

ErrNotFound wraps any "does not exist" answer from the host.

View Source
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.

View Source
var ErrStacksUnavailable = errors.New("forge: native stacks unavailable")

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.

View Source
var ErrTransient = errors.New("transient forge error")

ErrTransient wraps failures worth retrying: 5xx, rate limits, network.

View Source
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

func HostMessage(err error) string

HostMessage is the host's message carried in err's chain, on one line of printable characters (no terminal escapes), or "".

func NoreplyEmail

func NoreplyEmail(u User) string

NoreplyEmail is the user's GitHub noreply address. Public commits use it so real email addresses never go public.

func PairTokenLink(public, shadow string) (link, repos string)

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 SplitName

func SplitName(full string) (string, string, error)

SplitName splits owner/name.

func TokenLink(name, description, owner string, days int, perms []string) string

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

type HostError struct {
	Message string
	Err     error
}

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.

func (*HostError) Error

func (e *HostError) Error() string

func (*HostError) Unwrap

func (e *HostError) Unwrap() error

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 NewPR

type NewPR struct {
	Title string
	Body  string
	Head  string
	Base  string
	Draft bool
}

type PR

type PR struct {
	Number int
	Head   string
	Base   string
	State  string
	Draft  bool
	URL    string
	// Merged is true when the PR was merged; State is then closed.
	Merged bool
}

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

type PushAccess struct {
	Can        string `json:"can"`
	HTTPStatus int    `json:"http_status"`
}

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 Repo

type Repo struct {
	FullName      string
	Private       bool
	Fork          bool
	DefaultBranch string
	CloneURL      string
	// OwnerType is GitHub's type of the repo's owner: OwnerOrganization or
	// OwnerUser ("" when unknown).
	OwnerType string
}

type RepoPermissions

type RepoPermissions struct {
	Have     map[string]string
	Accepted map[string]string
}

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

type Stack struct {
	Number int
	PRs    []int
}

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.

type User

type User struct {
	Login string
	ID    int64
}

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.

Jump to

Keyboard shortcuts

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