Skip to content

feat: make the export machinery usable from Go - #521

Merged
josegonzalez merged 1 commit into
mainfrom
425-library-usable-export
Sep 2, 2026
Merged

feat: make the export machinery usable from Go#521
josegonzalez merged 1 commit into
mainfrom
425-library-usable-export

Conversation

@josegonzalez

@josegonzalez josegonzalez commented Sep 2, 2026

Copy link
Copy Markdown
Member

Closes #425. Closes #518. The export is the only part of docket that reads current server state back as structured data, and three things kept a Go caller from using it.

ExportResult.plays was unexported, so the only ways out were MarshalRecipe and MarshalVars - a caller wanting data had to marshal to YAML and parse it straight back, or call ExportApp directly and reimplement the ordering, warnings and sensitive-value handling the engine already does. Plays() returns the plays as exported values whose task bodies are still their own Go types, so dokku_config comes back as a ConfigTask. They are stored that way rather than converted on the way out, so the structured view and the marshalled recipe cannot describe different exports; the recipe output is byte-identical.

An address naming a global resource is now honoured alongside --app. Reading one back used to require exporting the whole server, and the combination was worse than absent: the global play was skipped and the address was then reported as missing from a server that had it, so docket export --app foo --resource 'dokku_plugin[name=redis]' exported nothing and exited non-zero.

NewTask allocates a task from the registry with its default: tags applied, and DecodeTask does the same from a YAML body. Building a task by struct literal skips those defaults, so one with no State got "" and fell into the invalid-state branch rather than behaving as present - a foot-gun the loader avoided only through an unexported function.

docs/embedding.md documents the resulting surface, including the run context, the narrowing options, and the sensitive values a caller has to register before printing anything.

Closes #425. Closes #518. The export is the only part of docket that reads
current server state back as structured data, and three things kept a Go
caller from using it.

`ExportResult.plays` was unexported, so the only ways out were
`MarshalRecipe` and `MarshalVars` - a caller wanting data had to marshal to
YAML and parse it straight back, or call `ExportApp` directly and
reimplement the ordering, warnings and sensitive-value handling the engine
already does. `Plays()` returns the plays as exported values whose task
bodies are still their own Go types. They are stored that way rather than
converted on the way out, so the structured view and the marshalled recipe
cannot describe different exports; the recipe is byte-identical.

An address naming a global resource is now honoured alongside `--app`.
Reading one back required exporting the whole server, and the combination
was worse than absent: the global play was skipped and the address was then
reported as missing from a server that had it, so the command exported
nothing and exited non-zero.

`NewTask` allocates a task from the registry with its `default:` tags
applied, and `DecodeTask` does the same from a YAML body. Building a task by
struct literal skips those defaults, so one with no `State` got "" and fell
into the invalid-state branch rather than behaving as present - a foot-gun
the loader avoided only through an unexported function.
@josegonzalez
josegonzalez merged commit a1d6a5d into main Sep 2, 2026
19 checks passed
@josegonzalez
josegonzalez deleted the 425-library-usable-export branch September 2, 2026 05:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

export --app with a global --resource address exports nothing Make the export machinery usable from Go

1 participant