commands

package
v0.0.0-...-e2b0339 Latest Latest
Warning

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

Go to latest
Published: Sep 10, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PrefixErrorMessage

func PrefixErrorMessage(err error) string

PrefixErrorMessage prepends `ssh:` or `dokku:` to err.Error() based on whether err unwraps to a *subprocess.SSHError. Exported so the plan command can reuse the same prefixing logic for the probe-error suffix that surfaces inline in the TaskLine instead of in a continuation line.

Types

type ApplyCommand

type ApplyCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdin is where a `--tasks -` recipe is read from. Populated from
	// main.go; nil reads the process's standard input. A test hands over its
	// own pipe instead of swapping os.Stdin, which no two tests can do at
	// once.
	Stdin io.Reader

	// Argv is the process argv this command resolves its --tasks and
	// --tasks-format from, before pflag has parsed anything. Populated from
	// main.go; nil falls back to os.Args, which is what a command built
	// directly gets. It exists so a test can hand the command its own argv
	// instead of assigning to the process global and putting it back.
	Argv []string

	// Ctx is the run context, populated from main.go with the process signal
	// context. It carries cancellation down through every task's Plan and
	// Execute. Nil when the command was constructed directly (tests do this),
	// in which case Run falls back to context.Background().
	Ctx context.Context
	// contains filtered or unexported fields
}

func (*ApplyCommand) Arguments

func (c *ApplyCommand) Arguments() []command.Argument

func (*ApplyCommand) AutocompleteArgs

func (c *ApplyCommand) AutocompleteArgs() complete.Predictor

func (*ApplyCommand) AutocompleteFlags

func (c *ApplyCommand) AutocompleteFlags() complete.Flags

func (*ApplyCommand) Examples

func (c *ApplyCommand) Examples() map[string]string

func (*ApplyCommand) FlagSet

func (c *ApplyCommand) FlagSet() *flag.FlagSet

func (*ApplyCommand) Help

func (c *ApplyCommand) Help() string

func (*ApplyCommand) Name

func (c *ApplyCommand) Name() string

func (*ApplyCommand) ParsedArguments

func (c *ApplyCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*ApplyCommand) Run

func (c *ApplyCommand) Run(args []string) int

Run executes every task in the parsed recipe against the live server, printing a one-line summary per task plus a final summary line.

Exit codes (default):

0 - the run completed without errors, whether or not anything changed
1 - read error, parse error, or at least one task errored

Exit codes (--detailed-exitcode):

0 - the run completed cleanly; nothing changed
1 - read error, parse error, or at least one task errored (errors win)
2 - the run completed; at least one task changed server state

--list-tasks returns before any task runs, so it is unaffected by --detailed-exitcode and still exits 0 or 1.

func (*ApplyCommand) Synopsis

func (c *ApplyCommand) Synopsis() string

type ApplyCounts

type ApplyCounts struct {
	Tasks        int
	Changed      int
	OK           int
	Skipped      int
	Errors       int
	PlaysSkipped int
}

ApplyCounts holds the running totals printed by the apply summary line.

type ApplyTaskEvent

type ApplyTaskEvent struct {
	// Play is the name of the enclosing play (today always "tasks").
	Play string
	// Name is the task's envelope name.
	Name string
	// State is the post-execute state returned by Task.Execute.
	// Zero-value State is acceptable for the WhenError / Skipped branches.
	State tasks.TaskOutputState
	// WhenError, when non-nil, indicates the `when:` predicate raised an
	// expr error and the task did not run. Mutually exclusive with the
	// other branches.
	WhenError error
	// Skipped indicates the `when:` predicate evaluated to false and the
	// task was filtered out. Mutually exclusive with the other branches.
	Skipped bool
	// SkipReason carries a short human-readable annotation rendered as a
	// parenthetical suffix after the [skipped] marker. Set when the
	// skip is driven by something other than `when:` (e.g.
	// "before --start-at-task"). Empty for plain `when:`-driven skips so
	// the line stays terse.
	SkipReason string
	// InvalidState, when true, indicates Execute reported success but the
	// final State did not match DesiredState; treated as an error in
	// counts and exit logic.
	InvalidState bool
	// Ignored, when true, indicates the task errored but `ignore_errors:
	// true` suppressed the fatal-exit decision. The event is still
	// emitted with the `[error]` marker so the user sees what failed,
	// but the run continues and the error does not count toward the
	// summary.
	Ignored bool
	// Phase labels group children (#211): "block", "rescue", or
	// "always". Empty for top-level tasks and for the group's own
	// summary event. The formatter indents children one level and
	// surfaces the phase as a marker on the continuation line; the
	// JSON emitter exposes the same value under a `phase` key.
	Phase string
	// Group, when true, marks the event as a group summary (#211)
	// rather than a leaf or child task. The formatter renders these
	// with a `(group)` annotation so the user can spot the group's
	// own outcome at a glance.
	Group bool
	// Duration is the wall-clock time Execute took (or zero for the
	// when-skipped / when-error branches).
	Duration time.Duration
	// Timestamp is when the event was produced (UTC). The JSON emitter
	// serialises this as the `ts` field; the human emitter ignores it.
	Timestamp time.Time
}

