feat(tpagectl): add export command #627

Merged
fuzzy merged 1 commit from feat/tpagectl-export into main 2026-08-10 11:43:04 +00:00
Owner

What

Implements Phase 10 export command (roadmap #316).

  • siteconfig.Write — new shared writer for the declared site-config document (YAML default, indented JSON), complementing the existing LoadFile. This is the apply-compatible format (#315 — marked done as format-ready; a future apply consumes these files via LoadFile).
  • New internal/tpagectl/exporttpagectl export SITE:
    • #314 — export site config to file (YAML/JSON) — fetches GET /api/v1/sites/{name}, builds the SiteConfig (name, owner, visibility, custom_domain, preview_enabled), and writes it to <SITE>.yaml (or <SITE>.json with --format json; --output overrides, creating parent dirs), printing Exported site "<name>" to <path>.
    • --format validation → exit 5; site resolved positionally or via --site with the interactive picker on a terminal; 404 → friendly not-found error.

Why

Roadmap task #316.

Testing

  • siteconfig: WriteLoadFile round-trip for YAML and JSON; unsupported format error
  • export: e2e vs fake daemon — default blog.yaml contents, --format jsonblog.json, --output custom path (parent dir created), invalid --format → validation error, 404 → friendly not-found
  • export --help wiring via the root command; root-help golden + docs regenerated
  • go test -race ./... passes (35 packages); make coverage = 84.8% (≥80% gate)
  • golangci-lint run clean; pre-commit hooks pass

Breaking Changes

None. Adds an export command and a siteconfig.Write helper.

Notes

No thwap-actions action applies (CLI feature). #315 (apply, explicitly future) is closed as format-ready: the exported YAML/JSON document is exactly what a future apply will read via siteconfig.LoadFile.

Closes #314
Closes #315
Closes #316

## What Implements Phase 10 `export` command (roadmap #316). - **`siteconfig.Write`** — new shared writer for the declared site-config document (YAML default, indented JSON), complementing the existing `LoadFile`. This is the apply-compatible format (`#315` — marked done as format-ready; a future `apply` consumes these files via `LoadFile`). - **New `internal/tpagectl/export`** — `tpagectl export SITE`: - **#314 — export site config to file (YAML/JSON)** — fetches `GET /api/v1/sites/{name}`, builds the `SiteConfig` (name, owner, visibility, custom_domain, preview_enabled), and writes it to `<SITE>.yaml` (or `<SITE>.json` with `--format json`; `--output` overrides, creating parent dirs), printing `Exported site "<name>" to <path>`. - `--format` validation → exit 5; site resolved positionally or via `--site` with the interactive picker on a terminal; 404 → friendly not-found error. ## Why Roadmap task #316. ## Testing - [x] `siteconfig`: `Write` → `LoadFile` round-trip for YAML and JSON; unsupported format error - [x] `export`: e2e vs fake daemon — default `blog.yaml` contents, `--format json` → `blog.json`, `--output` custom path (parent dir created), invalid `--format` → validation error, 404 → friendly not-found - [x] `export --help` wiring via the root command; root-help golden + docs regenerated - [x] `go test -race ./...` passes (35 packages); `make coverage` = 84.8% (≥80% gate) - [x] `golangci-lint run` clean; pre-commit hooks pass ## Breaking Changes None. Adds an `export` command and a `siteconfig.Write` helper. ## Notes No `thwap-actions` action applies (CLI feature). `#315` (apply, explicitly future) is closed as format-ready: the exported YAML/JSON document is exactly what a future `apply` will read via `siteconfig.LoadFile`. Closes #314 Closes #315 Closes #316
feat(tpagectl): add export command
Some checks failed
CI / docker (pull_request) Successful in 2m58s
CI / build (pull_request) Successful in 6m5s
CI / test (pull_request) Successful in 12m48s
CI / lint (pull_request) Successful in 5m58s
CI / docker (push) Failing after 1m0s
CI / test (push) Successful in 5m37s
CI / lint (push) Successful in 5m48s
CI / build (push) Successful in 30m30s
a34f42933f
Add `tpagectl export SITE` which fetches a site from the daemon and writes
its declared configuration as a YAML or JSON site-config document:

- siteconfig.Write writes the shared SiteConfig document (YAML default,
  indented JSON); the future apply command will consume these files via
  LoadFile (#315 format-ready).
- export writes <SITE>.yaml (or <SITE>.json with --format json; --output
  overrides), creating parent directories, and prints the confirmation.
- --format validation (exit 5); site resolved positionally or via --site
  with the interactive picker on a terminal; 404 yields the friendly
  not-found error.

Documented in the README and regenerated command docs.

Closes #314
Closes #315
Closes #316
fuzzy scheduled this pull request to auto merge when all checks succeed 2026-08-10 11:33:31 +00:00
the.auditor left a comment

Clean, minimal export command. Site resolution (positional/--site/interactive), format validation (exit 5), the friendly 404 path, parent-dir creation, and the siteconfig.Write/LoadFile round-trip for YAML and JSON are all correct, and omitempty keeps empty custom domains out of the document. Approving; one data-loss risk filed.

Suggestions

  1. internal/tpagectl/export/export.go:119os.Create silently overwrites an existing <SITE>.yaml (or --output target). Since exported documents are meant to be edited and later applied, a re-export clobbers user edits. Refuse to overwrite, or require --force. Filed as #628.

Notes

  • YAML output relies on yaml.Marshal for its trailing newline; the JSON path explicitly appends \n, so a YAML file may not be POSIX-text — minor inconsistency worth checking.
  • --output blog.json without --format json writes YAML content into a .json file (format drives content, extension only matters when --output is unset) — minor UX.
  • Direct os.Create (no temp+rename) can leave a partial file on a crash mid-write — regenerable, low risk.

Praise

  • siteconfig.Write cleanly centralizes the declared-document encoding, keeping export thin and the apply-compatible format consistent with diff/future apply.
  • File errors map to KindConfig (exit 2), and success output is styled via ui.Success.
  • Round-trip tests (Write → LoadFile) cover both formats.
Clean, minimal `export` command. Site resolution (positional/`--site`/interactive), format validation (exit 5), the friendly 404 path, parent-dir creation, and the `siteconfig.Write`/`LoadFile` round-trip for YAML and JSON are all correct, and `omitempty` keeps empty custom domains out of the document. Approving; one data-loss risk filed. ## Suggestions 1. `internal/tpagectl/export/export.go:119` – `os.Create` silently overwrites an existing `<SITE>.yaml` (or `--output` target). Since exported documents are meant to be edited and later applied, a re-export clobbers user edits. Refuse to overwrite, or require `--force`. Filed as #628. ## Notes - YAML output relies on `yaml.Marshal` for its trailing newline; the JSON path explicitly appends `\n`, so a YAML file may not be POSIX-text — minor inconsistency worth checking. - `--output blog.json` without `--format json` writes YAML content into a `.json` file (format drives content, extension only matters when `--output` is unset) — minor UX. - Direct `os.Create` (no temp+rename) can leave a partial file on a crash mid-write — regenerable, low risk. ## Praise - `siteconfig.Write` cleanly centralizes the declared-document encoding, keeping `export` thin and the apply-compatible format consistent with `diff`/future `apply`. - File errors map to `KindConfig` (exit 2), and success output is styled via `ui.Success`. - Round-trip tests (Write → LoadFile) cover both formats.
fuzzy merged commit a34f42933f into main 2026-08-10 11:43:04 +00:00
fuzzy deleted branch feat/tpagectl-export 2026-08-10 11:43:05 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thwap/thwap-pagesd!627
No description provided.