forges

package
v0.2.49 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: GPL-2.0, GPL-3.0 Imports: 25 Imported by: 0

Documentation

Overview

Package forges integrates remote git forges (GitHub, GitLab, Gitea/Codeberg) by orchestrating their first-party CLI tools (gh, glab, tea).

Design: the CLI tools own API pagination, error mapping, the git credential helpers, AND their own credential stores — vibekit talks to each store exclusively through the CLI's documented subcommands (login/logout/status; see auth.go and discover.go) and never reads or writes another program's config file. The one documented exception is glab's read-only discovery parser (glab_config.go), kept only because glab ships no machine-readable status output. vibekit owns the UX, the unified API surface that the agent and the web UI both consume, and the GitHub OAuth device flow (oauth/device_flow.go — see login.go for the split). No token-refresh path exists on either side: PATs and device-flow tokens are used until they expire or are disconnected.

There is no encrypted credential store. The CLIs persist tokens in their own stores under the persistent /config volume. The container is single-user; file permissions are sufficient.

Index

Constants

View Source
const (
	StatusSuccess  = "success"
	StatusFailure  = "failure"
	StatusError    = "error"
	StatePending   = "pending"
	StateSkipped   = "skipped"
	StateCompleted = "completed"
)

Exported status/state constants defining the forge protocol vocabulary.

View Source
const CmdTimeout = 30 * time.Second

CmdTimeout is the default per-command timeout. Long enough for large repo lists; short enough that a wedged forge doesn't pin the request.

View Source
const ListTimeout = 60 * time.Second

ListTimeout is for paginated listings that may take longer.

Variables

View Source
var EnsureTool func(ctx context.Context, name string) error

EnsureTool is the tools-engine hook that installs a tool by name and waits for it. Wired from main.go; nil in tests/dev, where a missing CLI simply surfaces as an error.

View Source
var ErrNotInstalled = cliexec.ErrNotInstalled

ErrNotInstalled signals the backing CLI is not on PATH. Aliased to the cliexec sentinel (which runCmd actually returns) — the package previously declared a SEPARATE errors.New with the same message, so every errors.Is against this symbol silently never matched.

View Source
var ErrNotLoggedIn = cliexec.ErrNotLoggedIn

ErrNotLoggedIn signals the CLI is installed but no auth is configured for this host. Aliased for the same reason as ErrNotInstalled.

Functions

func EnsureCLI

func EnsureCLI(ctx context.Context, kind Kind) error

EnsureCLI checks if the CLI for the given kind is on PATH, and if not, installs it through the tools engine. Safe to call repeatedly.

func LoginWithPAT

func LoginWithPAT(ctx context.Context, p LoginPATParams) error

LoginWithPAT performs a PAT-based login: install the CLI, log it in natively (the CLIs validate the token against the forge at login time), then verify with Whoami and roll back on failure.

func Logout

func Logout(ctx context.Context, kind Kind, host string) error

Logout disconnects a forge: removes the credential from the CLI's own store via its logout subcommand.

func MakeID

func MakeID(kind Kind, host string) string

MakeID returns the canonical ID for a kind+host pair.

func ParseRepo

func ParseRepo(s string) (owner, name string, err error)

ParseRepo splits a "owner/name" string. Returns an error if the format is invalid. Both parts must be non-empty.

func SetConfigHome

func SetConfigHome(p string)

SetConfigHome overrides the config root for tests. Pass "" to reset to the default.

Types

type Check

type Check struct {
	Name       string `json:"name"`
	Status     string `json:"status"`     // "queued" | "in_progress" | stateCompleted
	Conclusion string `json:"conclusion"` // statusSuccess | statusFailure | "cancelled" | stateSkipped | ""
	URL        string `json:"url,omitempty"`
}

Check is a single CI status check for a commit.

type ConfiguredForge

type ConfiguredForge struct {
	ID         string `json:"id"`
	Kind       Kind   `json:"kind"`
	Host       string `json:"host"`
	Username   string `json:"username,omitempty"`
	Email      string `json:"email,omitempty"`
	LastError  string `json:"last_error,omitempty"`
	LastProbed int64  `json:"last_probed,omitempty"`
	Connected  bool   `json:"connected"`
	// CLIMissing marks a connection whose backing CLI binary is absent
	// (uninstalled/disabled in Settings → Tools, or a fresh tools volume
	// against a kept config volume) while a configuration for it still
	// exists. The row renders as a warning with a reinstall pointer; it
	// is never probed and cannot be disconnected until the CLI returns.
	CLIMissing bool `json:"cli_missing,omitempty"`
}