ApplyTaskEvent describes a single task outcome from an apply run. The run-loop in commands/apply.go populates this once per task and hands it to the active emitter; the emitter decides how to render it.

type Argument

type Argument struct {
	Required  bool
	Sensitive bool
	// HasDefault records whether the recipe declared a non-empty `default:`
	// for this input. It is the half of "the value was actually supplied"
	// that the flag pointer cannot answer: a bool / int / float pointer is
	// never nil, so GetValue() cannot tell an implicit zero apart from a
	// declared or user-typed one. Paired with userSetKeys it drives both the
	// required-input check and the decision to register a sensitive value.
	HasDefault bool
	// Type is the declared input type ("string", "int", "float", "bool"). It
	// is normalised to the canonical lowercase form; an empty `type:` field
	// in the recipe stores as "string", and so does a type docket does not
	// implement, which the loader rejects as invalid_input_type before the
	// value is ever read. Used by SetFromVarsFile to coerce loosely-typed map
	// values from a --vars-file into the same Go type pflag would have
	// produced from the equivalent CLI flag.
	Type string
	// contains filtered or unexported fields
}

func (Argument) ContextValue

func (c Argument) ContextValue() interface{}

ContextValue returns the value the recipe sees for this input: the concrete Go value rather than the flag pointer GetValue reports.

The pointer is pflag's, not something the recipe asked for, and putting it in the render / predicate context leaked it into two evaluators that each read a pointer as "true" (#497). expr dereferences the operands of an operator but not a program that is nothing but an identifier, so `when: debug` tested the pointer - never nil for a bool / int / float - instead of the value. text/template's own isTrue counts any non-nil pointer as true, so `{{ if .debug }}` in a recipe body did the same.

It differs from GetValue in one place, on purpose: an empty string is a value, not nil, so an input left at its zero value renders as the empty string rather than as text/template's `<no value>`. GetValue keeps the nil because HasValue, IsSatisfied, and StringValue read it as "nothing was supplied".

func (Argument) GetValue

func (c Argument) GetValue() interface{}

func (Argument) HasValue

func (c Argument) HasValue() bool

func (Argument) IsSatisfied

func (c Argument) IsSatisfied(userSet bool) bool

IsSatisfied reports whether this input has a non-empty value that the recipe or the operator actually wrote. It is the test behind `required: true`, and it needs both halves:

HasValue() alone cannot answer it, because pflag's pointer for a bool / int / float is never nil - every non-string input looked satisfied, so `required:` was enforced for strings only (#493). "The user typed the flag" alone cannot answer it either, because `--app=` types the flag and supplies nothing; the input would resolve to an empty string and render an empty app name.

userSet is whether the operator supplied a value for this input, on the command line or through a --vars-file; see userSetKeys.

func (*Argument) SetBoolValue

func (c *Argument) SetBoolValue(ptr *bool)

func (*Argument) SetFloatValue

func (c *Argument) SetFloatValue(ptr *float64)

func (*Argument) SetFromVarsFile

func (c *Argument) SetFromVarsFile(name string, value interface{}) error

