forge

package
v0.4.4 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package forge — see forge.go for the canonical package overview.

This file exists only as a reservation for future package-level godoc elements (examples, build constraints) so callers running `go doc internal/forge` see a stable doc location regardless of file ordering.

Package forge defines the forge-agnostic interface surface that Nightgauge consumes. A "forge" is any source-hosting system that provides issues, pull/merge requests, project boards, CI checks, branch rulesets, and labels — GitHub today, GitLab and others in the future.

The package is structured as a set of per-domain service interfaces (IssueService, PRService, ProjectService, BoardService, CIService, LabelService, RulesetService, AuthService, RepoService, SecurityService) plus a ForgeClient aggregate that exposes accessors for each. Concrete adapters live in sibling packages (internal/github today) and provide compile-time satisfaction of these interfaces.

New(Config) is the factory entry point. It dispatches on Config.Kind to build the appropriate adapter and returns it as a ForgeClient. Unknown kinds return ErrUnsupported wrapped with %w so callers can use errors.Is(err, forge.ErrUnsupported).

See docs/decisions/006-forge-abstraction.md for the design rationale, the audit table mapping every internal/github method to its forge counterpart, and the cross-forge interaction diagram.

Index

Constants

View Source
const MaxSecurityAlertsPerRequest = 100

MaxSecurityAlertsPerRequest bounds how many alerts one ListOpenAlerts call enumerates.

The service is contractually SINGLE-REQUEST for the alert list: it runs inside the attention sweep's shared 30-second budget alongside every other producer, so a paginating implementation would spend another producer's time. A repository holding more open alerts than this gets SecurityAlerts.Truncated set rather than a second round trip — under-reporting loudly beats starving the sweep, and a caller that reads Truncated cannot mistake the page for the whole set.

Variables

View Source
var (
	// ErrNotFound indicates the requested resource (issue, PR, label, etc.)
	// does not exist or the caller cannot see it.
	ErrNotFound = errors.New("forge: resource not found")

	// ErrRateLimited indicates the caller has exceeded the forge's rate
	// limit. Callers should back off and retry per the forge's published
	// reset window.
	ErrRateLimited = errors.New("forge: rate limited")

	// ErrPermissionDenied indicates the token is valid but lacks permission
	// for the requested action (forbidden, scope mismatch).
	ErrPermissionDenied = errors.New("forge: permission denied")

	// ErrUnauthorized indicates the token is missing, expired, or revoked.
	ErrUnauthorized = errors.New("forge: unauthorized")

	// ErrUnsupported indicates the requested forge kind is recognised but
	// no adapter implementation is registered for it. Returned by
	// forge.New for unknown Kind values. Also used by adapter methods that
	// have not yet been implemented for a given forge — callers can use
	// errors.Is to fall back to an alternate code path.
	ErrUnsupported = errors.New("forge: unsupported forge kind")

	// ErrUnsupportedOnEdition indicates the requested feature exists in
	// the forge family but not in the licensed edition the caller has
	// access to. Examples: GitLab CE silently ignores
	// approvals_before_merge — adapters surface this as
	// ErrUnsupportedOnEdition so callers can choose to treat it as a
	// soft warning rather than a hard failure.
	ErrUnsupportedOnEdition = errors.New("forge: unsupported on this edition")
)

Sentinel errors returned (wrapped via %w) by forge adapters. Callers use errors.Is to react to a particular failure class without coupling to a specific forge's error text or HTTP status codes.

Adapter implementations are responsible for translating their native errors (HTTP 404 → ErrNotFound, 401 → ErrUnauthorized, etc.) into these sentinels at the adapter boundary. Existing fmt.Errorf wrapping for non-sentinel cases is preserved.

Functions

func RegisterAdapter

func RegisterAdapter(kind Kind, factory func(Config) (ForgeClient, error))

RegisterAdapter associates a Kind with its constructor. Intended to be called from an init() in an adapter package. Re-registering an existing Kind silently overrides the prior factory — useful in tests.

