Documentation
¶
Index ¶
- func BranchFromRefspec(refspec string) string
- func Replay(session *gitstate.SyncSession) (err error)
- func RunCommitMsgHook(repoRoot, message string, cb func(stream, line string)) (string, error)
- func RunHook(repoRoot, hookName string, args []string, input []byte, ...) error
- func RunPostCommitHook(repoRoot string, cb func(stream, line string))
- func RunPreCommitHook(repoRoot string, wt *git.Worktree, cb func(stream, line string)) error
- type Backend
- type CommitBlock
- type CommitBlocks
- type CommitRing
- type ConfirmRequiredError
- type DecisionRequiredError
- type DryRunBackend
- type Engine
- func (e *Engine) Execute(plan gitplan.Plan, opts ExecuteOptions) (*ExecuteResult, error)
- func (e *Engine) Plan(policy gitplan.Policy) gitplan.Plan
- func (e *Engine) PlanPull(policy gitplan.Policy) gitplan.Plan
- func (e *Engine) PlanTo(remote, branch string, policy gitplan.Policy) (gitplan.Plan, error)
- type EngineOptions
- type ErrReplayCorruption
- type ExecuteOptions
- type ExecuteResult
- type FileChange
- type ForgeBackend
- type GitBackend
- type Plan
- type PlannerOptions
- type PushOptions
- type RefusedError
- type Result
- type StageMode
- type SyncAction
- type SyncResult
- type TypeRegistry
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BranchFromRefspec ¶
BranchFromRefspec extracts the branch name from a refspec like "HEAD:refs/heads/main".
func Replay ¶ added in v0.6.0
func Replay(session *gitstate.SyncSession) (err error)
Replay rebases local commits onto upstream using controlled tree replay. It is NOT a raw git rebase — it replays only SF-generated commits via explicit tree diffing with full integrity verification at each step.
Algorithm:
- Pre-conditions: HEAD attached, worktree clean, upstream configured → fail fast, no mutation
- Gate: no merge commits, linear chain (structural only — no authorship constraints)
- Re-validate upstream hash non-zero; record fetchedUpstreamHash
- Compute merge-base (exactly 1); collect commits oldest-first
- Hard reset to upstream
- For each commit: apply diff, stage, verify staging states, commit
- Race guard: upstream unchanged since fetch
Push is NOT performed by Replay — the planner's executor owns it: a diverged plan is the operation graph Confirm → Replay → Upload, so Execute runs the Upload after Replay returns. Replay only rewrites local history; the push stays a separate, gated operation.
Hooks are NOT run during replay — replay commits are machine-generated re-applications; running hooks again would double-execute side effects.
func RunCommitMsgHook ¶ added in v0.6.0
RunCommitMsgHook writes the message to a temp file, executes .git/hooks/commit-msg, and re-reads the (possibly modified) message from the file. Returns the (possibly modified) message and any error.
func RunHook ¶ added in v0.6.0
func RunHook(repoRoot, hookName string, args []string, input []byte, cb func(stream, line string)) error
RunHook executes a git hook if it exists and is executable. Returns ErrHookRejected if the hook exits non-zero. cb receives incremental stdout/stderr lines — never silently swallowed.
Hook sequence (caller's responsibility to run in order):
- pre-commit — no args, stdin /dev/null. Non-zero → abort.
- commit-msg <tmpfile> — write message to tmpfile, pass path as arg. Hook may modify the file; re-read after. Non-zero → abort.
- wt.Commit() — called by the CommitEngine, not here.
- post-commit — no args. Non-zero → warning only, no abort.
Hooks are treated as untrusted side-effect producers: - stdout/stderr always surfaced via cb - worktree snapshot before/after pre-commit; any new dirty paths emitted as hook_side_effect - filesystem mutations outside commit-msg tmpfile are detected and reported
func RunPostCommitHook ¶ added in v0.6.0
RunPostCommitHook executes .git/hooks/post-commit. Non-zero exit is logged as a warning via cb but does NOT abort.
Types ¶
type Backend ¶
type Backend interface {
Execute(ctx context.Context, plan *Plan, conventional bool) (*Result, error)
}
Backend executes a commit plan.
type CommitBlock ¶ added in v0.6.0
type CommitBlock struct {
Ring CommitRing
ID string // stable identifier for programmatic use and output
Message string // human-readable explanation
}
CommitBlock is a classified failure at any stage of commit planning or execution. Hard rings (Mechanical, Determinism) propagate as errors. Governance rings accumulate and are either reported or bypassed.
func (CommitBlock) Overrideable ¶ added in v0.6.0
func (b CommitBlock) Overrideable() bool
Overrideable returns true when the block can be bypassed with --maintainer-override.
type CommitBlocks ¶ added in v0.6.0
type CommitBlocks []CommitBlock
CommitBlocks is an ordered collection of CommitBlock values.
func (CommitBlocks) GovernanceOnly ¶ added in v0.6.0
func (bs CommitBlocks) GovernanceOnly() CommitBlocks
GovernanceOnly returns a slice containing only governance-ring blocks.
func (CommitBlocks) HasDeterminism ¶ added in v0.6.0
func (bs CommitBlocks) HasDeterminism() bool
HasDeterminism returns true when any RingDeterminism block is present. UX message: "StageFreight cannot safely describe what will be committed".
func (CommitBlocks) HasGovernance ¶ added in v0.6.0
func (bs CommitBlocks) HasGovernance() bool
HasGovernance returns true when any overrideable governance block is present.
func (CommitBlocks) HasHard ¶ added in v0.6.0
func (bs CommitBlocks) HasHard() bool
HasHard returns true when any non-overrideable block is present. Use HasMechanical and HasDeterminism for UX-distinct messaging.
func (CommitBlocks) HasMechanical ¶ added in v0.6.0
func (bs CommitBlocks) HasMechanical() bool
HasMechanical returns true when any RingMechanical block is present. UX message: "fix your repository state".
type CommitRing ¶ added in v0.6.0
type CommitRing string
CommitRing classifies a commit failure by its relationship to the commit path's safety and determinism. The ring determines whether a failure is absolute or can be bypassed with explicit maintainer intent.
Three rings, ordered by overrideability:
RingMechanical → git integrity is broken. No escape.
RingDeterminism → StageFreight cannot reliably describe what will happen. No escape.
RingGovernance → StageFreight policy or model is degraded, but the commit
path is still deterministic. Bypassed by --maintainer-override.
The rule: do not let Ring 3 failures disable a still-deterministic commit path.
const ( // RingMechanical covers failures where the git repository, index, or // filesystem state makes committing impossible regardless of intent: // - detached HEAD // - unresolved rebase/merge conflict // - index write failure // - hook rejected the commit // - push explicitly requested but mechanically blocked // Cannot be overridden. RingMechanical CommitRing = "mechanical" // RingDeterminism covers failures where StageFreight cannot reliably // determine what will be committed, construct the message, or truthfully // describe the result: // - missing commit summary // - unresolvable path set // - sync plan logically impossible (not a git error, a planning error) // Cannot be overridden. RingDeterminism CommitRing = "determinism" // RingGovernance covers failures where StageFreight policy, schema, or // model is degraded but the commit path itself remains deterministic: // - partial config-model migration incomplete // - generated outputs stale (docs, badges, manifests) // - convention strictness failures // - unrelated StageFreight subsystem broken // Can be bypassed with --maintainer-override. // Bypasses are recorded in Result.OverriddenBlocks and printed to output. RingGovernance CommitRing = "governance" )
type ConfirmRequiredError ¶ added in v0.7.0
type ConfirmRequiredError struct{ Detail string }
ConfirmRequiredError is returned when Execute reaches a Confirm without approval — the plan is sound, but a shared-history mutation needs an explicit yes.
func (*ConfirmRequiredError) Error ¶ added in v0.7.0
func (e *ConfirmRequiredError) Error() string
type DecisionRequiredError ¶ added in v0.7.0
DecisionRequiredError is returned when Execute reaches a Decide — the planner has multiple safe paths and no policy to choose; the operator must pick.
func (*DecisionRequiredError) Error ¶ added in v0.7.0
func (e *DecisionRequiredError) Error() string
type DryRunBackend ¶
type DryRunBackend struct {
RootDir string
}
DryRunBackend prints the commit plan without side effects.
type Engine ¶ added in v0.6.0
type Engine struct {
// contains filtered or unexported fields
}
Engine drives a repository push through the planner: Plan() (engine_plan.go) resolves the current repository state into an operation graph (gitplan.Plan), and Execute() (engine_execute.go) walks it, realizing each operation through the bound SyncSession — whose Transport (system git or embedded go-git) it inherits. The pre-planner state-machine convergence (Sync and its explicit transitions) has been retired in favour of the planner.
func NewEngine ¶ added in v0.6.0
func NewEngine(session *gitstate.SyncSession, opts EngineOptions) *Engine
NewEngine creates an Engine bound to the given SyncSession.
func (*Engine) Execute ¶ added in v0.7.0
func (e *Engine) Execute(plan gitplan.Plan, opts ExecuteOptions) (*ExecuteResult, error)
Execute is the boring graph-walker: it walks the plan's operations in order and realizes each through the EXISTING session/transport (never a new git shell-out or go-git call). All decisions were made in Plan(); Execute only carries them out. The interaction ops gate: Refuse stops, Decide surfaces the choices, Confirm requires approval before the operations that follow it — so a shared-history mutation can never run un-gated.
func (*Engine) Plan ¶ added in v0.7.0
Plan resolves the current repository situation into a gitplan.Plan WITHOUT mutating — the read-only half of the planner/executor split. It reads the session's current state (reflecting the last fetch), folds in policy, and returns the operation graph that the render / execute consumers walk. All decision logic lives in the pure gitplan.Resolve; this is thin, deterministic glue over the existing session.
func (*Engine) PlanPull ¶ added in v0.7.0
PlanPull resolves the current state into a DOWN-sync plan (`stagefreight pull`): bring the remote's commits into the local branch (fast-forward, or rebase-local-onto-remote when diverged). Read-only; the same executor walks it.
func (*Engine) PlanTo ¶ added in v0.7.0
PlanTo resolves an EXPLICIT cross-target push (`push <remote> <branch>`) — e.g. landing a feature branch onto origin/main — computing ahead/behind against the DESTINATION ref rather than the branch's own upstream. The caller must have fetched the remote first. An empty branch defaults to the current branch name.
type EngineOptions ¶ added in v0.6.0
type EngineOptions struct {
// OnEvent receives a structured event for informational transitions (e.g. the Teach
// lines emitted during Execute). If nil, events are dropped.
OnEvent func(gitstate.TransitionEvent)
}
EngineOptions configures Engine behaviour.
type ErrReplayCorruption ¶ added in v0.7.0
ErrReplayCorruption signals that a replayed commit's delta did not match the source commit's delta — a structural corruption. Raised by both the pre-commit path-set guard (e.g. nested files written to the repo root by basename) and the post-commit change-set equivalence gate (blob/mode/op divergence at preserved paths). Expected/Actual hold the source vs replayed signatures. Never pushed.
func (*ErrReplayCorruption) Error ¶ added in v0.7.0
func (e *ErrReplayCorruption) Error() string
type ExecuteOptions ¶ added in v0.7.0
type ExecuteOptions struct {
// Approved satisfies a Confirm gate (operator said yes, or a governed --yes). Without
// it, Execute stops at the first Confirm and mutates nothing.
Approved bool
}
ExecuteOptions carries what the graph-walker needs to satisfy interaction gates.
type ExecuteResult ¶ added in v0.7.0
ExecuteResult records what actually happened.
type FileChange ¶
FileChange represents a file with its change status.
type ForgeBackend ¶
ForgeBackend creates commits purely via forge API (no local git commit).
type GitBackend ¶
type GitBackend struct {
RootDir string
// OnCommitLine is called for each output line during hook execution and sync
// transition events. stream: "stdout", "stderr", "hook_side_effect", "sync".
// If nil, output is captured but not forwarded.
OnCommitLine func(stream string, line string)
}
GitBackend executes commits via go-git — no git binary required. Push/sync is also handled via go-git through the Engine.
func (*GitBackend) Push ¶ added in v0.6.0
func (g *GitBackend) Push(opts PushOptions) (*SyncResult, error)
Push synchronizes the current branch with its remote through the planner (Plan/Execute). There is now ONE push implementation, shared by `commit --push` and `stagefreight push`; the legacy engine.Sync convergence path is gone. pushViaPlanner handles the refspec (CI detached-HEAD) direct push internally.
type Plan ¶
type Plan struct {
Type string
Scope string
Summary string
Body string
Breaking bool
SkipCI bool
Paths []string // for StageExplicit
StageMode StageMode
Push PushOptions
SignOff bool
}
Plan is a fully resolved, validated commit intent.
func BuildPlan ¶
func BuildPlan(opts PlannerOptions, cfg config.CommitConfig, registry *TypeRegistry, rootDir string) (*Plan, error)
BuildPlan merges CLI flags with config defaults, validates, and returns a Plan.
type PlannerOptions ¶
type PlannerOptions struct {
Type string
Scope string
Message string // positional or --message
Body string
Breaking bool
SkipCI *bool // nil = use config default
Push *bool // nil = use config default
Paths []string // from --add flags
All bool
SignOff bool
Remote string
Refspec string
}
PlannerOptions holds raw inputs from CLI flags and positional args.
type PushOptions ¶
type PushOptions struct {
Enabled bool
Remote string // default: "origin"
Refspec string // default: "" (current branch)
RebaseOnDiverge bool // when true (default), rebase onto upstream if diverged before pushing
}
PushOptions controls post-commit push behavior.
type RefusedError ¶ added in v0.7.0
type RefusedError struct{ Detail string }
RefusedError is returned when Execute reaches a Refuse.
func (*RefusedError) Error ¶ added in v0.7.0
func (e *RefusedError) Error() string
type Result ¶
type Result struct {
SHA string
Message string
Files []string // actual staged files (from git diff --cached --name-only)
Pushed bool
NoOp bool
Backend string // stable descriptor: "git", "forge (gitlab)", "forge (github)", "dry-run"
Sync *SyncResult // populated when push was executed via the convergence engine
// MaintainerOverride is true when --maintainer-override was active for this commit.
// OverriddenBlocks records which governance checks were bypassed.
// Both are empty for normal commits with no governance failures.
MaintainerOverride bool
OverriddenBlocks CommitBlocks
}
Result holds the outcome of a commit execution. All informational status must be represented here, not printed by backends.
type SyncAction ¶ added in v0.6.0
type SyncAction string
SyncAction names a single step in the repository convergence plan.
const ( SyncSetUpstream SyncAction = "set-upstream" // configure tracking branch on first push SyncFetch SyncAction = "fetch" // fetch remote before rebase or fast-forward SyncFastForward SyncAction = "fast-forward" // merge --ff-only to catch up to upstream SyncRebase SyncAction = "rebase" // rebase local commits onto upstream SyncPush SyncAction = "push" // push to remote SyncNoop SyncAction = "noop" // already up to date, nothing to do )
type SyncResult ¶ added in v0.6.0
type SyncResult struct {
ActionsExecuted []SyncAction
PushedRef string // remote name that was pushed to
Noop bool // true only when SyncNoop was the sole action
}
SyncResult is the outcome of a push operation.
type TypeRegistry ¶
type TypeRegistry struct {
// contains filtered or unexported fields
}
TypeRegistry validates and resolves commit type keys.
func NewTypeRegistry ¶
func NewTypeRegistry(types []config.CommitType) *TypeRegistry
NewTypeRegistry creates a registry from configured commit types.
func (*TypeRegistry) List ¶
func (r *TypeRegistry) List() []config.CommitType
List returns all configured commit types in definition order.
func (*TypeRegistry) Resolve ¶
func (r *TypeRegistry) Resolve(key string) (resolvedKey string, forceBang bool, err error)
Resolve returns the resolved type key and whether a bang (!) is forced. If the type has an AliasFor, it returns the alias target key.
func (*TypeRegistry) Valid ¶
func (r *TypeRegistry) Valid(key string) bool
Valid returns true if the key is a recognized commit type.