SetFromVarsFile coerces value to the Argument's declared Type and writes it through the underlying typed pointer that registerInputFlags allocated. The resulting state is indistinguishable from a CLI flag at the same value having been parsed by pflag, so the existing GetValue / HasValue / StringValue / Sensitive plumbing keeps working without per-call branching.

Loose typing (YAML decodes "42" as a string when quoted but as int64 when bare; JSON always gives float64 for numbers) is normalised here so vars files written by hand or generated by another tool both feed the same pflag-shaped pointer.

func (*Argument) SetIntValue

func (c *Argument) SetIntValue(ptr *int)

func (*Argument) SetStringValue

func (c *Argument) SetStringValue(ptr *string)

func (Argument) StringValue

func (c Argument) StringValue() string

StringValue returns the argument's value formatted as the same string sigil will substitute into the rendered YAML. Returns "" when no value is set. Used to register sensitive input values with the subprocess masker.

type EventEmitter

type EventEmitter interface {
	// PlayStart announces the beginning of a play. host is the optional
	// remote host annotation, "" for local execution.
	PlayStart(name, host string)
	// PlaySkipped announces a play that was filtered out by its `when:`
	// predicate. whenSrc is the raw expr source so the human formatter
	// can quote it back at the user.
	PlaySkipped(name, whenSrc string)
	// ApplyTask emits one event per task in an `apply` run.
	ApplyTask(ev ApplyTaskEvent)
	// PlanTask emits one event per task in a `plan` run.
	PlanTask(ev PlanTaskEvent)
	// TaskWarning emits a non-fatal warning associated with a task, such
	// as a task-type deprecation notice or a property probe diagnostic. It
	// does not affect task counts or exit codes. reason is a stable machine
	// key ("deprecated", or a tasks.WarnReason* value) the JSON emitter
	// surfaces and the human emitter maps to a marker. The warning is
	// emitted before the per-task event so it appears above the task's
	// result line.
	TaskWarning(play, name, reason, message string)
	// ApplySummary emits the end-of-run footer for `apply`.
	ApplySummary(c ApplyCounts, d time.Duration)
	// PlanSummary emits the end-of-run footer for `plan`.
	PlanSummary(c PlanCounts, d time.Duration)
}

EventEmitter is the structured event sink consumed by `apply` and `plan`. Both the human Formatter and the JSONEmitter implement it. The executor in apply.go / plan.go constructs the right emitter at the top of Run() based on the --json flag and funnels each per-task branch through the interface so the two output modes stay in lock-step.

type ExportCommand

type ExportCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdout is where a streamed recipe, diff or catalog is written. Populated
	// from main.go; nil writes to the process's standard output. These writes
	// bypass Ui on purpose - it is wrapped in a log formatter - so a test that
	// asserts on them needs somewhere of its own to capture.
	Stdout io.Writer

	// Ctx is the run context, populated from main.go with the process signal
	// context. It carries cancellation down through every task's Plan and
	// Execute. Nil when the command was constructed directly (tests do this),
	// in which case Run falls back to context.Background().
	Ctx context.Context

	// ChmodVarsFile overrides how the companion vars-file's mode is set. Only
	// a test sets it, to force the failure path; nil uses os.File.Chmod.
	ChmodVarsFile chmodFunc
	// contains filtered or unexported fields
}

ExportCommand reads a live Dokku server and writes a recipe describing it - the inverse of apply. Sensitive values are lifted into a companion vars-file that the emitted recipe references through inputs, so the pair applies with `docket apply --vars-file <vars>`.

func (*ExportCommand) Arguments

func (c *ExportCommand) Arguments() []command.Argument

func (*ExportCommand) AutocompleteArgs

func (c *ExportCommand) AutocompleteArgs() complete.Predictor

func (*ExportCommand) AutocompleteFlags

func (c *ExportCommand) AutocompleteFlags() complete.Flags

func (*ExportCommand) Examples

func (c *ExportCommand) Examples() map[string]string

func (*ExportCommand) FlagSet

func (c *ExportCommand) FlagSet() *flag.FlagSet

func (*ExportCommand) Help

func (c *ExportCommand) Help() string

func (*ExportCommand) Name

func (c *ExportCommand) Name() string

func (*ExportCommand) ParsedArguments