Types

type AuthService

type AuthService interface {
	CheckTokenScopes(ctx context.Context) (*forgetypes.TokenScopeInfo, error)

	// Whoami returns the actor associated with the active token. Mirrors
	// `gh api user --jq .login` — used by repo-init to discover the
	// authenticated user for personal-project lookup. Adapters that
	// cannot identify the caller return an error wrapping ErrUnsupported.
	Whoami(ctx context.Context) (*forgetypes.Actor, error)
}

AuthService is the forge-agnostic surface for authentication / token inspection. Adapters report whichever scope/permission model their forge exposes through TokenScopeInfo.

type BoardService

type BoardService interface {
	ListItems(ctx context.Context, statusFilter string) ([]forgetypes.BoardItem, error)
	ListOpenItems(ctx context.Context) ([]forgetypes.BoardItem, int, error)

	// GetItem fetches a single board item by issue number. Adapters return
	// ErrNotFound when the issue exists but is not on the bound board (or
	// the issue itself does not exist).
	GetItem(ctx context.Context, owner, repo string, issueNumber int) (*forgetypes.BoardItem, error)
}

BoardService is a read-only subset of the project board surface used by callers that only need to enumerate items (e.g. the state board snapshot).

There is deliberately no CountsByStatus here. Per-status counts are an aggregation over the open-item snapshot, computed once in boardcache.CountsByStatus from whatever ListOpenItems returned — a per-adapter count query was a second read of the same board that no cache could collapse (#TBD-board-counts).

type CIService

type CIService interface {
	GetCheckStatus(ctx context.Context, owner, repo string, prNumber int) (*forgetypes.CheckStatus, error)
	GetRequiredCheckNames(ctx context.Context, owner, repo, branch string) ([]string, error)
	GetIndividualCheckRuns(ctx context.Context, owner, repo, ref string) ([]forgetypes.CheckDetail, error)
	WaitForChecks(ctx context.Context, owner, repo string, prNumber int, cfg forgetypes.WaitConfig) (*forgetypes.CheckStatus, error)
	GetRunLogs(ctx context.Context, owner, repo string, runID int64) (*forgetypes.CIRunLog, error)
}

CIService is the forge-agnostic surface for CI / pipeline check inspection. GitHub Checks, GitLab CI/CD, and Bitbucket Pipelines all map to the same status-roll-up shape; per-check details (Status, Conclusion) follow GitHub's vocabulary as the lowest-common denominator.

type Config

type Config struct {
	// Kind selects the adapter (e.g. "github").
	Kind Kind

	// Token is the auth token for the forge. Resolution from env / gh CLI
	// happens in the caller; Config carries only the resolved value.
	Token string

	// Owner is the org or user namespace the client targets (e.g.
	// "nightgauge" or "octocat").
	Owner string

	// ProjectNumber is the project board number (1-based) for forges that
	// expose projects (GitHub Projects V2). Zero means "no project bound".
	ProjectNumber int

	// OwnerType distinguishes organisations from user accounts. Forges
	// that don't separate the two should leave this empty.
	OwnerType string

	// Host is the server hostname for self-hosted forge instances (e.g. a
	// self-hosted GitLab at "gitlab.mycompany.com"). Empty for github.com
	// and gitlab.com SaaS. Consumed by Router.ResolveLink to construct
	// cross-forge full URLs.
	Host string

	// BoardStatusStrategy selects how Status field writes are mapped onto
	// the underlying forge. Currently consumed only by the GitLab adapter:
	//
	//   - "" (empty) or "label-status": scoped Status::<value> label,
	//     mutually-exclusive enforcement via GitLab scoped labels.
	//   - "state-only": map Done → close, anything else → reopen + clear
	//     Status::* labels. In-between states (In progress / In review)
	//     return a wrapped error because state-only mode cannot represent
	//     them.
	//
	// The GitHub adapter ignores this field — Status is a project-V2
	// single-select option there.
	BoardStatusStrategy string
}

Config is the minimal data needed to construct a ForgeClient. Adapter- specific options (rate-limit floor, GraphQL URL override for tests, shared rate-limit tracker) remain on the underlying client constructors rather than leaking into this cross-forge config.

type DefaultBranchFileService added in v0.4.2

type DefaultBranchFileService interface {
	// DefaultBranchFiles returns the head of owner/name's default branch and
	// each of paths at that commit. A path the commit does not have is absent
	// from Files and is not an error; a repository the forge does not show,
	// or one with no default branch, is.
	DefaultBranchFiles(ctx context.Context, owner, name string, paths []string) (*forgetypes.DefaultBranchFiles, error)
}

DefaultBranchFileService is an optional surface, not part of ForgeClient, that reads files of a repository at the head of its default branch, as the forge serves them. The branch, its head and every file come from one answer, so no file is read at another commit. The GitHub adapter's RepoService implements it.

type ForgeClient

type ForgeClient interface {
	Issues() IssueService
	PRs() PRService
	Project() ProjectService
	Board() BoardService
	CI() CIService
	Labels() LabelService
	Rulesets() RulesetService
	Auth() AuthService
	Repo() RepoService
	Security() SecurityService
}

ForgeClient is the aggregate interface that exposes per-domain services. Callers depend on this interface (or a subset like BoardService) rather than on a concrete adapter.

func New

func New(cfg Config) (ForgeClient, error)

New constructs a ForgeClient for the given Config. Returns ErrUnsupported (wrapped) when no adapter is registered for the kind.

type GraphQLService

type GraphQLService interface {
	ExecuteGraphQL(ctx context.Context, query string, variables map[string]interface{}) ([]byte, error)
}

GraphQLService is an optional surface — not part of ForgeClient — that the GitHub adapter implements to support the `forge graphql` pass- through subcommand. Adapters that do not expose a GraphQL transport (or that intentionally restrict ad-hoc queries) return ErrUnsupported wrapped via %w from ExecuteGraphQL.

The contract is intentionally minimal: a raw query string plus a variables map, returning the raw JSON envelope. The CLI layer in cmd/nightgauge/forge/graphql.go does the flag parsing (-f key=value, -F key=value) and prints the envelope verbatim.

type IssueRef

type IssueRef struct {
	Owner  string
	Repo   string
	Number int
}

IssueRef identifies one issue by number, carrying its own owner and repo.

Both sides of a link carry their own repository because cross-repository linking is a live path in this tree, not a hypothetical: internal/audit's issue creator resolves the epic's repository and the sub-issue's repository from different sources and they routinely differ. A single owner/repo pair shared by both ends of the call would be silently wrong there — it would link within whichever repository the caller happened to name.

func (IssueRef) String

func (r IssueRef) String() string

String renders the canonical "owner/repo#number" form used in errors.

type IssueService

type IssueService interface {
	// Read.
	GetIssue(ctx context.Context, owner, repo string, number int) (*forgetypes.Issue, error)
	GetIssuesByNumbers(ctx context.Context, owner, repo string, numbers []int) (map[int]*forgetypes.Issue, error)
	ListIssues(ctx context.Context, owner, repo string, labels []string) ([]forgetypes.Issue, error)
	IterateIssues(ctx context.Context, owner, repo string, labels []string) Iterator[forgetypes.Issue]
	SearchIssues(ctx context.Context, owner, repo, query string, limit int) ([]forgetypes.Issue, error)
	HasLabel(ctx context.Context, owner, repo string, number int, label string) (bool, error)
	GetRepoLabels(ctx context.Context, owner, repo string) (map[string]string, error)

	// Mutate (CRUD).
	CreateIssue(ctx context.Context, repoID, title, body string, labelIDs []string) (*forgetypes.Issue, error)
	CloseIssue(ctx context.Context, issueID string) error
	ReopenIssue(ctx context.Context, issueID string) error
	EditIssue(ctx context.Context, nodeID, body string) (*forgetypes.Issue, error)
	UpdateIssue(ctx context.Context, nodeID string, opts UpdateIssueOptions) (*forgetypes.Issue, error)

	// Comments.
	AddComment(ctx context.Context, subjectID, body string) error

	// Sub-issue linking (GitHub-native; GitLab adapters may emulate via
	// related issues with a documented mapping).
	//
	// These take references rather than node IDs. The REST endpoints behind
	// them address issues by number and database id, so a caller that already
	// knows the number no longer pays a read to turn it into a node ID.
	AddSubIssue(ctx context.Context, parent, child IssueRef) error
	RemoveSubIssue(ctx context.Context, parent, child IssueRef) error
	LinkSubIssue(ctx context.Context, owner, repo string, parentNumber, childNumber int) error

	// Blocking relationships.
	AddBlockedBy(ctx context.Context, blocked, blocker IssueRef) error
	RemoveBlockedBy(ctx context.Context, blocked, blocker IssueRef) error

	// Labels.
	AddLabels(ctx context.Context, issueID string, labelIDs []string) error
	RemoveLabels(ctx context.Context, issueID string, labelIDs []string) error
	SyncStatusLabel(ctx context.Context, owner, repo string, number int, newStatus string) error
	MarkRefined(ctx context.Context, owner, repo string, number int) error

	// Epic helpers.
	GetEpicProgress(ctx context.Context, epicNodeID string) (*forgetypes.EpicProgress, error)
	GetEpicProgressByNumber(ctx context.Context, owner, repo string, number int) (*forgetypes.EpicProgress, error)
}

IssueService is the forge-agnostic surface for issue operations. The signature set mirrors GitHub's issue operations; future GitLab support maps GitLab's Issue API to the same interface.

type Iterator

type Iterator[T any] interface {
	// Next returns the next value in the stream, or (nil, io.EOF) when no
	// more values are available.
	Next(ctx context.Context) (*T, error)

	// Close releases adapter resources. Idempotent.
	Close() error
}

Iterator yields a stream of values of type T. Adapters return an Iterator from List-style operations that can paginate without loading the full result set into memory.

Contract:

  • Next returns (*T, nil) for each value, then (nil, io.EOF) when the stream is exhausted. Any other error stops iteration; callers should not call Next again after a non-EOF error.
  • Close releases adapter-side resources (open HTTP responses, paginated cursors). Close is idempotent — calling it multiple times returns nil after the first call. Callers should always call Close, typically via defer, even after Next returned io.EOF.
  • Iterator is not safe for concurrent use; callers must serialise Next calls.

type Kind

type Kind string

Kind discriminates between supported forges. New string values are added when an adapter is implemented; until then they return ErrUnsupported.

const (
	KindGitHub Kind = "github"
	KindGitLab Kind = "gitlab"
)

Supported (and recognised-but-unsupported) Kind values.

type LabelService

type LabelService interface {
	List(ctx context.Context) ([]*forgetypes.Label, error)
	Create(ctx context.Context, name, description, color string) (*forgetypes.Label, error)
	Delete(ctx context.Context, labelID string) error
}

LabelService is the forge-agnostic surface for repository label CRUD.

type PRService

type PRService interface {
	GetPR(ctx context.Context, owner, repo string, number int) (*forgetypes.PullRequest, error)
	ListPRs(ctx context.Context, owner, repo string, state string, headRef string) ([]forgetypes.PullRequest, error)
	IteratePRs(ctx context.Context, owner, repo, state, headRef string) Iterator[forgetypes.PullRequest]

	CreatePR(ctx context.Context, repoID, title, body, headRef, baseRef string) (*forgetypes.PullRequest, error)
	UpdatePR(ctx context.Context, prID string, opts UpdatePROptions) (*forgetypes.PullRequest, error)
	ClosePR(ctx context.Context, prID string) error
	MergePR(ctx context.Context, prID string) error
	MergePRWithStrategy(ctx context.Context, prID string, strategy string) (string, error)
	DeleteBranch(ctx context.Context, owner, repo, branch string) error

	// Epic PR helpers — composite operations that orchestrate a multi-PR
	// merge for an epic branch.
	CreateEpicPR(ctx context.Context, owner, repo string, epicNumber int, epicTitle, epicBranch, baseBranch string) (*forgetypes.EpicPRResult, error)
	MergeEpicPR(ctx context.Context, owner, repo string, prNodeID, epicBranch string) error
}

PRService is the forge-agnostic surface for pull/merge-request operations.

type ProjectService

type ProjectService interface {
	// Item membership.
	AddItem(ctx context.Context, contentNodeID string) (string, error)
	AddIssueByNumber(ctx context.Context, owner, repo string, number int) (string, error)
	BulkAddIssues(ctx context.Context, owner, repo string, issues []forgetypes.Issue) forgetypes.BulkAddResult

	// Status routing.
	SyncStatus(ctx context.Context, owner, repo string, issueNumber int, status string) error
	MoveStatus(ctx context.Context, owner, repo string, issueNumber int, newStatus string) error
	SyncIteration(ctx context.Context, owner, repo string, issueNumber int, iteration string) error

	// Single-field setters by item ID.
	SetSingleSelectField(ctx context.Context, itemID, fieldName, optionName string) error
	SetNumberField(ctx context.Context, itemID, fieldName string, value float64) error
	SetTextField(ctx context.Context, itemID, fieldName, value string) error
	SetTextFieldOptional(ctx context.Context, itemID, fieldName, value string) error
	SetDateField(ctx context.Context, itemID, fieldName, dateValue string) error
	SetDateFieldOptional(ctx context.Context, itemID, fieldName, dateValue string) error
	SetIterationField(ctx context.Context, itemID, fieldName, iterationTitle string) error

	// Batch / number-keyed setters.
	SetFields(ctx context.Context, owner, repo string, issueNumber int, fields map[string]string) error
	SetHours(ctx context.Context, owner, repo string, issueNumber int, hours float64) error
	SetDateFieldByNumber(ctx context.Context, owner, repo string, issueNumber int, fieldName, dateValue string) error
	SetEstimateFromLabels(ctx context.Context, owner, repo string, issueNumber int, labels []string, mapping map[string]float64) error

	// Blocking / dependency edges.
	AddBlockedByNumber(ctx context.Context, owner, repo string, blockedNumber, blockerNumber int) error
	RemoveBlockedByNumber(ctx context.Context, owner, repo string, blockedNumber, blockerNumber int) error

	// Epic aggregation.
	UpdateEpicEstimates(ctx context.Context, owner, repo string, epicNumber int) (float64, error)

	// Schema / drift management.
	EnsureFields(ctx context.Context, schema forgetypes.FieldSchema) (*forgetypes.EnsureFieldsResult, error)
	DriftCheck(ctx context.Context) ([]forgetypes.FieldDrift, error)
	DriftFix(ctx context.Context) ([]forgetypes.FieldDrift, error)
	SnapshotFields(ctx context.Context) (*forgetypes.FieldsSnapshot, error)
}

ProjectService is the forge-agnostic surface for project board / kanban operations. The shape closely follows GitHub Projects V2 — GitLab issue boards map to the same operations with an adapter-side translation.

type RepoService

type RepoService interface {
	// RepoMetadata returns the canonical name/owner pair for the named
	// repository. Adapters that do not separate owner namespaces from
	// repository names return Owner == "" and Name == NameWithOwner.
	RepoMetadata(ctx context.Context, owner, name string) (*forgetypes.Repo, error)
}

RepoService is the forge-agnostic surface for read-only repository metadata. Mirrors the field set returned by `gh repo view --json nameWithOwner,owner,name` so jq pipelines parsing the gh output can be reused verbatim against `nightgauge forge repo view --json`.

type Router

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

Router resolves a forge identifier to a constructed ForgeClient. It supports three input forms:

  1. An explicit forge ID matching one of the configured forges (e.g. "github" or "acme-gitlab"). Used for `--forge <id>` and IB_FORGE.
  2. A repo spec ("owner/repo") whose forge is inferred from the router's repo→forge map.
  3. No input (single-forge fallback) — returns the singleton forge configured at construction time.

The interface is deliberately narrow: a future router (#3361) will add ResolveLink, ambiguity validation, and orphan-warning logic on top of the same For/ByID surface.

func NewRouter

func NewRouter() *Router

NewRouter constructs an empty Router with no registered forges. Use Register to add forges and SetDefault to declare the fallback.

func (*Router) ByID

func (r *Router) ByID(id string) (ForgeClient, error)

ByID is the explicit-id resolver used by callers that already know the forge identifier (e.g. when iterating r.IDs()). Returns ErrUnsupported (wrapped) for unregistered IDs.

func (*Router) For

func (r *Router) For(forgeFlag, repoSpec string) (ForgeClient, error)

For resolves a forge given the CLI's --forge flag and --repo flag. Resolution precedence: explicit forgeFlag > IB_FORGE env > repoSpec inference > defaultID > sole-registered-forge fallback.

Returns ErrUnsupported (wrapped) when an explicit forge ID is given but not registered.

func (*Router) ForgeIDFor

func (r *Router) ForgeIDFor(repoSpec string) (string, error)

ForgeIDFor returns the forge ID that owns the given repo spec, applying the same precedence chain as resolveID but without constructing a client. Returns ("", error) when the forge cannot be determined.

func (*Router) IDs

func (r *Router) IDs() []string

IDs returns the registered forge IDs, sorted alphabetically. Useful for diagnostic output ("registered forges: github, gitlab").

func (*Router) KindFor

func (r *Router) KindFor(id string) Kind

KindFor returns the forge Kind registered under the given forge ID. Returns an empty string when the ID is not registered.

func (*Router) MapRepo

func (r *Router) MapRepo(repoSpec, forgeID string)

MapRepo declares that the given "owner/repo" spec is hosted on the forge with the given id. Lookups are case-insensitive.

func (*Router) Register

func (r *Router) Register(id string, cfg Config)

Register associates a forge ID (e.g. "github") with its construction Config. Re-registering an existing ID replaces the prior config — this keeps tests trivial and matches RegisterAdapter's semantics.

func (r *Router) ResolveLink(fromRepo, toRepo, linkSlug string) string

ResolveLink returns the canonical reference string for a cross-repo link. When fromRepo and toRepo are on the same forge, returns the compact slug form (e.g. "owner/repo#42"). When they cross forge boundaries, returns the full URL:

linkSlug is the input reference ("owner/repo#42" or a full URL). The method does not make network calls.

func (*Router) SetDefault

func (r *Router) SetDefault(id string)

SetDefault declares the forge ID used when no explicit --forge flag or --repo lookup matches.

func (*Router) Validate

func (r *Router) Validate() []ValidationError

Validate checks the router for misconfigurations:

  • Dangling forge ref: a MapRepo call referenced a forge ID not in r.configs
  • Orphan forge: a registered forge has no repos mapped to it (warning only)
  • Ambiguous mapping: a repo appears in repoToID more than once (cannot happen via MapRepo alone, detected for manual-construction safety)

Returns nil when valid. Callers must treat Fatal=true entries as hard errors.

type RulesetService

type RulesetService interface {
	CheckRulesets(ctx context.Context, owner, repo string, prNumber int) (*forgetypes.RulesetCheckResult, error)
	SatisfyRulesets(ctx context.Context, owner, repo string, prNumber int, blockers []string) ([]string, error)
}

RulesetService is the forge-agnostic surface for branch protection / merge ruleset evaluation. GitHub branch rulesets and GitLab push rules map to the same precheck-and-resolve flow.

type SecurityService

type SecurityService interface {
	// ListOpenAlerts returns every OPEN security alert the forge reports for
	// owner/repo, up to MaxSecurityAlertsPerRequest, setting Truncated when the
	// forge holds more.
	ListOpenAlerts(ctx context.Context, owner, repo string) (*forgetypes.SecurityAlerts, error)
}

SecurityService is the forge-agnostic surface for dependency security advisories (GitHub Dependabot alerts; GitLab dependency scanning when it lands — tracked on #343).

The contract has four parts, and each exists because a caller downstream cannot work without it:

  • The advisory's OWN fields come back, not an inference. Severity, identifier, package, manifest, vulnerable range and first patched version are the advisory's; nothing here is derived from a label.

  • Every alert carries its own deep link in SecurityAlert.URL. It is the page that names this repository, this manifest and this alert, and offers a dismiss — and for the alerts with no remediation PR it is the ONLY useful destination, because the advisory URL is a public database page that mentions none of the three. An implementation that cannot obtain the link from its forge must construct it; leaving it empty silently downgrades the card class this surface exists for.

  • Scanning-disabled is a STATUS, not an error. See the design note on forgetypes.SecurityAlerts. "Zero open alerts" and "nobody is looking" are different facts and no caller should have to read an error string to tell them apart.

  • A failure to READ the alerts is an error wrapping forge.ErrUnauthorized or forge.ErrPermissionDenied, and the denial must be one the FORGE reported. Implementations must not answer an under-scoped token with an empty list: a security surface that silently reports "clean" when it was never allowed to look is worse than one that reports nothing at all. Nor may they INFER a denial from a role, a scope guess, or any other proxy — these sentinels are read by the attention sweep as repo-wide facts, so a wrong guess inside one adapter degrades surfaces that never called it. When an answer is ambiguous and no authoritative check is available, return a plain error: "I could not confirm" is a real answer and it fails closed without asserting something the forge never said.

type UpdateIssueOptions

type UpdateIssueOptions struct {
	Title     *string
	Body      *string
	Labels    *[]string
	Assignees *[]string
	State     *string // "opened" or "closed"
	Milestone *string
}

UpdateIssueOptions describes a partial update to an existing issue. All fields are pointers so callers can distinguish "do not change" (nil) from "set to empty" (non-nil pointer to zero value). State accepts forge-agnostic "opened" / "closed".

type UpdatePROptions

type UpdatePROptions struct {
	Title                *string
	Body                 *string
	Draft                *bool
	TargetBranch         *string
	Squash               *bool
	AllowForcePush       *bool
	ApprovalsBeforeMerge *int
	Labels               *[]string
}

UpdatePROptions describes a partial update to an existing pull / merge request. All fields are pointers so callers can distinguish "do not change" (nil) from "set to empty" (non-nil pointer to zero value). Forge-specific fields (Squash, AllowForcePush, ApprovalsBeforeMerge) are honoured by adapters that support them; adapters that don't surface them as a non-fatal ErrUnsupportedOnEdition warning where applicable.

type ValidationError

type ValidationError struct {
	Path    string // e.g. "repositories.acme/platform.forge"
	Message string // human-readable description
	Fatal   bool   // false = warning (non-fatal); true = blocks dispatch
}

ValidationError reports a misconfiguration in the router's repo/forge mappings.

Directories

Path Synopsis
Package boardcache holds one board read per board, per window, for the lifetime of a daemon.
Package boardcache holds one board read per board, per window, for the lifetime of a daemon.
Package output centralises the rendering layer used by every `nightgauge forge` subcommand.
Package output centralises the rendering layer used by every `nightgauge forge` subcommand.
Package forgetypes contains forge-agnostic data types used by the internal/forge interfaces and adapters.
Package forgetypes contains forge-agnostic data types used by the internal/forge interfaces and adapters.
Package webhook provides a forge-agnostic HTTP webhook abstraction that can be reused for GitHub, GitLab, Bitbucket, and other forge webhook receivers.
Package webhook provides a forge-agnostic HTTP webhook abstraction that can be reused for GitHub, GitLab, Bitbucket, and other forge webhook receivers.

Jump to

Keyboard shortcuts

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