feat(tpagectl): add watch command #624

Merged
fuzzy merged 1 commit from feat/tpagectl-watch into main 2026-08-09 23:48:19 +00:00
Owner

What

Implements Phase 10 watch command (roadmap #310).

  • New internal/tpagectl/watch packagetpagectl watch SITE polls the site status endpoint (GET /api/v1/sites/{name}, whose payload already carries current_deployment) every --interval (default 2s); the daemon exposes no SSE endpoint, so polling is used (#307).
  • #308 — real-time events — prints the current production deployment once, then a real-time line on every change (version, commit, status, deployed-at).
  • #309 — notify on new production deployments — the change line is the New production deployment: … notification, colored success on a terminal.
  • --once checks once and exits (scripting/CI); Ctrl-C (ctx cancel) stops cleanly; a 404 yields the friendly not-found error; transient poll errors are reported and retried.
  • Site is resolved positionally or via --site, with the interactive fuzzy picker when omitted on a terminal.
  • README example added; docs/commands/tpagectl-watch.* and the root-help golden regenerated.

Why

Roadmap task #310, the first item in Phase 10.

Testing

  • Unit: deploymentChanged (nil/same/version/commit/status transitions), formatDeployment
  • E2E: watch --once prints the current deployment; a fake server returning v1 then v2 produces the New production deployment: v2.0.0 line (short interval + canceled ctx); 404 → friendly not-found error
  • watch --help wiring via the root command
  • go test -race ./... passes (32 packages); make coverage = 84.7% (≥80% gate)
  • golangci-lint run clean; pre-commit hooks pass

Breaking Changes

None. Adds a watch command.

Notes

No thwap-actions action applies (CLI feature). Polling is used because the daemon has no events/SSE endpoint.

Closes #307
Closes #308
Closes #309
Closes #310

## What Implements Phase 10 `watch` command (roadmap #310). - **New `internal/tpagectl/watch` package** — `tpagectl watch SITE` polls the site status endpoint (`GET /api/v1/sites/{name}`, whose payload already carries `current_deployment`) every `--interval` (default `2s`); the daemon exposes no SSE endpoint, so **polling** is used (#307). - **#308 — real-time events** — prints the current production deployment once, then a real-time line on every change (version, commit, status, deployed-at). - **#309 — notify on new production deployments** — the change line is the `New production deployment: …` notification, colored success on a terminal. - `--once` checks once and exits (scripting/CI); Ctrl-C (ctx cancel) stops cleanly; a 404 yields the friendly not-found error; transient poll errors are reported and retried. - Site is resolved positionally or via `--site`, with the interactive fuzzy picker when omitted on a terminal. - README example added; `docs/commands/tpagectl-watch.*` and the root-help golden regenerated. ## Why Roadmap task #310, the first item in Phase 10. ## Testing - [x] Unit: `deploymentChanged` (nil/same/version/commit/status transitions), `formatDeployment` - [x] E2E: `watch --once` prints the current deployment; a fake server returning v1 then v2 produces the `New production deployment: v2.0.0` line (short interval + canceled ctx); 404 → friendly not-found error - [x] `watch --help` wiring via the root command - [x] `go test -race ./...` passes (32 packages); `make coverage` = 84.7% (≥80% gate) - [x] `golangci-lint run` clean; pre-commit hooks pass ## Breaking Changes None. Adds a `watch` command. ## Notes No `thwap-actions` action applies (CLI feature). Polling is used because the daemon has no events/SSE endpoint. Closes #307 Closes #308 Closes #309 Closes #310
feat(tpagectl): add watch command
All checks were successful
CI / test (pull_request) Successful in 5m58s
CI / docker (pull_request) Successful in 3m6s
CI / build (pull_request) Successful in 5m49s
CI / lint (pull_request) Successful in 5m51s
CI / build (push) Successful in 8m22s
CI / test (push) Successful in 13m5s
CI / lint (push) Successful in 13m39s
CI / docker (push) Successful in 27m58s
595cf0a42b
Add `tpagectl watch SITE` which polls the site status endpoint and prints
a notification whenever the production deployment changes:

- #307: polls GET /api/v1/sites/{name} every --interval (default 2s); the
  daemon exposes no SSE endpoint, so polling is used.
- #308: prints the current production deployment once, then a real-time
  line on every change (version, commit, status, deployed-at).
- #309: the change line is the "New production deployment: ..."
  notification, colored success on a terminal.
- --once checks once and exits (scripting/CI); Ctrl-C stops cleanly; 404
  yields the friendly not-found error; transient errors are retried.
- Site resolved positionally or via --site, with the interactive picker
  when omitted on a terminal.

Documented in the README and regenerated command docs.

Closes #307
Closes #308
Closes #309
Closes #310
fuzzy scheduled this pull request to auto merge when all checks succeed 2026-08-09 23:32:10 +00:00
fuzzy scheduled this pull request to auto merge when all checks succeed 2026-08-09 23:37:20 +00:00
the.auditor left a comment

Clean, focused watch command. Polling fits the daemon's API (no SSE), 404 maps to the friendly not-found error, transient failures are reported and retried, --once/--interval are present with a sane guard on non-positive intervals, and change detection across version/commit/status/deployed-at is correct with the notification colored success. Tests cover the core paths. Approving; one --once semantics issue filed.

Suggestions

  1. internal/tpagectl/watch/watch.go:121watch SITE --once returns nil even when the poll failed (non-404 5xx/network errors print watch: ... then fall through to return nil). For the documented scripting/CI use of --once, a failed check should exit non-zero — return the last poll error. Filed as #625.

Notes

  • A production deployment removal prints New production deployment: none — a removal, not a new deployment; wording is slightly off but harmless.
  • Ctrl-C stops via the default SIGINT handler (no signal→ctx wiring in the CLI); the clean ctx.Done() path only fires in the canceled-ctx test — practically fine.
  • Persistent-poll errors print the raw client error rather than clierr-rendered output; acceptable as informational.

Praise

  • deploymentChanged correctly handles nil transitions (none → v1 and v1 → none both detected).
  • The interval <= 0 guard prevents a tight-loop DoS from a bad flag.
  • Reuses interactive.ResolveSite and ui.Success, keeping the command consistent with the rest of the CLI.
Clean, focused `watch` command. Polling fits the daemon's API (no SSE), 404 maps to the friendly not-found error, transient failures are reported and retried, `--once`/`--interval` are present with a sane guard on non-positive intervals, and change detection across version/commit/status/deployed-at is correct with the notification colored success. Tests cover the core paths. Approving; one `--once` semantics issue filed. ## Suggestions 1. `internal/tpagectl/watch/watch.go:121` – `watch SITE --once` returns nil even when the poll failed (non-404 5xx/network errors print `watch: ...` then fall through to `return nil`). For the documented scripting/CI use of `--once`, a failed check should exit non-zero — return the last poll error. Filed as #625. ## Notes - A production deployment *removal* prints `New production deployment: none` — a removal, not a new deployment; wording is slightly off but harmless. - Ctrl-C stops via the default SIGINT handler (no signal→ctx wiring in the CLI); the clean `ctx.Done()` path only fires in the canceled-ctx test — practically fine. - Persistent-poll errors print the raw client error rather than clierr-rendered output; acceptable as informational. ## Praise - `deploymentChanged` correctly handles nil transitions (none → v1 and v1 → none both detected). - The `interval <= 0` guard prevents a tight-loop DoS from a bad flag. - Reuses `interactive.ResolveSite` and `ui.Success`, keeping the command consistent with the rest of the CLI.
fuzzy merged commit 595cf0a42b into main 2026-08-09 23:48:19 +00:00
fuzzy deleted branch feat/tpagectl-watch 2026-08-09 23:48:19 +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!624
No description provided.