Skip to content

fix(env): emit JSON results and route status text to stderr#119

Open
tcerqueira wants to merge 3 commits into
mainfrom
tc/env-json-discipline
Open

fix(env): emit JSON results and route status text to stderr#119
tcerqueira wants to merge 3 commits into
mainfrom
tc/env-json-discipline

Conversation

@tcerqueira

Copy link
Copy Markdown
Member

What

The mutating env subcommands — add, update-value, update-contexts, delete, and load — printed their human success confirmation to stdout and never emitted a machine-readable result. Under --json (the agent/CI contract) this corrupted stdout: a piped/parsed consumer got a non-JSON line like ✔ Environment variable 'X' has been successfully set. instead of a result payload. This is the env instance of the --json stdout-pollution rough edge tracked in #112; env list (a read) already complied.

Changes

  • Route all confirmation/status text to stderr (console.error), including the interactive "already defined" prompt chrome in load.
  • Under --json, emit exactly one JSON object per mutating command on stdout via writeJsonResult:
    • add / update-value / update-contexts → the affected variable shaped exactly like an env list item: { id, key, value (null for secrets), isSecret, contexts }.
    • delete{ id, key, deleted: true }.
    • load{ file, added, updated, skipped } summary.
  • Extract a shared shapeEnvVar helper, reused by list so every command's JSON shape stays identical.
  • Add an e2e test (tests/env.test.ts) covering the add/update-value/delete cycle under --json --non-interactive, asserting stdout is a single JSON object per command. Gated on DENO_DEPLOY_TEST_ORG/APP and run from an isolated temp cwd so it never dirties the repo deno.json; skipped when throwaway creds are absent.

Verification

Ran each mutating subcommand with --json --non-interactive against a throwaway org/app: stdout is pure JSON, human text is on stderr, and all created vars were cleaned up. deno fmt --check, deno lint, deno check, and the new test all pass.

The mutating `env` subcommands (add, update-value, update-contexts,
delete, load) printed their human success confirmation to stdout and
never emitted a machine-readable result, so `--json` (and any piped)
output was polluted with non-JSON text.

Route all confirmation/status text to stderr and, under `--json`, emit a
single JSON object per command on stdout: add/update-* report the
affected variable shaped exactly like an `env list` item (id, key,
masked value, isSecret, contexts), delete reports `{ id, key, deleted }`,
and load reports an `{ file, added, updated, skipped }` summary. The
shared `shapeEnvVar` helper is reused by `list` so all JSON stays
consistent.
Add an end-to-end test exercising the env add/update-value/delete cycle
with `--json --non-interactive`, asserting stdout carries exactly one
JSON object per command. Gated on DENO_DEPLOY_TEST_ORG/APP and run from
an isolated temp cwd so it never touches the repo's deno.json; skipped
when throwaway creds are absent.
…te miss

fetchShapedEnvVar returned null when the variable could not be read back
after a successful add/update-value/update-contexts mutation (e.g. a
backend read-after-write miss or key-normalization difference), and the
call sites passed that straight to writeJsonResult, printing a bare
`null` to stdout and breaking the agent/JSON contract.

Fold the miss handling into fetchShapedEnvVar: it now exits via error()
with ExitCode.NOT_FOUND / errorCode ENV_VAR_NOT_FOUND (message naming the
key) so the command always yields either the documented variable object
on stdout or a structured {error:{...}} envelope on stderr. The normal
found path is unchanged.
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.

1 participant