func (c *ExportCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*ExportCommand) Run

func (c *ExportCommand) Run(args []string) int

Run reads the server, marshals the recipe (and vars-file), and writes them. Exit codes:

0 - export written (or streamed to stdout)
1 - flag parse error, a file-only flag combined with --output -, read
    error, an output file exists without --overwrite (and the prompt was
    declined or stdin is not interactive), or an IO error

func (*ExportCommand) Synopsis

func (c *ExportCommand) Synopsis() string

type FmtCommand

type FmtCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdout is where a streamed recipe, diff or catalog is written. Populated
	// from main.go; nil writes to the process's standard output. These writes
	// bypass Ui on purpose - it is wrapped in a log formatter - so a test that
	// asserts on them needs somewhere of its own to capture.
	Stdout io.Writer

	// Stdin is where a `--tasks -` recipe is read from. Populated from
	// main.go; nil reads the process's standard input. A test hands over its
	// own pipe instead of swapping os.Stdin, which no two tests can do at
	// once.
	Stdin io.Reader
	// contains filtered or unexported fields
}

FmtCommand canonicalises tasks.yml files in place. CLI semantics are modeled after black / ruff format: --check controls exit-code-on- mismatch, --diff controls whether the unified diff is printed, the two flags compose. Default (no flags) writes each file in place.

fmt is offline by contract: it never opens a subprocess and never contacts the Dokku server.

func (*FmtCommand) Arguments

func (c *FmtCommand) Arguments() []command.Argument

func (*FmtCommand) AutocompleteArgs

func (c *FmtCommand) AutocompleteArgs() complete.Predictor

func (*FmtCommand) AutocompleteFlags

func (c *FmtCommand) AutocompleteFlags() complete.Flags

func (*FmtCommand) Examples

func (c *FmtCommand) Examples() map[string]string

func (*FmtCommand) FlagSet

func (c *FmtCommand) FlagSet() *flag.FlagSet

func (*FmtCommand) Help

func (c *FmtCommand) Help() string

func (*FmtCommand) Name

func (c *FmtCommand) Name() string

func (*FmtCommand) ParsedArguments

func (c *FmtCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*FmtCommand) Run

func (c *FmtCommand) Run(args []string) int

Run executes fmt against the resolved file list and reports per-file outcomes. Exit codes:

0 - every file is canonical (or was successfully formatted, converted,
    or written to --output)
1 - flag parse error, a rejected flag combination, an --output that
    would overwrite an existing file without --force, IO error, parse /
    round-trip failure, a --check that would have to convert, or a
    --check mismatch on at least one file

func (*FmtCommand) Synopsis

func (c *FmtCommand) Synopsis() string

type Formatter

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

Formatter renders the structured per-task output for `apply` and `plan`. It owns marker padding, color decisions, and the play / summary line shapes so both subcommands stay visually consistent.

Color is resolved once at construction and honours NO_COLOR plus stdout-isatty, matching fatih/color's defaults. When the active Ui is not the real terminal Ui (e.g. cli.MockUi in tests), color is also forced off so test assertions stay stable.

func NewFormatter

func NewFormatter(ui cli.Ui, verbose bool, masker *subprocess.Masker) *Formatter

NewFormatter constructs a Formatter bound to the given Ui. verbose controls whether `→`-prefixed continuation lines are emitted under each task line in apply mode.

func (*Formatter) ApplySummary

func (f *Formatter) ApplySummary(c ApplyCounts, elapsed time.Duration)

ApplySummary emits the blank line and `Summary: ...` footer that follows an apply run. elapsed is rendered with one decimal of seconds, matching the spec in issue #202.

