hotfix

package
v0.3.0-rc.24 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package hotfix plans and validates per-environment hotfixes that apply a trunk commit onto an environment pinned to an older trunk base.

The plan verb computes and validates only; the cherry-pick, build, deploy, and state write happen in the generated workflow. A plan with --dry-run mutates nothing.

Index

Constants

View Source
const EnvBranchPrefix = "env/"

EnvBranchPrefix is the prefix of the per-environment integration branches a hotfix creates (for example env/test). A branch carrying this prefix exists only while its environment is diverged; once the env rejoins trunk the branch is deleted.

Variables

This section is empty.

Functions

func HotfixTagsForBase

func HotfixTagsForBase(baseVersion string, tags []string) []string

HotfixTagsForBase returns the hotfix tags in tags that belong to the rc base of baseVersion. A hotfix tag has the dotted shape vX.Y.Z-rc.N.hotfix.M; it shares the rc base (vX.Y.Z-rc.N) of the version the environment held while diverged. The RC-shaped cleanup in internal/release deliberately cannot see these tags (it matches only ^vX.Y.Z-rc.N$), so divergence-end cleanup must collect them explicitly.

baseVersion may itself be a hotfix version (vX.Y.Z-rc.N.hotfix.M); it is normalized to its rc base before matching. Tags that do not parse, are not hotfix tags, or belong to a different rc base are excluded. The result is nil when nothing matches.

func NewCommand

func NewCommand() *cobra.Command

NewCommand creates the `cascade hotfix` command and its subcommands.

func OrphanEnvBranches

func OrphanEnvBranches(branches []string, state map[string]*config.EnvState) []string

