simulate

package
v0.8.1-dryrun.28 Latest Latest
Warning

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

Go to latest
Published: Jul 5, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewCommand

func NewCommand() *cobra.Command

NewCommand builds the simulate parent command and its subcommands.

func ParseDeployResults

func ParseDeployResults(pairs []string) (map[string]DeployOutcome, error)

ParseDeployResults parses repeatable "name=outcome" pairs (for example "services=failure") into a per-callback outcome map. Outcomes are limited to success, failure, and skipped. It rejects a malformed pair, a blank name, and an unknown outcome so a typo never silently resolves to the success default.

Types

type Action

type Action interface {
	// Name is a short identifier for the action (for example "promote").
	Name() string

	// Describe returns a one-line human-readable summary of the action.
	Describe() string

	// Apply replays the action against the clone manifest and returns the
	// effects plus the after-state path.
	Apply(ctx ActionContext) (*ActionOutcome, error)
}

Action is a hypothetical operation the what-if engine can replay against a cloned manifest. Implementations drive the real orchestration logic in record-only mode and report the effects it would produce.

type ActionContext

type ActionContext struct {
	// ClonePath is the path to the temp clone of the manifest the action may
	// mutate. The real promoter writes its transitions here.
	ClonePath string

	// Actor is the identity that performs the hypothetical action.
	Actor string

	// Deploys is the deploy-stub model for the manifest's build and deploy
	// callbacks. The simulator validates orchestration, not the user's real
	// build and deploy scripts, so an action records each callback as a stubbed
	// effect with a simulated outcome and gates finalize on the result rather
	// than executing anything. It is never nil when supplied by the engine.
	Deploys *DeployStub
}

ActionContext carries the inputs an Action needs to replay orchestration against the cloned manifest. ClonePath points at the temp copy of the user's manifest; the real file is never handed to an action.

type ActionOutcome

type ActionOutcome struct {
	// Effects is the ordered list of steps the orchestration would take.
	Effects []Effect

	// AfterStatePath is the manifest path holding the after-state.
	AfterStatePath string
}

ActionOutcome is what an Action returns after replaying orchestration. It carries the ordered effects plus the path holding the resolved after-state (the clone path, since the real promoter writes there).

type DeployDiff

type DeployDiff struct {
	Name    string      `json:"name"`
	SHA     FieldChange `json:"sha"`
	Version FieldChange `json:"version"`
}

DeployDiff captures the field changes for a single named deploy within an environment.

type DeployOutcome

type DeployOutcome string

DeployOutcome is the simulated result of a single build or deploy callback. The simulator never runs the user's real build and deploy scripts, so each callback resolves to one of these recorded outcomes instead of an execution.

const (
	// OutcomeSuccess marks a callback the simulation treats as having succeeded.
	// It is the default when no outcome is injected for a callback.
	OutcomeSuccess DeployOutcome = "success"

	// OutcomeFailure marks a callback the simulation treats as having failed.
	// A failed deploy gates the downstream finalize, matching how the real
	// finalizers refuse to record state when a deploy did not succeed.
	OutcomeFailure DeployOutcome = "failure"

	// OutcomeSkipped marks a callback the simulation treats as not run. A
	// skipped deploy is never a failure, but it does not count as a success
	// either, so a step whose only deploys were skipped still gates.
	OutcomeSkipped DeployOutcome = "skipped"
)

type DeployStub

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

DeployStub is the simulate-side model of the build and deploy callbacks a manifest declares. It exists to make one boundary explicit: the simulator validates cascade's ORCHESTRATION, meaning the run, skip, and gate decisions and the state transitions, not the user's real build and deploy scripts. Those scripts never execute in a what-if. Each callback is therefore recorded as a stubbed effect carrying a simulated outcome rather than run.

Outcomes default to success, so the orchestration sequences exactly as it would with real callbacks that all passed. A caller can inject a failure or skipped outcome per callback to preview the orchestration's gating behavior. The gate mirrors the DEPLOY_RESULT_<name> inputs the real finalizers read from the environment (see internal/promote/finalize.go and internal/rollback/command_subcommands.go): a deploy that did not succeed refuses to advance trunk state, so the simulated finalize is held back.

type Disposition

type Disposition string

Disposition classifies how the orchestration treats a single effect when the hypothetical action is replayed in record-only mode.

const (
	// DispositionRun marks an effect the orchestration would carry out.
	DispositionRun Disposition = "run"

	// DispositionSkip marks an effect the orchestration would skip as a no-op.
	DispositionSkip Disposition = "skip"

	// DispositionGate marks an effect held back behind a gate or guard.
	DispositionGate Disposition = "gate"
)