ConfiguredForge is one connected forge backend, discovered through the CLIs' own status subcommands (see discover.go).

type CreateIssueParams

type CreateIssueParams struct {
	Title  string   `json:"title"`
	Body   string   `json:"body,omitempty"`
	Labels []string `json:"labels,omitempty"`
}

CreateIssueParams describes an issue to create.

type CreatePRParams

type CreatePRParams struct {
	Title        string   `json:"title"`
	Body         string   `json:"body,omitempty"`
	SourceBranch string   `json:"source_branch"`
	TargetBranch string   `json:"target_branch"`
	Labels       []string `json:"labels,omitempty"`
	Draft        bool     `json:"draft,omitempty"`
}

CreatePRParams describes a PR to create.

type CreateReleaseParams

type CreateReleaseParams struct {
	TagName    string `json:"tag_name"`
	Name       string `json:"name,omitempty"`
	Body       string `json:"body,omitempty"`
	Target     string `json:"target,omitempty"` // commit SHA or branch
	Draft      bool   `json:"draft,omitempty"`
	Prerelease bool   `json:"prerelease,omitempty"`
}

CreateReleaseParams describes a release to create.

type DeviceFlowResponse

type DeviceFlowResponse = oauth.DeviceFlowResponse

DeviceFlowResponse describes a started OAuth device flow. Re-exported from the oauth sub-package for API compatibility.

func StartGitHubDeviceFlow

func StartGitHubDeviceFlow(ctx context.Context) (*DeviceFlowResponse, error)

StartGitHubDeviceFlow initiates the OAuth device flow with GitHub.

type ForgeErrCode

type ForgeErrCode string

ForgeErrCode is a typed error code for machine-readable forge HTTP error responses.

const (
	ForgeErrCLINotInstalled ForgeErrCode = "cli_not_installed"
	ForgeErrNotLoggedIn     ForgeErrCode = "not_logged_in"
)

ForgeErrCLINotInstalled and the following constants define the ForgeErrCode values for machine-readable HTTP error responses.

type ForgeOps

type ForgeOps interface {
	// Kind returns the backend kind (github/gitlab/gitea).
	Kind() Kind

	// Host returns the forge hostname this provider is bound to.
	Host() string

	// Whoami returns the authenticated account, or an error if not
	// logged in (or the CLI is not installed).
	Whoami(ctx context.Context) (*User, error)

	// ListRepos returns repositories accessible to the authenticated
	// account (owned + member).
	ListRepos(ctx context.Context) ([]Repo, error)

	// ListPRs lists pull/merge requests for repo.
	ListPRs(ctx context.Context, repo string, state ListState) ([]PR, error)

	// CreatePR opens a new pull/merge request.
	CreatePR(ctx context.Context, repo string, p *CreatePRParams) (*PR, error)

	// MergePR merges an open PR.
	MergePR(ctx context.Context, repo string, number int, method MergeMethod) error

	// ClosePR closes (without merging) an open PR.
	ClosePR(ctx context.Context, repo string, number int) error

	// ListIssues lists issues for repo.
	ListIssues(ctx context.Context, repo string, state ListState) ([]Issue, error)

	// CreateIssue files a new issue.
	CreateIssue(ctx context.Context, repo string, p CreateIssueParams) (*Issue, error)

	// CloseIssue closes an open issue.
	CloseIssue(ctx context.Context, repo string, number int) error

	// CommitStatus returns CI checks for a commit ref (branch / SHA).
	CommitStatus(ctx context.Context, repo, ref string) ([]Check, error)

	// ListReleases returns recent releases for repo.
	ListReleases(ctx context.Context, repo string) ([]Release, error)

	// CreateRelease cuts a new release.
	CreateRelease(ctx context.Context, repo string, p CreateReleaseParams) (*Release, error)

	// ListLabels returns labels defined on repo.
	ListLabels(ctx context.Context, repo string) ([]Label, error)
}

