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
- Variables
- func RegisterAdapter(kind Kind, factory func(Config) (ForgeClient, error))
- type AuthService
- type BoardService
- type CIService
- type Config
- type DefaultBranchFileService
- type ForgeClient
- type GraphQLService
- type IssueRef
- type IssueService
- type Iterator
- type Kind
- type LabelService
- type PRService
- type ProjectService
- type RepoService
- type Router
- func (r *Router) ByID(id string) (ForgeClient, error)
- func (r *Router) For(forgeFlag, repoSpec string) (ForgeClient, error)
- func (r *Router) ForgeIDFor(repoSpec string) (string, error)
- func (r *Router) IDs() []string
- func (r *Router) KindFor(id string) Kind
- func (r *Router) MapRepo(repoSpec, forgeID string)
- func (r *Router) Register(id string, cfg Config)
- func (r *Router) ResolveLink(fromRepo, toRepo, linkSlug string) string
- func (r *Router) SetDefault(id string)
- func (r *Router) Validate() []ValidationError
- type RulesetService
- type SecurityService
- type UpdateIssueOptions
- type UpdatePROptions
- type ValidationError
Constants ¶
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 ¶
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 = 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 ¶
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.
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.
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:
- An explicit forge ID matching one of the configured forges (e.g. "github" or "acme-gitlab"). Used for `--forge <id>` and IB_FORGE.
- A repo spec ("owner/repo") whose forge is inferred from the router's repo→forge map.
- 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 ¶
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 ¶
IDs returns the registered forge IDs, sorted alphabetically. Useful for diagnostic output ("registered forges: github, gitlab").
func (*Router) KindFor ¶
KindFor returns the forge Kind registered under the given forge ID. Returns an empty string when the ID is not registered.
func (*Router) MapRepo ¶
MapRepo declares that the given "owner/repo" spec is hosted on the forge with the given id. Lookups are case-insensitive.
func (*Router) Register ¶
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 (*Router) ResolveLink ¶
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:
- GitHub: "https://github.com/owner/repo/issues/N"
- GitLab: "https://<host>/group/project/-/issues/N"
linkSlug is the input reference ("owner/repo#42" or a full URL). The method does not make network calls.
func (*Router) SetDefault ¶
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.
Source Files
¶
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. |