When one or more plays were filtered out by their `when:` predicate (#208), an extra `· N play(s) skipped` segment is appended before the duration so the user sees both the per-task skip count and the per-play skip count.

func (*Formatter) ApplyTask

func (f *Formatter) ApplyTask(ev ApplyTaskEvent)

ApplyTask renders one apply task line plus optional continuations, matching the legacy formatter dispatch in commands/apply.go.

func (*Formatter) Continuation

func (f *Formatter) Continuation(prefix rune, body string)

Continuation emits an indented continuation line under the most recent task line. prefix is the leading rune (`!` for errors, `→` for the verbose command echo, `-` for plan mutation items). Each line of `body` is emitted as its own continuation so multi-line stderr renders cleanly under the marker column. The body is masked against the global sensitive value set before output.

func (*Formatter) ErrorContinuation

func (f *Formatter) ErrorContinuation(err error)

ErrorContinuation emits an `! <prefix>: <body>` continuation line under an errored task. The prefix is `ssh` when err unwraps to a *subprocess.SSHError (transport-level failure: connect, auth, host-key) and `dokku` otherwise (remote command exit). Multi-line bodies are masked and rendered as separate continuation lines under the same indent.

func (*Formatter) PlanSummary

func (f *Formatter) PlanSummary(c PlanCounts, _ time.Duration)

PlanSummary emits the blank line and `Plan: ...` footer that follows a plan run. The format intentionally matches the legacy shape so existing CI consumers (and the bats partial-match assertions in tests/bats/plan.bats) keep working. The skipped count is appended only when at least one task was filtered out by `when:`, so recipes that do not exercise envelope predicates still produce the legacy summary.

The elapsed duration is accepted for parity with ApplySummary and EventEmitter, but the human plan summary line does not render it (the legacy format omits timing). The JSON emitter consumes it.

func (*Formatter) PlanTask

func (f *Formatter) PlanTask(ev PlanTaskEvent)

PlanTask renders one plan task line plus optional continuations, matching the legacy formatter dispatch in commands/plan.go.

func (*Formatter) PlayHeader

func (f *Formatter) PlayHeader(name string)

PlayHeader emits a `==> Play: <name>` line above the per-task listing. Used once per play; until #208 lands, callers emit one header per run.

func (*Formatter) PlayHeaderWithHost

func (f *Formatter) PlayHeaderWithHost(name, host string)

PlayHeaderWithHost is like PlayHeader but appends a `(host: <name>)` annotation when the apply/plan run targets a remote dokku host (DOKKU_HOST set). When host is empty it delegates to PlayHeader so callers can pass `os.Getenv("DOKKU_HOST")` unconditionally.

func (*Formatter) PlaySkipped

func (f *Formatter) PlaySkipped(name, whenSrc string)

PlaySkipped renders a `==> Play: <name> (skipped: when "<src>")` line for a play whose `when:` predicate evaluated to false. whenSrc is the raw expr source; the formatter quotes it back so the user can see which predicate caused the skip. Both the name and whenSrc are masked against the global sensitive value set: a play predicate can sigil-interpolate a sensitive input, so whenSrc (and the same string wrapped with an eval error by apply/plan) may contain the literal secret.

func (*Formatter) PlayStart

func (f *Formatter) PlayStart(name, host string)

PlayStart satisfies EventEmitter; delegates to PlayHeaderWithHost.

func (*Formatter) TaskLine

func (f *Formatter) TaskLine(m Marker, name, suffix string)

TaskLine emits one structured task line: a colored, bracketed, padded marker followed by the task name. suffix, when non-empty, is appended after two spaces (matching the legacy plan-line layout).

Errored task lines are routed through Ui.Error so they land on stderr and inherit the cli-skeleton error styling. Both the name and the suffix are masked against the global sensitive value set: the name can carry a secret via a loop expansion (`… (item=<value>)`), and the suffix can carry a secret via a plan reason or stderr context.

func (*Formatter) TaskWarning

func (f *Formatter) TaskWarning(_, name, reason, message string)

TaskWarning renders a `[<marker>] <name> (<message>)` line above the task's result line. It is informational, so the line goes to Ui.Output (not Ui.Error) and does not affect counts. The marker is `[deprecated]` for a deprecation notice and `[warning]` for any other diagnostic. The message is masked against the global sensitive set.

func (*Formatter) Verbose

func (f *Formatter) Verbose() bool

Verbose reports whether the formatter is in verbose mode.

type InitCommand

type InitCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdout is where a streamed recipe, diff or catalog is written. Populated
	// from main.go; nil writes to the process's standard output. These writes
	// bypass Ui on purpose - it is wrapped in a log formatter - so a test that
	// asserts on them needs somewhere of its own to capture.
	Stdout io.Writer
	// contains filtered or unexported fields
}

