Documentation
¶
Index ¶
- Variables
- func FormatHandoffMessage(r *HandoffResult) string
- func HandoffDepth() int
- func HasFacet(facets []ActiveFacet, name string) bool
- func IsBranchHeadFresh(ciCtx *CIContext) bool
- func NeedsDinD(facets []ActiveFacet) bool
- func RunSubsystem(reg Registry, subsystem string, ctx context.Context, cfg *config.Config, ...) error
- func ValidSubsystems() []string
- type ActiveFacet
- type CIContext
- type FacetDef
- type HandoffDecision
- type HandoffResult
- type Registry
- type RunOptions
- type Runner
Constants ¶
This section is empty.
Variables ¶
var FacetRegistry = []FacetDef{ { Name: "validate", Subsystem: "validate", NeedsDinD: false, Predicate: func(c *config.Config) bool { return c.Lint.Level != "" }, }, { Name: "deps", Subsystem: "deps", NeedsDinD: true, Predicate: func(c *config.Config) bool { return c.Dependency.Enabled }, }, { Name: "build", Subsystem: "build", NeedsDinD: true, Predicate: func(c *config.Config) bool { return len(c.Builds) > 0 }, }, { Name: "security", Subsystem: "security", NeedsDinD: true, Predicate: func(c *config.Config) bool { return c.Security.Enabled }, }, { Name: "release", Subsystem: "release", NeedsDinD: false, Predicate: func(c *config.Config) bool { return c.Release.Enabled }, }, { Name: "gitops-reconcile", Subsystem: "reconcile", NeedsDinD: false, Predicate: func(c *config.Config) bool { return c.GitOps.Cluster.Name != "" }, }, { Name: "governance-reconcile", Subsystem: "reconcile", NeedsDinD: false, Predicate: func(c *config.Config) bool { return len(c.Governance.Clusters) > 0 }, }, { Name: "narrate", Subsystem: "docs", NeedsDinD: false, Predicate: func(c *config.Config) bool { return !c.Narrate.IsZero() }, }, }
FacetRegistry is the canonical, ordered set of all known facets. Order determines canonical stage ordering.
Functions ¶
func FormatHandoffMessage ¶
func FormatHandoffMessage(r *HandoffResult) string
FormatHandoffMessage returns a human-readable message for the handoff result. Returns empty string when no message is needed.
func HandoffDepth ¶
func HandoffDepth() int
HandoffDepth reads SF_CI_HANDOFF_DEPTH from the environment. Returns 0 when unset or unparseable (original pipeline, not a handoff).
func HasFacet ¶ added in v0.5.0
func HasFacet(facets []ActiveFacet, name string) bool
HasFacet checks if a named facet is in the active set.
func IsBranchHeadFresh ¶
IsBranchHeadFresh reports whether this pipeline's commit is still the remote branch HEAD. It is the mutation-safety gate, and the INVARIANT it serves is about state, not operations: mutating shared or MOVING state — a rolling registry tag (latest/latest-dev), generated docs/badges committed back to the repo, registry retention/prune, a rolling release/package channel — requires freshness, so a superseded branch pipeline (one that lost the HEAD race) never drags shared state backward; the pipeline now at HEAD does that work instead. Immutable publications (a digest, a version-pinned tag, a v1.2.3 release) are inherently freshness-INDEPENDENT.
CURRENT POLICY is deliberately conservative and coarse-grained — it does not yet classify mutability per target. Mutability is approximated by event: a tag pipeline is always fresh (IsTag → true); a branch pipeline is HEAD-checked, and callers gate their WHOLE operation on the result, so a stale branch pipeline skips even the immutable per-sha tags it would have published. That is a safe simplification, NOT a claim that immutable publication is unsafe; a future refinement may let freshness-safe immutable publications through while still blocking moves of rolling state, without changing this contract.
Returns true when not in CI or when the branch cannot be resolved (fail-open for local runs). Orthogonal to config.TargetEligibility (when:-routing): eligibility asks "should this fire?", freshness asks "is it safe to mutate?".
func NeedsDinD ¶ added in v0.5.0
func NeedsDinD(facets []ActiveFacet) bool
NeedsDinD returns true if any active facet requires Docker-in-Docker.
func RunSubsystem ¶
func RunSubsystem(reg Registry, subsystem string, ctx context.Context, cfg *config.Config, ciCtx *CIContext, opts RunOptions) error
RunSubsystem dispatches to a subsystem runner by name. Returns a clear error for unknown subsystem names.
func ValidSubsystems ¶
func ValidSubsystems() []string
ValidSubsystems returns the list of valid subsystem names. Canonical lifecycle phases are the primary interface. Legacy names (build, deps, security, docs, release, validate, reconcile) remain as compatibility aliases.
Types ¶
type ActiveFacet ¶ added in v0.5.0
ActiveFacet is a facet that passed its predicate.
func DetectActive ¶ added in v0.5.0
func DetectActive(cfg *config.Config) []ActiveFacet
DetectActive evaluates all facets against the effective config. Returns only active facets in canonical order.
type CIContext ¶
type CIContext struct {
Provider string // gitlab, github, gitea, forgejo, jenkins
Event string // push, tag, merge_request, schedule
Branch string // current branch (empty on tags)
Tag string // current tag (empty on branches)
SHA string // full commit SHA
DefaultBranch string // repo default branch name
RepoURL string // repository URL
Workspace string // working directory
PipelineID string // provider pipeline/run ID (for cancel API)
}
CIContext holds normalized CI environment information. Generated CI files translate forge-native vars into SF_CI_* env vars; CIContext reads those to provide a provider-neutral execution context.
func ResolveContext ¶
func ResolveContext() *CIContext
ResolveContext reads SF_CI_* env vars to build a CIContext. Falls back to git inspection for local (non-CI) runs.
func (*CIContext) IsBranch ¶
IsBranch returns true when the current context is a branch build (not a tag).
type FacetDef ¶ added in v0.5.0
type FacetDef struct {
Name string // "build", "security", "gitops-reconcile", etc.
Subsystem string // what `ci run <x>` dispatches to
NeedsDinD bool // requires Docker-in-Docker transport
Predicate func(*config.Config) bool // config-driven activation check
}
FacetDef defines a CI facet — a capability that may be active in a repo. Predicates are deterministic: config presence only, no heuristics.
type HandoffDecision ¶
type HandoffDecision int
HandoffDecision describes the outcome of a handoff evaluation.
const ( // HandoffNone — no handoff needed (continue mode, or no commit created). HandoffNone HandoffDecision = iota // HandoffRestart — new commit pushed, requesting pipeline restart on repaired revision. HandoffRestart // HandoffSuppressed — handoff would fire, but this pipeline already originated // from a repaired-revision handoff (depth >= 1). One-hop guard prevents infinite loops. HandoffSuppressed // HandoffFail — repair was needed but policy says fail if handoff can't proceed. HandoffFail )
type HandoffResult ¶
type HandoffResult struct {
Decision HandoffDecision
CommitSHA string // SHA of the new commit deps created
Triggered bool // true if a new pipeline was triggered via provider API
Stale bool // true if current pipeline SHA != branch HEAD (should stop shipping)
Depth int // current handoff depth from SF_CI_HANDOFF_DEPTH
}
HandoffResult describes what happened when deps attempted a pipeline handoff.
func EvaluateHandoff ¶
func EvaluateHandoff(ciCtx *CIContext, handoff config.DependencyHandoff, commitSHA string) *HandoffResult
EvaluateHandoff checks whether a dependency commit requires pipeline handoff.
Handoff fires only when ALL of these are true:
- A new commit SHA was created and pushed
- Handoff mode is restart_pipeline
- Handoff depth is 0 (original pipeline, not already a rerun)
When depth >= 1 and a new commit was still created, the decision is HandoffSuppressed — the one-hop guard prevents infinite restart loops.
When handoff is "continue", the decision is always HandoffNone. When handoff is "fail" and depth >= 1, the decision is HandoffFail.
type RunOptions ¶
RunOptions holds runtime options that can be passed from CLI flags or resolved from CI context. This ensures local reproducibility — users can pass --tag v1.2.3 instead of needing CI env vars.
Directories
¶
| Path | Synopsis |
|---|---|
|
azuredevops
Package azuredevops renders a StageFreight pipeline to an Azure DevOps pipeline.
|
Package azuredevops renders a StageFreight pipeline to an Azure DevOps pipeline. |
|
forgejo
Package forgejo renders a StageFreight pipeline to a Forgejo Actions workflow.
|
Package forgejo renders a StageFreight pipeline to a Forgejo Actions workflow. |
|
gitea
Package gitea renders a StageFreight pipeline to a Gitea Actions workflow.
|
Package gitea renders a StageFreight pipeline to a Gitea Actions workflow. |
|
github
Package github renders a StageFreight pipeline to a GitHub Actions workflow.
|
Package github renders a StageFreight pipeline to a GitHub Actions workflow. |
|
gitlab
Package gitlab lowers a forge-neutral model.Pipeline to GitLab CI YAML.
|
Package gitlab lowers a forge-neutral model.Pipeline to GitLab CI YAML. |
|
internal/actions
Package actions is a private serialization backend: it writes a forge-neutral model.Pipeline out in the GitHub Actions workflow wire format.
|
Package actions is a private serialization backend: it writes a forge-neutral model.Pipeline out in the GitHub Actions workflow wire format. |
|
internal/azurepipelines
Package azurepipelines is a private serialization backend: it writes a forge-neutral model.Pipeline out as an Azure DevOps pipeline (azure-pipelines.yml).
|
Package azurepipelines is a private serialization backend: it writes a forge-neutral model.Pipeline out as an Azure DevOps pipeline (azure-pipelines.yml). |
|
model
Package model defines the forge-neutral CI pipeline types.
|
Package model defines the forge-neutral CI pipeline types. |