type Effect

type Effect struct {
	Disposition Disposition `json:"disposition"`
	Action      string      `json:"action"`
	Target      string      `json:"target"`
	Detail      string      `json:"detail"`
}

Effect is one ordered step the orchestration would take for the simulated action. It carries the disposition (run, skip, or gate), the kind of action, the target it acts on, and a human-readable detail string.

type Engine

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

Engine runs hypothetical actions against a clone of the user's manifest and reports the resulting state diff and effect sequence. It never mutates the user's real manifest and never touches git or the network.

func NewEngine

func NewEngine(manifestPath string, opts ...Option) (*Engine, error)

NewEngine builds an Engine bound to the manifest at manifestPath. The path is validated by reading it; the file is never modified.

func (*Engine) Simulate

func (e *Engine) Simulate(a Action) (*Result, error)

Simulate replays the action against a temp clone of the manifest and returns the before and after diff plus the ordered effects. The clone is created in a temp directory and removed when Simulate returns.

type EnvDiff

type EnvDiff struct {
	Environment  string       `json:"environment"`
	Version      FieldChange  `json:"version"`
	SHA          FieldChange  `json:"sha"`
	Divergence   FieldChange  `json:"divergence"`
	PreviousRing FieldChange  `json:"previous_ring"`
	Deploys      []DeployDiff `json:"deploys,omitempty"`
}

EnvDiff captures the field-by-field changes for a single environment. The run-stamped CommittedAt and CommittedBy fields are deliberately excluded: timestamps are run-stamped and not part of the what-if outcome.

type FieldChange

type FieldChange struct {
	Field   string `json:"field"`
	From    string `json:"from"`
	To      string `json:"to"`
	Changed bool   `json:"changed"`
}

FieldChange records a single field transitioning from one value to another. Changed is true only when From and To differ.

type HotfixAction

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

HotfixAction replays the real hotfix finalize orchestration against a cloned manifest. It drives hotfix.Finalizer in record-only mode so the genuine divergence state machine runs: it allocates the next hotfix version, snapshots the prior state into the deploy-history ring, and writes the divergence fields (Ref, BaseSHA, Patches) to the clone only. Git, the trunk read, the manifest push, and the release API are all replaced with record-only seams, so the simulation touches no git and no network.

func NewHotfixAction

func NewHotfixAction(targetEnv string, fixSHAs []string, mergeSHA string) *HotfixAction

NewHotfixAction builds a HotfixAction that simulates landing fixSHAs as a hotfix on targetEnv. mergeSHA is the resolution-branch tip the hotfix merges to; when empty it defaults to the first fix SHA, which is the common case for a single-commit hotfix.

func (*HotfixAction) Apply

func (a *HotfixAction) Apply(ctx ActionContext) (*ActionOutcome, error)

Apply drives the real hotfix Finalizer against the clone manifest in record-only mode and returns the divergence after-state plus an ordered effect sequence. The Finalizer writes the diverged state to the clone via os.WriteFile only; the injected pusher and release manager record what the workflow would commit and publish without performing it.

func (*HotfixAction) Describe

func (a *HotfixAction) Describe() string

Describe returns a one-line summary of the hotfix being simulated.

func (*HotfixAction) Name

func (a *HotfixAction) Name() string

Name returns the action identifier.

type Option

type Option func(*Engine)

Option configures an Engine.

func WithActor

func WithActor(actor string) Option

WithActor sets the actor identity used when replaying an action.

func WithDeployResults

func WithDeployResults(outcomes map[string]DeployOutcome) Option

WithDeployResults injects per-callback simulated outcomes keyed by build or deploy name. Callbacks not named here default to success. Use it to preview the orchestration's gating behavior, for example a deploy failure holding back finalize. Real build and deploy scripts never run regardless of the outcome.

type PromoteAction

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

PromoteAction replays the real promotion orchestration against a cloned manifest. It drives promote.NewPromoter in non-dry-run mode so the genuine state-machine computes transitions and writes them to the clone only.

func NewPromoteAction

func NewPromoteAction(mode promote.PromotionMode, target string) *PromoteAction

NewPromoteAction builds a PromoteAction for the given promotion mode and target. The target is only consulted for cascade mode.

func (*PromoteAction) Apply

func (a *PromoteAction) Apply(ctx ActionContext) (*ActionOutcome, error)

Apply runs the real promoter against the clone manifest in non-dry-run mode and maps the returned PromotionResult into an ordered effect sequence. The promoter writes its transitions to the clone path via os.WriteFile only; no git or network call is made.