InitCommand scaffolds a starter tasks.yml from an embedded template.

init is offline by contract: it never opens a subprocess and never contacts the Dokku server. All defaults are derived from the working directory (cwd basename for --name, ./.git/config for --repo).

func (*InitCommand) Arguments

func (c *InitCommand) Arguments() []command.Argument

func (*InitCommand) AutocompleteArgs

func (c *InitCommand) AutocompleteArgs() complete.Predictor

func (*InitCommand) AutocompleteFlags

func (c *InitCommand) AutocompleteFlags() complete.Flags

func (*InitCommand) Examples

func (c *InitCommand) Examples() map[string]string

func (*InitCommand) FlagSet

func (c *InitCommand) FlagSet() *flag.FlagSet

func (*InitCommand) Help

func (c *InitCommand) Help() string

func (*InitCommand) Name

func (c *InitCommand) Name() string

func (*InitCommand) ParsedArguments

func (c *InitCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*InitCommand) Run

func (c *InitCommand) Run(args []string) int

Run renders the scaffold and writes it. Exit codes:

0 - scaffold written
1 - flag parse error, --force combined with --output -, output file
    already exists without --force, template render error, IO error

func (*InitCommand) Synopsis

func (c *InitCommand) Synopsis() string

type JSONEmitter

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

JSONEmitter writes one JSON-lines event per call to the underlying Ui's stdout (Output) sink. Sensitive values registered via the run's masker are masked before any string field that could carry them is serialised.

func NewJSONEmitter

func NewJSONEmitter(ui cli.Ui, masker *subprocess.Masker) *JSONEmitter

NewJSONEmitter constructs a JSONEmitter bound to the given Ui.

func (*JSONEmitter) ApplySummary

func (e *JSONEmitter) ApplySummary(c ApplyCounts, d time.Duration)

ApplySummary emits the end-of-run summary event for apply.

func (*JSONEmitter) ApplyTask

func (e *JSONEmitter) ApplyTask(ev ApplyTaskEvent)

ApplyTask emits one `task` event for an apply run. Status is one of "ok", "changed", "skipped", "error".

func (*JSONEmitter) PlanSummary

func (e *JSONEmitter) PlanSummary(c PlanCounts, d time.Duration)

PlanSummary emits the end-of-run summary event for plan.

func (*JSONEmitter) PlanTask

func (e *JSONEmitter) PlanTask(ev PlanTaskEvent)

PlanTask emits one `task` event for a plan run. Status is one of "ok", "+", "~", "-", "skipped", "error".

func (*JSONEmitter) PlaySkipped

func (e *JSONEmitter) PlaySkipped(name, whenSrc string)

PlaySkipped emits a `play_skipped` event for a play that was filtered out by its `when:` predicate. The reason field carries the raw expr source so consumers can correlate the skip with the recipe. The name, when, and reason are masked against the global sensitive value set: a play predicate can sigil-interpolate a sensitive input, so whenSrc (and the same string wrapped with an eval error by apply/plan) may contain the literal secret.

func (*JSONEmitter) PlayStart

func (e *JSONEmitter) PlayStart(name, host string)

PlayStart emits a `play_start` event.

func (*JSONEmitter) TaskWarning

func (e *JSONEmitter) TaskWarning(play, name, reason, message string)

TaskWarning emits a `warning` event keyed by `reason` and tied to a specific task. reason is "deprecated" for a deprecation notice or a tasks.WarnReason* value for a probe diagnostic; the event is emitted before the task's own `task` event so consumers can correlate by ordering.

type Marker

type Marker string

Marker is the bracketed status marker that prefixes a task line. The concrete strings (without brackets) match the conventions documented in issue #202: apply uses ok/changed/skipped/error, plan uses ok/+/~/-/!.

