Documentation
¶
Overview ¶
Package plan holds the ordered list of changes upkeep intends to make.
Index ¶
- type Action
- type Change
- type Diff
- type Op
- type Plan
- func (p *Plan) Add(actions ...Action)
- func (p Plan) Destructive() bool
- func (p Plan) Empty() bool
- func (p Plan) Executable() []Action
- func (p *Plan) Extend(other Plan)
- func (p Plan) Manual() []Action
- func (p Plan) Save(w io.Writer) error
- func (p Plan) Write(w io.Writer) error
- func (p Plan) WriteJSON(w io.Writer) error
- type Saved
- type SavedAction
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 ¶
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 ¶
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.
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) Destructive ¶
Destructive reports whether the plan deletes anything, so a caller can insist on confirmation before running it.
func (Plan) Executable ¶
Executable is everything with a Do — what apply will actually run.
func (Plan) Manual ¶
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) Write ¶
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 ¶
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 (Saved) Matches ¶
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.