OrphanEnvBranches returns the env/* branches in branches that have no matching divergence in state. A branch env/<name> is healthy only while state[<name>] reports IsDiverged(); a branch with no diverged env behind it is an orphan left over from an interrupted hotfix or manual meddling and should be flagged.

Non env/* branches are ignored. The returned slice preserves the input order and is nil when nothing is orphaned, so callers can treat a nil result as "consistent".

Types

type EnvPlan added in v0.3.0

type EnvPlan struct {
	Env     string `json:"env"`
	Branch  string `json:"branch"`
	BaseSHA string `json:"base_sha"`

	// Commits are the fix SHAs still to cherry-pick into this environment, in
	// the caller's requested ref order, after skipping commits already present.
	Commits []string `json:"commits"`

	// NoOp is true when the whole requested set is already present in this env.
	NoOp bool `json:"no_op"`

	// ConflictExpected hints whether a cherry-pick is likely to conflict. The
	// plan verb does not run the cherry-pick, so this is best-effort and false
	// by default; the workflow is authoritative.
	ConflictExpected bool `json:"conflict_expected"`
}

EnvPlan is the plan for one environment in the chain: the env branch, its recorded base SHA, and the ordered list of commits still to apply after per-(commit,env) idempotency skips. NoOp is true when every requested commit is already present in that environment.

type FinalizeOption

type FinalizeOption func(*Finalizer)

FinalizeOption configures optional, additive Finalizer behavior.

func WithFinalizeDryRun

func WithFinalizeDryRun(dryRun bool) FinalizeOption

WithFinalizeDryRun computes the finalize plan without writing state, tags, or release objects.

func WithReleaseManager

func WithReleaseManager(m releaseManager) FinalizeOption

WithReleaseManager injects the release operations. When unset, finalize builds a *release.Manager from GITHUB_REPOSITORY and the release token at run time.

func WithStatePusher

func WithStatePusher(p statePusher) FinalizeOption

WithStatePusher injects the manifest commit/push. The default reuses the shared rebase-retry helper.

func WithTagLister

func WithTagLister(l tagLister) FinalizeOption

WithTagLister injects the existing-tag lookup used for version allocation.

func WithTrunkStateReader

func WithTrunkStateReader(r trunkStateReader) FinalizeOption

WithTrunkStateReader injects the reader that returns the manifest as it exists on the trunk branch. Finalize uses it to read prior env state from trunk, the source of truth, rather than from the lagging env branch the hotfix merged into. The default reads via the GitHub Contents API on real GitHub and plain git under act.

type Finalizer

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

Finalizer writes the diverged state, tag, and release object for a completed hotfix. It mirrors the inputs of promote's Finalizer but targets one env on its integration branch rather than a trunk promotion.

func NewFinalizer

func NewFinalizer(opts FinalizerOptions, options ...FinalizeOption) (*Finalizer, error)

NewFinalizer constructs a Finalizer over the manifest at opts.ConfigPath.

func (*Finalizer) Finalize

func (f *Finalizer) Finalize(targetEnv, mergeSHA string, fixSHAs []string, baseSHA string) error

Finalize writes the diverged state for a completed hotfix on env/<targetEnv>.

targetEnv is the environment being hotfixed; mergeSHA is the tip of env/<targetEnv> after the resolution PR merged; fixSHAs are the trunk commits the hotfix carries (every cherry-picked commit, in apply order); baseSHA is the trunk anchor the integration branch diverged from. It cross-checks the merge SHA against the env-branch tip, allocates the next free hotfix version, snapshots the prior state into the Previous ring, writes the divergence fields and substates, commits the manifest to trunk, and creates the hotfix tag and release object. Every commit in fixSHAs is appended to the env's recorded patch set so a multi-commit hotfix records all of its commits, not just the first.

Finalize is idempotent on identical inputs: a rerun after the state already records the merge SHA is a no-op that neither double-applies patches nor re-snapshots Previous.

func (*Finalizer) SetBuildResult

func (f *Finalizer) SetBuildResult(name, result string)

SetBuildResult records the conclusion of a build job. Valid results mirror SetDeployResult; only successful builds update per-build state.

func (*Finalizer) SetDeployResult

func (f *Finalizer) SetDeployResult(name, result string)

SetDeployResult records the result of a deploy job, mirroring promote.Finalizer.SetDeployResult. Valid results: "success", "failure", "skipped", "cancelled". Only successful deploys update per-deploy state.

type FinalizerOptions

type FinalizerOptions struct {
	ConfigPath  string
	ManifestKey string
	Actor       string
}

FinalizerOptions carries the required inputs for NewFinalizer.

type OpenPR

type OpenPR struct {
	Number int    `json:"number"`
	URL    string `json:"url"`
}

OpenPR is a minimal view of an open pull request returned by a PRChecker.

type Option

type Option func(*Planner)

Option configures optional, additive Planner behavior.

func WithDryRun

func WithDryRun(dryRun bool) Option

WithDryRun controls whether the planner mutates anything. When true the env branch is computed but not created.

func WithPRChecker

func WithPRChecker(c PRChecker) Option

WithPRChecker injects the single-flight PR lookup. The default reports no open PRs.

func WithRemote

func WithRemote(remote string) Option

WithRemote overrides the git remote env branches live on (default "origin").

type PRChecker

type PRChecker interface {
	// OpenHotfixPRs returns open PRs labeled cascade-hotfix whose base is baseBranch.
	OpenHotfixPRs(baseBranch string) ([]OpenPR, error)
}

PRChecker reports open hotfix PRs targeting a given base branch. It is the single-flight gate: the plan verb refuses to proceed while a hotfix PR is already open against the target env branch. The default implementation is a no-op that reports no open PRs, so callers without GitHub context (and unit tests) are not forced to provide one.

type PlanChainResult added in v0.3.0

type PlanChainResult struct {
	// Envs are the per-environment plans in bottom-up chain order (the first
	// environment is excluded; the target environment is the last entry).
	Envs []EnvPlan `json:"envs"`
}

PlanChainResult is the computed, validated plan for elevating a set of trunk commits across the bottom-up environment chain up to and including a target environment. It is the multi-commit, multi-env companion to PlanResult and is additive: the single-env Plan and PlanResult are unchanged.

type PlanResult

type PlanResult struct {
	TargetEnv string `json:"target_env"`
	FixSHA    string `json:"fix_sha"`
	Branch    string `json:"branch"`
	BaseSHA   string `json:"base_sha"`

	// NoOp is true when the fix is already contained in the target state SHA.
	NoOp bool `json:"no_op"`

	// BranchCreated is true when env/<target> was (or, in dry-run, would be)
	// created at BaseSHA. False when it already existed at the expected tip.
	BranchCreated bool `json:"branch_created"`

	// HotfixVersionCandidate is the next free hotfix version over the target
	// env's current version base (e.g. v1.0.0-rc.1 -> v1.0.0-rc.1.hotfix.1).
	HotfixVersionCandidate string `json:"hotfix_version_candidate"`

	// ConflictExpected hints whether the cherry-pick is likely to conflict.
	// The plan verb does not run the cherry-pick, so this is best-effort and
	// false by default; the workflow is authoritative.
	ConflictExpected bool `json:"conflict_expected"`

	// ProtectionSuggestions are ready-to-run gh/gh api commands an operator can
	// paste to establish env/* branch protection. cascade never applies these.
	ProtectionSuggestions []string `json:"protection_suggestions"`

	DryRun bool `json:"dry_run"`
}

PlanResult is the computed, validated hotfix plan emitted as JSON and GHA outputs. It records only what the workflow needs; no mutation has happened beyond the optional env-branch creation.

type Planner

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

Planner validates and computes a hotfix plan for one environment.

func NewPlanner

func NewPlanner(opts PlannerOptions, options ...Option) (*Planner, error)

NewPlanner constructs a Planner from the manifest at opts.ConfigPath.

func (*Planner) Plan

func (p *Planner) Plan(fixRef, targetEnv string) (*PlanResult, error)

Plan validates the hotfix request and computes the env-branch plan.

fixRef is the trunk commit (or ref/short SHA) to apply; targetEnv is the environment to hotfix. It enforces, in order: trunk ancestry of the fix, target-env eligibility, no-op detection, the single-flight open-PR gate, and env-branch reconciliation. The single-flight gate runs before any branch mutation, so a blocked plan leaves no git state changes.

func (*Planner) PlanChain added in v0.3.0

func (p *Planner) PlanChain(refs []string, targetEnv string) (*PlanChainResult, error)

PlanChain validates and computes the per-environment plan for elevating a set of trunk commits across the bottom-up environment chain up to and including targetEnv. Commits are kept in the caller's ref order; environments run bottom-up. Each ref must resolve and be a trunk ancestor; each (commit, env) pair is skipped when the commit is already present in that environment (an ancestor of its state SHA or already in its patch list). An environment whose whole requested set is already present is reported as a no-op.

PlanChain is additive: it does not create branches or mutate state, and the single-env Plan and PlanResult are unchanged.

type PlannerOptions

type PlannerOptions struct {
	ConfigPath  string
	ManifestKey string
	Actor       string
}

PlannerOptions carries the required inputs for NewPlanner.

Jump to

Keyboard shortcuts

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