func (*PromoteAction) Describe

func (a *PromoteAction) Describe() string

Describe returns a one-line summary of the promotion being simulated.

func (*PromoteAction) Name

func (a *PromoteAction) Name() string

Name returns the action identifier.

type ReleaseAction

type ReleaseAction struct{}

ReleaseAction replays the real promotion state-machine across the release boundary against a cloned manifest. The promoter is the orchestration brain that decides whether a crossing is a prerelease promotion or a publish, and it computes the rc-to-publish version carry; this action drives it and surfaces that decision as the release-marker effect.

The network-bound release executor (internal/release Manager) is not invoked: the simulator validates orchestration, meaning the state transitions and the release decision, not the GitHub release API calls. The marker effect labels the step with the internal/release action vocabulary so the simulator and the executor name the step identically.

func NewReleaseAction

func NewReleaseAction() *ReleaseAction

NewReleaseAction builds a ReleaseAction.

func (*ReleaseAction) Apply

func (a *ReleaseAction) Apply(ctx ActionContext) (*ActionOutcome, error)

Apply runs the real promoter in default mode against the clone manifest and returns the effect sequence including the release marker. It reports a clear error when the manifest state is not at a release boundary, so the operator learns the crossing would not produce a release rather than seeing an empty result.

func (*ReleaseAction) Describe

func (a *ReleaseAction) Describe() string

Describe returns a one-line summary of the release crossing being simulated.

func (*ReleaseAction) Name

func (a *ReleaseAction) Name() string

Name returns the action identifier.

type Result

type Result struct {
	// ActionName is the short identifier of the simulated action.
	ActionName string `json:"action"`

	// ActionDescribe is the one-line human-readable summary of the action.
	ActionDescribe string `json:"describe"`

	// Diff is the before and after state difference.
	Diff StateDiff `json:"diff"`

	// Effects is the ordered list of orchestration steps.
	Effects []Effect `json:"effects"`

	// Note states the orchestration-not-deploys boundary so a green simulation
	// is never read as a passing deploy.
	Note string `json:"note,omitempty"`
}

Result is the outcome of one simulation: the action identity, the before and after state diff, and the ordered effect sequence.

func (*Result) RenderHuman

func (r *Result) RenderHuman(w io.Writer) error

RenderHuman writes a human-readable report of the simulation to w. The output is deterministic: environment keys are sorted and run-stamped timestamps are excluded from the diff.

func (*Result) RenderJSON

func (r *Result) RenderJSON(w io.Writer) error

RenderJSON writes the simulation result as deterministic, 2-space-indented JSON to w.

type RollbackAction

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

RollbackAction replays the real rollback orchestration against a cloned manifest. It drives rollback.New, Plan, and Apply so the genuine target resolution and state revert run, writing the reverted state to the clone only.

func NewRollbackAction

func NewRollbackAction(env, to, deployable string) *RollbackAction

NewRollbackAction builds a RollbackAction for the given environment. The to argument selects a prior SHA or version; when empty the previous distinct state is resolved from the deploy-history ring. The deployable argument scopes the rollback to a single deploy when set.

func (*RollbackAction) Apply

func (a *RollbackAction) Apply(ctx ActionContext) (*ActionOutcome, error)

Apply resolves the rollback target against the clone manifest and applies it. History resolution is pinned to the in-state deploy-history ring by injecting an empty history reader, so the simulation never shells out to git. Apply writes the reverted state to the clone path via os.WriteFile only.

func (*RollbackAction) Describe

func (a *RollbackAction) Describe() string

Describe returns a one-line summary of the rollback being simulated.

func (*RollbackAction) Name

func (a *RollbackAction) Name() string

Name returns the action identifier.

type StateDiff

type StateDiff struct {
	// Envs holds the per-environment diffs in sorted-key order.
	Envs []EnvDiff `json:"envs"`
}

StateDiff is the difference between a before and after manifest state, keyed by environment name in deterministic (sorted) order.

func DiffState

func DiffState(before, after map[string]*config.EnvState) StateDiff

DiffState computes the StateDiff between before and after environment states. Environment keys are sorted for deterministic output. Run-stamped timestamps (CommittedAt, CommittedBy) are ignored so output stays stable across runs.

func (StateDiff) Changed

func (s StateDiff) Changed() bool

Changed reports whether any environment in the diff changed.

func (StateDiff) Env

func (s StateDiff) Env(name string) (EnvDiff, bool)

Env returns the diff for a single environment by name.

Jump to

Keyboard shortcuts

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