ForgeOps is the unified abstraction over a specific forge backend. Each implementation shells out to the corresponding CLI tool.

Methods take a context for cancellation and a host for routing (each Provider instance is bound to one host but methods accept it explicitly so multi-host instances are possible later).

func New

func New(kind Kind, host string) (ForgeOps, error)

New returns a ForgeOps for the given kind + host. host="" maps to the kind's default host (or returns an error for self-hosted Gitea where no default exists).

type HTTPHandler

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

HTTPHandler exposes the forges package over HTTP.

func NewHTTPHandler

func NewHTTPHandler(m *Manager, b api.Broadcaster) *HTTPHandler

NewHTTPHandler builds an HTTPHandler with the given Manager. broadcaster may be nil; when nil, forge change events are silently dropped.

func (*HTTPHandler) RegisterRoutes

func (h *HTTPHandler) RegisterRoutes(mux *http.ServeMux)

RegisterRoutes installs the /api/forges/* mux entries.

func (*HTTPHandler) SetOnChange added in v0.1.184

func (h *HTTPHandler) SetOnChange(fn func())

SetOnChange wires a callback fired whenever a forge connection changes (PAT login, OAuth completion, disconnect, refresh). Called once at composition; used to refresh the steering forge-snapshot cache and regenerate environment.md. The callback must not block — it runs on the HTTP request path — and must not capture the request context (composition kicks its work onto the app-lifetime context).

type Issue

type Issue struct {
	Title     string   `json:"title"`
	Body      string   `json:"body,omitempty"`
	State     string   `json:"state"`
	Author    string   `json:"author,omitempty"`
	URL       string   `json:"url,omitempty"`
	Labels    []string `json:"labels,omitempty"`
	Number    int      `json:"number"`
	CreatedAt int64    `json:"created_at,omitempty"`
	UpdatedAt int64    `json:"updated_at,omitempty"`
}

Issue represents a forge issue.

type Kind

type Kind string

Kind identifies a forge backend.

const (
	KindGitHub   Kind = "github"
	KindGitLab   Kind = "gitlab"
	KindGitea    Kind = "gitea"    // also covers Codeberg (codeberg.org is a Gitea instance)
	KindCodeberg Kind = "codeberg" // synonym for KindGitea, host=codeberg.org
)

KindGitHub and the following constants define the valid Kind values identifying forge backends.

func AllKinds

func AllKinds() []Kind

AllKinds returns every supported forge kind. Stable ordering for UI rendering.

func (Kind) CLI

func (k Kind) CLI() string

CLI returns the CLI tool name backing this kind.

func (Kind) DefaultHost

func (k Kind) DefaultHost() string

DefaultHost returns the canonical hostname for the kind, or "" if no default exists (self-hosted Gitea/Forgejo).

func (Kind) Title

func (k Kind) Title() string

Title returns the human-readable display name for the kind.

func (Kind) Valid

func (k Kind) Valid() bool

Valid reports whether k is a known forge kind.

type Label

type Label struct {
	Name        string `json:"name"`
	Color       string `json:"color,omitempty"`
	Description string `json:"description,omitempty"`
}

Label is a forge label (used on PRs and issues).

type ListState

type ListState string

ListState is a typed enum for PR/issue listing state filters.

const (
	StateOpen   ListState = "open"
	StateClosed ListState = "closed"
	StateMerged ListState = "merged"
	StateAll    ListState = "all"
)

StateOpen and the following constants define the valid ListState filter values for PR and issue listings.

type LoginPATParams

type LoginPATParams struct {
	Kind  Kind
	Host  string
	Token string
}

LoginPATParams describes a PAT-based login (GitLab/Gitea/Codeberg). The CLIs discover the account identity from the token themselves.

type Manager

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

Manager owns the list of configured forges.

func NewManager

func NewManager() *Manager

NewManager constructs a Manager.

func (*Manager) Get

func (m *Manager) Get(id string) *ConfiguredForge

Get returns the configured forge with the given ID, or nil.

func (*Manager) Invalidate

func (m *Manager) Invalidate()

Invalidate clears the cache so the next List/Get reloads.

func (*Manager) List

func (m *Manager) List(ctx context.Context) []ConfiguredForge

List returns all configured forges, refreshing from CLI configs if the cache is stale.

func (*Manager) Probe

func (m *Manager) Probe(ctx context.Context, id string) error

Probe runs a Whoami against the forge to verify auth still works and updates the Connected/LastProbed/LastError fields.

func (*Manager) Provider

func (m *Manager) Provider(id string) (ForgeOps, error)

Provider returns a ForgeOps for the given configured forge ID. Returns an error if the ID is unknown.

func (*Manager) Refresh

func (m *Manager) Refresh(ctx context.Context) error

Refresh re-queries every CLI's own status output and rebuilds the forge list. Presence-only: gh's network-tested per-account "state" is deliberately not consulted (Probe is the sole network path), and gh's own connection test fails fast offline, so the subprocess cost per stale TTL stays bounded by CmdTimeout in the worst case.

type MergeMethod

type MergeMethod string

MergeMethod is a typed enum for PR merge strategies.

const (
	MergeCommit MergeMethod = "merge"
	MergeSquash MergeMethod = "squash"
	MergeRebase MergeMethod = "rebase"
)

MergeCommit and the following constants define the valid MergeMethod values for PR merge strategies.

type PR

type PR struct {
	Title        string `json:"title"`
	Body         string `json:"body,omitempty"`
	State        string `json:"state"`
	Author       string `json:"author,omitempty"`
	SourceBranch string `json:"source_branch"`
	TargetBranch string `json:"target_branch"`
	URL          string `json:"url,omitempty"`
	Number       int    `json:"number"`
	CreatedAt    int64  `json:"created_at,omitempty"`
	UpdatedAt    int64  `json:"updated_at,omitempty"`
	Mergeable    bool   `json:"mergeable,omitempty"`
	Draft        bool   `json:"draft,omitempty"`
}

PR represents a pull/merge request.

type PollResult

type PollResult struct {
	Status string `json:"status"`
	Error  string `json:"error,omitempty"`
}

PollResult is the per-poll status during the device flow.

func PollGitHubDeviceFlow

func PollGitHubDeviceFlow(ctx context.Context, deviceCode string) (PollResult, error)

PollGitHubDeviceFlow checks if the user has approved the device. On complete, the token is written to gh's config and the helper is set up.

type Release

type Release struct {
	TagName     string `json:"tag_name"`
	Name        string `json:"name,omitempty"`
	Body        string `json:"body,omitempty"`
	URL         string `json:"url,omitempty"`
	PublishedAt int64  `json:"published_at,omitempty"`
	Draft       bool   `json:"draft,omitempty"`
	Prerelease  bool   `json:"prerelease,omitempty"`
}

Release represents a tagged release.

type Repo

type Repo struct {
	Owner         string `json:"owner"`
	Name          string `json:"name"`
	FullName      string `json:"full_name"`
	DefaultBranch string `json:"default_branch,omitempty"`
	URL           string `json:"url,omitempty"`
	CloneURL      string `json:"clone_url,omitempty"`
	Description   string `json:"description,omitempty"`
	Private       bool   `json:"private,omitempty"`
	Archived      bool   `json:"archived,omitempty"`
	Fork          bool   `json:"fork,omitempty"`
	UpdatedAt     int64  `json:"updated_at,omitempty"` // unix millis
}

Repo is a remote repository accessible via the authenticated forge.

type User

type User struct {
	Login string `json:"login"`
	Name  string `json:"name,omitempty"`
	Email string `json:"email,omitempty"`
	URL   string `json:"url,omitempty"`
}

User represents the authenticated forge account.

Directories

Path Synopsis
Package cliexec provides CLI subprocess execution with structured output capture, size-capped buffers, and typed errors.
Package cliexec provides CLI subprocess execution with structured output capture, size-capped buffers, and typed errors.
Package gitea provides the Gitea/Codeberg ForgeOps implementation.
Package gitea provides the Gitea/Codeberg ForgeOps implementation.
Package github provides the GitHub ForgeOps implementation.
Package github provides the GitHub ForgeOps implementation.
Package gitlab provides the GitLab ForgeOps implementation.
Package gitlab provides the GitLab ForgeOps implementation.
Package oauth implements the GitHub OAuth device flow protocol.
Package oauth implements the GitHub OAuth device flow protocol.

Jump to

Keyboard shortcuts

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