Skip to content

Add --format json to CLI commands - #388

Draft
dhruv8sh wants to merge 3 commits into
mainfrom
spec/383-cli-format-json
Draft

dhruv8sh wants to merge 3 commits into
mainfrom
spec/383-cli-format-json

Conversation

@dhruv8sh

Copy link
Copy Markdown

Summary

  • CI scripts that drive EdgeZero have had to scrape key=value log lines that were never a stable contract. Nine commands now accept --format json: active-version, auth status, build, config gc, config validate, deploy, healthcheck, provision and rollback. Each one writes a single versioned envelope, { schema_version, command, ok, result, error }, to stdout, on success and on failure.
  • stdout stays clean because, under JSON, logs and every child process's stdout (cargo, fastly, wrangler, spin, manifest commands) go to stderr. A new clippy disallowed-methods lint means future code can't bypass this. --format text is the default, and its output is byte-identical to main.
  • Follows the spec that Add --json output across the CLI #383 requires, included in this PR as docs/superpowers/specs/2026-09-25-cli-format-json-design.md. config diff --format json is unchanged.

Changes

Crate / File Change
edgezero-adapter (registry.rs) Adapter::execute returns ActionOutcome, provision returns ProvisionReport, gc_config_entries returns GcReport, instead of () or prose lines. A negative result that was still measured (unhealthy probe, unauthenticated session, partly failed gc) is an Ok outcome carrying a failure message.
edgezero-adapter (process.rs, new) Process-wide child-stdout policy plus process::status, the one sanctioned inheriting spawn.
edgezero-adapter (cli_support.rs) native_auth_status. run_native_cli goes through process::status.
edgezero-adapter-{fastly,cloudflare,spin,axum} Return typed outcomes and reports. Fastly no longer prints the version= / healthy= / status-code= / rolled-back-to= data lines; the CLI prints the same bytes. All inheriting spawns go through process::status.
edgezero-cli (output.rs, new) OutputScope (routes stdout while alive), Failure / Outcome, the envelope, and the serde wire schema, kept separate from the adapter types so internal refactors can't change the JSON.
edgezero-cli (args.rs) New OutputFormat { Text, Json } and a --format flag on the nine commands. DiffFormat is unchanged.
edgezero-cli (lib.rs, auth.rs, provision.rs, config.rs, adapter.rs) Each run_* keeps its public signature and emits the envelope itself, so CLIs already generated from the template get JSON without regenerating main.rs. The logger's info output moves to stderr under JSON.
clippy.toml disallowed-methods for Command::status / Command::spawn. Piped spawns carry a documented #[expect].
edgezero-cli/tests/format_json.rs (new) End-to-end tests against the real binary.
docs/guide/cli-reference.md --format on each command, plus a new "Machine-readable output" section covering the envelope, streams, exit codes, compatibility policy, per-command schemas and changelog.
docs/superpowers/specs/…-cli-format-json-design.md The spec, revision 2 (§13 notes what changed during implementation).

Closes

Closes #383

Test plan

  • cargo test --workspace --all-targets
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check
  • cargo check --workspace --all-targets --features "fastly cloudflare spin"
  • WASM builds: wasm32-wasip1 (Fastly) / wasm32-wasip2 (Spin) / wasm32-unknown-unknown (Cloudflare), via the full format.yml wasm clippy matrix and cargo check -p edgezero-adapter-spin --target wasm32-wasip2 --features spin
  • examples/app-demo workspace: cd examples/app-demo && cargo test --workspace --all-targets (--locked), plus its fmt and clippy
  • Docs build: cd docs && npm run lint && npm run format && npm run build
  • Manual testing via edgezero serve --adapter axum (not applicable: serve is out of scope)
  • Other:
    • Text mode compared byte-for-byte against main: both binaries ran 21 hermetic scenarios (success and failure paths for every in-scope command, a usage error, the bundled stub), with stdout, stderr and exit codes identical in all of them.
    • cargo test -p edgezero-cli --test generated_project_builds -- --ignored, cargo test -p edgezero-adapter-fastly --features cli, and the check_no_nested_app_config steps.
    • All checks were run on the pinned toolchain 1.95.0.

Checklist

  • Changes follow CLAUDE.md conventions
  • No Tokio deps added to core or adapter crates
  • Route params use {id} syntax (not :id)
  • Types imported from edgezero_core (not http crate)
  • Store wiring goes through KvRegistry / ConfigRegistry / SecretRegistry (not the legacy single-handle setters) — see spec §6.6
  • New code has tests
  • No secrets or credentials committed

Spec for #383: settles the open questions (shared OutputFormat enum, `text` default, stdout/stderr discipline, error envelopes, schema versioning, bundled stubs) and defines the per-command JSON schema. Also corrects the docs/.prettierignore comment: design docs are tracked in git.
active-version, auth status, build, config gc, config validate, deploy, healthcheck, provision and rollback accept --format text|json. JSON mode writes one versioned envelope to stdout and routes logs and child-process stdout to stderr; text mode is byte-identical to before.

Adapters now return typed outcomes (ActionOutcome, ProvisionReport, GcReport) instead of printing their results, and every inheriting child spawn goes through edgezero_adapter::process::status, enforced by a clippy disallowed-methods lint.

Closes #383
@dhruv8sh dhruv8sh self-assigned this Sep 25, 2026

This branch has not been deployed

No deployments
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.

Add --json output across the CLI

2 participants