const (
	// Apply markers
	MarkerOK      Marker = "ok"
	MarkerChanged Marker = "changed"
	MarkerSkipped Marker = "skipped"
	MarkerError   Marker = "error"

	// Plan markers (PlanStatusOK reuses MarkerOK)
	MarkerCreate     Marker = "+"
	MarkerModify     Marker = "~"
	MarkerDestroy    Marker = "-"
	MarkerProbeError Marker = "!"

	// MarkerDeprecated prefixes a TaskWarning line emitted when a task
	// type implements DeprecationDocer. Distinct from the apply/plan
	// markers because the warning is informational and does not feed
	// the run counts or exit code.
	MarkerDeprecated Marker = "deprecated"

	// MarkerWarning prefixes a TaskWarning line for a non-deprecation
	// diagnostic (for example a property probe that found no matching
	// report key). Like MarkerDeprecated it is informational and does not
	// feed the run counts or exit code.
	MarkerWarning Marker = "warning"
)

type PlanCommand

type PlanCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdin is where a `--tasks -` recipe is read from. Populated from
	// main.go; nil reads the process's standard input. A test hands over its
	// own pipe instead of swapping os.Stdin, which no two tests can do at
	// once.
	Stdin io.Reader

	// Argv is the process argv this command resolves its --tasks and
	// --tasks-format from, before pflag has parsed anything. Populated from
	// main.go; nil falls back to os.Args, which is what a command built
	// directly gets. It exists so a test can hand the command its own argv
	// instead of assigning to the process global and putting it back.
	Argv []string

	// Ctx is the run context, populated from main.go with the process signal
	// context. It carries cancellation down through every task's Plan and
	// Execute. Nil when the command was constructed directly (tests do this),
	// in which case Run falls back to context.Background().
	Ctx context.Context
	// contains filtered or unexported fields
}

PlanCommand reports the drift each task in a docket recipe would produce against the live server, without mutating it. Plan is fully driven by the per-task Plan() method; the apply path is never invoked.

func (*PlanCommand) Arguments

func (c *PlanCommand) Arguments() []command.Argument

func (*PlanCommand) AutocompleteArgs

func (c *PlanCommand) AutocompleteArgs() complete.Predictor

func (*PlanCommand) AutocompleteFlags

func (c *PlanCommand) AutocompleteFlags() complete.Flags

func (*PlanCommand) Examples

func (c *PlanCommand) Examples() map[string]string

func (*PlanCommand) FlagSet

func (c *PlanCommand) FlagSet() *flag.FlagSet

func (*PlanCommand) Help

func (c *PlanCommand) Help() string

func (*PlanCommand) Name

func (c *PlanCommand) Name() string

func (*PlanCommand) ParsedArguments

func (c *PlanCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*PlanCommand) Run

func (c *PlanCommand) Run(args []string) int

Run iterates every task in the parsed recipe, invokes Plan() (read-only by contract), and prints a one-line summary per task plus a final summary line.

Exit codes (default):

0 - plan completed successfully (regardless of drift)
1 - read error, parse error, or read-state probe error

Exit codes (--detailed-exitcode):

0 - plan completed cleanly; no drift detected
1 - read error, parse error, or read-state probe error (errors win)
2 - plan completed; at least one task reported drift

func (*PlanCommand) Synopsis

func (c *PlanCommand) Synopsis() string

type PlanCounts

type PlanCounts struct {
	Tasks        int
	WouldChange  int
	InSync       int
	Skipped      int
	Errors       int
	PlaysSkipped int
}

PlanCounts holds the running totals printed by the plan summary line.

type PlanTaskEvent

type PlanTaskEvent struct {
	Play      string
	Name      string
	Result    tasks.PlanResult
	WhenError error
	Skipped   bool
	// Phase labels group children (#211): "block", "rescue", or
	// "always". Empty for top-level tasks and for the group's own
	// summary event.
	Phase string
	// Group, when true, marks the event as a group summary (#211).
	Group     bool
	Duration  time.Duration
	Timestamp time.Time
}

PlanTaskEvent describes a single task outcome from a plan run.

type SchemaCommand

type SchemaCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdout is where a streamed recipe, diff or catalog is written. Populated
	// from main.go; nil writes to the process's standard output. These writes
	// bypass Ui on purpose - it is wrapped in a log formatter - so a test that
	// asserts on them needs somewhere of its own to capture.
	Stdout io.Writer
	// contains filtered or unexported fields
}

SchemaCommand prints the machine-readable catalog of task types.

