plan

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package plan holds the ordered list of changes upkeep intends to make.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Action

type Action struct {
	Op       Op
	Resource string // render-env, render-deploy, r2-bucket, r2-cors, r2-public, pages, neon
	Target   string // which service, bucket, project — the thing being changed
	Detail   string // human-readable, and NEVER a secret value
	Do       func(context.Context) error
}

Action is one intended change. Do performs it and must be idempotent: a rerun after a partial apply has to be safe. Do is nil exactly when Op is OpManual.

type Change

type Change struct {
	Field string
	From  string
	To    string
}

Change is one field whose value moved. Neither side is ever a secret: this is for lists of origins, methods and header names.

type Diff

type Diff struct {
	Added   []string
	Removed []string
	Changed []Change
}

Diff describes a change to something with structure, in terms of what moved rather than what the result should be.

"differs from the config: https://a https://b allow PUT with content-type" restates the destination and leaves the reader to spot the difference themselves — against a rule with four origins and six headers, nobody does. "+cache-control" is the whole change.

func SetDiff

func SetDiff(field string, from, to []string) Diff

SetDiff compares two unordered lists of names.

func (Diff) Empty

func (d Diff) Empty() bool

func (*Diff) Merge

func (d *Diff) Merge(other Diff)

Merge folds another diff into this one.

func (*Diff) Set

func (d *Diff) Set(field, from, to string)

Set records a scalar that moved.

func (Diff) String

func (d Diff) String() string

String renders the difference for a plan line: additions, removals, then anything that moved.

type Op

type Op string
const (
	OpCreate Op = "CREATE"
	OpUpdate Op = "UPDATE"
	OpDelete Op = "DELETE"
	// OpManual is a change a human must complete outside upkeep, because a
	// credential can only be minted by hand or a value is nobody's to invent.
	// It renders in the plan but is never executed, so a converged plan that
	// still lists a manual action is not a failure to converge.
	//
	// This is the whole reason the tool is worth having. An R2 API token cannot
	// be created from any CLI — the permission does not exist on an OAuth
	// session — so a tool that could only automate would report success on a
	// deployment whose photo upload was dead. Naming the gap IS the feature.
	OpManual Op = "MANUAL"
)

type Plan

type Plan struct {
	Actions []Action
}

func (*Plan) Add

func (p *Plan) Add(actions ...Action)

func (Plan) Destructive

func (p Plan) Destructive() bool

Destructive reports whether the plan deletes anything, so a caller can insist on confirmation before running it.

func (Plan) Empty

func (p Plan) Empty() bool

func (Plan) Executable

func (p Plan) Executable() []Action

Executable is everything with a Do — what apply will actually run.

func (*Plan) Extend

func (p *Plan) Extend(other Plan)

func (Plan) Manual

func (p Plan) Manual() []Action

Manual returns the actions no tool can perform. A caller that reports success should still surface these, or it is reporting a half-built deployment as a finished one.

func (Plan) Save

func (p Plan) Save(w io.Writer) error

Save writes the plan for a later apply.

func (Plan) Write

func (p Plan) Write(w io.Writer) error

Write renders the plan as aligned columns, grouped by resource, in a stable order so two runs of an unchanged config produce identical output.

func (Plan) WriteJSON

func (p Plan) WriteJSON(w io.Writer) error

WriteJSON renders the plan for something other than a person: a CI step deciding whether to fail, a dashboard, a diff between two runs.

Detail is included and values are not, which is the same rule the text rendering follows — a machine-readable plan that leaked what the text one hides would be a way around the guarantee rather than a second view of it.

type Saved

type Saved struct {
	Version int           `json:"version"`
	Actions []SavedAction `json:"actions"`
}

A Saved plan is what you reviewed, written down.

`upkeep apply` on its own re-reads live state, so what runs is not necessarily what you read a minute ago — someone else's deploy, a dashboard edit, or a provider's own housekeeping can move the world in between. Saving the plan and applying THAT closes the gap, the way `terraform plan -out` does.

It records intent rather than closures: an Action carries a func, which cannot be serialised, and a file full of instructions to run blind would be a worse thing to hand a machine than the config was. On apply, upkeep re-plans from the same config and refuses unless the new plan is identical to the saved one. Same guarantee, and it fails loudly when the world moved instead of quietly doing something you never saw.

func LoadSaved

func LoadSaved(r io.Reader) (Saved, error)

LoadSaved reads a plan written by Save.

func (Saved) Matches

func (s Saved) Matches(fresh Plan) error

Matches reports whether a freshly read plan is the one that was reviewed.

The comparison is every field including the detail, because the detail is where the reason lives: "not set on the service" and "differs from the config" are different facts about the same key, and a reviewer who approved one did not approve the other.

func (Saved) Write

func (s Saved) Write(w io.Writer) error

Write renders a saved plan the same way a live one is rendered, so reviewing a file and reviewing a run look identical.

type SavedAction

type SavedAction struct {
	Op       string `json:"op"`
	Resource string `json:"resource"`
	Target   string `json:"target"`
	Detail   string `json:"detail"`
}

SavedAction is one line of a reviewed plan. It holds no values, for the same reason nothing else here does.

Jump to

Keyboard shortcuts

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