docket knows the full shape of every task it registers - fields, types, defaults, choices, which values are secrets, what each task addresses, and for a property task the exact set of property names it accepts. Until this command existed, the only way to get at that was to read the generated markdown under docs/tasks/ or to vendor the reflection (#422). The catalog is the same data the reference pages are rendered from, so the two can never disagree.

It is offline by contract: no subprocess, no server, and no recipe. The answer depends only on which docket binary is running, which is why the catalog is not a committed file - it cannot go stale.

--task narrows it to named task types (#459). The document keeps its shape - a version and a tasks array - so a consumer parses one format either way and the published JSON Schema covers both.

func (*SchemaCommand) Arguments

func (c *SchemaCommand) Arguments() []command.Argument

func (*SchemaCommand) AutocompleteArgs

func (c *SchemaCommand) AutocompleteArgs() complete.Predictor

func (*SchemaCommand) AutocompleteFlags

func (c *SchemaCommand) AutocompleteFlags() complete.Flags

func (*SchemaCommand) Examples

func (c *SchemaCommand) Examples() map[string]string

func (*SchemaCommand) FlagSet

func (c *SchemaCommand) FlagSet() *flag.FlagSet

func (*SchemaCommand) Help

func (c *SchemaCommand) Help() string

func (*SchemaCommand) Name

func (c *SchemaCommand) Name() string

func (*SchemaCommand) ParsedArguments

func (c *SchemaCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*SchemaCommand) Run

func (c *SchemaCommand) Run(args []string) int

Run builds the catalog and writes it. Exit codes:

0 - catalog written
1 - flag parse error, unexpected positional argument, unknown --task type,
    or IO error

func (*SchemaCommand) Synopsis

func (c *SchemaCommand) Synopsis() string

type ValidateCommand

type ValidateCommand struct {
	command.Meta

	// BaseDir is the directory relative paths resolve against - the recipe
	// probed when --tasks is absent, and any output written to a relative
	// path. Populated from main.go; empty means the process working
	// directory, which is what it always was.
	//
	// It exists so a test can point a command at a temp directory instead of
	// chdir'ing the whole process, which no test can do while another runs
	// beside it.
	BaseDir string

	// Stdin is where a `--tasks -` recipe is read from. Populated from
	// main.go; nil reads the process's standard input. A test hands over its
	// own pipe instead of swapping os.Stdin, which no two tests can do at
	// once.
	Stdin io.Reader

	// Argv is the process argv this command resolves its --tasks and
	// --tasks-format from, before pflag has parsed anything. Populated from
	// main.go; nil falls back to os.Args, which is what a command built
	// directly gets. It exists so a test can hand the command its own argv
	// instead of assigning to the process global and putting it back.
	Argv []string
	// contains filtered or unexported fields
}

ValidateCommand performs offline schema and template checks against a docket recipe without contacting a Dokku server.

func (*ValidateCommand) Arguments

func (c *ValidateCommand) Arguments() []command.Argument

func (*ValidateCommand) AutocompleteArgs

func (c *ValidateCommand) AutocompleteArgs() complete.Predictor

func (*ValidateCommand) AutocompleteFlags

func (c *ValidateCommand) AutocompleteFlags() complete.Flags

func (*ValidateCommand) Examples

func (c *ValidateCommand) Examples() map[string]string

func (*ValidateCommand) FlagSet

func (c *ValidateCommand) FlagSet() *flag.FlagSet

func (*ValidateCommand) Help

func (c *ValidateCommand) Help() string

func (*ValidateCommand) Name

func (c *ValidateCommand) Name() string

func (*ValidateCommand) ParsedArguments

func (c *ValidateCommand) ParsedArguments(args []string) (map[string]command.Argument, error)

func (*ValidateCommand) Run

func (c *ValidateCommand) Run(args []string) int

Run loads the tasks file and reports every problem the validator finds.

Exit codes:

0 - no problems found
1 - file read failed, or the validator returned at least one problem

func (*ValidateCommand) Synopsis

func (c *ValidateCommand) Synopsis() string

Directories

Path Synopsis
Package templates ships the embedded scaffolds used by `docket init`.
Package templates ships the embedded scaffolds used by `docket init`.

Jump to

Keyboard shortcuts

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