Skip to content

fix: make YAML input and output usable, and drop flags that do nothing - #7

Merged
Alex (Alexkuva) merged 6 commits into
mainfrom
fix/yaml-io-dead-flags-and-readme
Oct 14, 2026
Merged

Alex (Alexkuva) merged 6 commits into
mainfrom
fix/yaml-io-dead-flags-and-readme

Conversation

@Alexkuva

Copy link
Copy Markdown
Contributor

What does this PR change?

  • YAML output is the document --output json prints: same keys, same order, same values. It printed Go field names (externalcustomerid), every absent field as null, and typed values such as a grant's value as {}.
  • YAML input is read as the JSON it stands for. A YAML --file or --payload lost every field whose name has more than one word (externalCustomerId, default_variant) without an error, so the request went out incomplete. A key the request has no field for now stops the command and is named. JSON input is unchanged.
  • licenses create has no --version. It was required and never sent: the API numbers the versions itself and refuses one it is sent. On licenses update the flag stays, optional, as a check the API makes.
  • Three flags that did nothing are removed: components update --previous-component-id (the API refuses the field on update), instances audit-trails --offset and instances list --include-deleted (the API declares neither).
  • An inline instances update keeps the instance's metadata. It sent "metadata": {}, which cleared it. It now reads the instance and sends its metadata back unless --metadata-json gives another; --metadata-json '{}' clears it.
  • README: the --output default for each kind of command, the two entitlement update commands described as each behaves, the exit codes of destructive commands, the rules for --file and --payload. The example --event-name instance.updated becomes INSTANCE_UPDATED. Installation and Development are untouched (feat: install scripts, Linux packages, a container image and automated releases #2 rewrites them).

Why?

YAML is the default output of every command that returns one resource, and it could not be read. YAML input lost data silently. Four flags were accepted and had no effect, one update cleared data it was not asked to touch, and the README described defaults and update behaviour the code does not have.

For scripts (nothing is released yet): the keys of YAML output change; licenses create --version and the three removed flags now exit 2; a YAML yes or no is no longer read as a boolean.

One point to decide. JSON input still skips a key it does not know, which is what lets get --output json | update --file - work. YAML input now refuses one, so the same write-back in YAML stops on the first read-only field (createdAt). Refusing catches a snake_case key written by hand, the failure this fixes; skipping would make the two formats agree. Accepting a resource's read-only fields in both formats would give both, and needs a map from each request to its resource.

Testing

Checklist

  • I have read CONTRIBUTING.md.
  • Every commit in this PR includes a valid DCO Signed-off-by line.
  • I have the right to submit all material in this PR.
  • I have not included secrets or confidential data.
  • I have updated tests where appropriate.
  • I have updated documentation where appropriate.
  • I have preserved required third-party licenses and attributions.

🤖 Generated with Claude Code · ✅ Tested and approved by Alex (@Alexkuva), maintainer

Alex (Alexkuva) and others added 6 commits October 14, 2026 00:00
YAML is the default output of every command that returns one resource:
`get`, `create`, `usage get`, `usage report`, `tokens create`. It was not
usable there. The API's types describe themselves in JSON only, through
json tags and MarshalJSON methods, and the YAML encoder reads neither:

- a field was named after the Go one, lowercased: `externalcustomerid`,
  `createdat`, `limitcapexceededoveragepercent`;
- a typed value printed as an empty mapping, so `licenses entitlements
  get` and `instances usage get` showed `value: {}` and `limit: {}`;
- every absent optional field was printed, as `null`.

YAML output is now built from the JSON encoding of the value: the same
keys, in the same order, with the same values. A number is carried over
as JSON writes it, and a string that would read as another type (a date,
"true", "1024") is quoted so that it stays a string.

The CLI's own documents (`doctor`, `config view`, the message of a
mutation) already carried matching json and yaml tags and print as
before.

Signed-off-by: Alexandre Bergere <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A `--file` or `--payload` written in YAML lost fields without an error.
The request types name their fields for JSON only, so the YAML decoder
filled the fields whose key is a single word and silently dropped every
other one:

- `customers create --file customer.yaml` sent no `externalCustomerId`;
- an instance file lost `customerId`, `licenseId` and both license dates;
- a feature flag went out with `"default_variant": null` and an empty
  `event_name`;
- a grant value (`type: number`, `value: 2000`) decoded to nothing.

Each command still exited 0, or failed on a request it had emptied itself.

A YAML document is now decoded as the JSON document it stands for, so it
makes the request the same document written in JSON makes: the same
field names, typed values included. Where the two formats part ways on
what a value is, the text wins, as it did before for single-word keys: a
bare `version: 1.0` is the text "1.0" in a text field, and a date stays
the text it is in JSON instead of being respelled as a timestamp.

A YAML key the request has no field for is now an error that names the
key, before any request is sent. JSON input is unchanged and still skips
such a key, which is what lets a resource printed by `--output json` be
edited and written back with its read-only fields still in it.

Signed-off-by: Alexandre Bergere <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`licenses create` required --version with inline flags and then never
sent it. The API numbers the versions of a license itself and refuses a
create that names one, so the request has no such field: the flag was
mandatory and had no effect.

--version is no longer a flag of `create`: passing it is an unknown
flag and exits 2, and an inline create needs --name, --description,
--type and --default.

`licenses update` keeps the flag, where the API does act on it, but not
as a setting: it accepts the version the license already has, refuses
any other (422 UpdateLicense.VersionNotSettable, exit 5) and keeps the
stored one when none is sent. So --version is no longer required there.
Given, it is sent for the API to check; left out, the update applies
whatever the version. The help of both commands says so.

Signed-off-by: Alexandre Bergere <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Each of these parsed, exited 0 and changed nothing:

- `components update --previous-component-id`. The link to the version a
  component follows is set once, at creation: the API's update refuses
  the field (422 UpdateComponent.PreviousComponentNotSettable) and the
  request built there never carried it. The flag stays on `create`.
- `instances audit-trails --offset`. The audit trail is paged by cursor
  and the API declares no offset parameter, so none was sent. --limit
  still caps how many entries come back.
- `instances list --include-deleted`. It was sent as include_deleted,
  which the list has no parameter for and ignores: the result was the
  same with and without it.

All three are now unknown flags and exit 2, as --slug already is on the
updates that cannot rename.

Signed-off-by: Alexandre Bergere <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`instances update` with inline flags and no --metadata-json sent
`"metadata": {}`. The API replaces an instance's metadata with what it
is sent, so an update that only meant to change a description or a
license date cleared the instance's metadata, and exited 0.

The request cannot leave the metadata out, so the command now reads the
instance first when the flags name none, and sends its metadata back.
--metadata-json is sent as given, without the read, and `'{}'` clears
the metadata on purpose. If the instance cannot be read, nothing is
sent. --file and --payload are still sent as written.

The deployment zone and the slug needed nothing: the API already keeps
them when the request leaves them out. The command's help now says what
each optional flag does when absent.

Signed-off-by: Alexandre Bergere <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The README said things the code does not do, and left out things the
previous commits changed.

- `--output` was said to default to `table`. That holds for lists only:
  a single resource prints YAML, with or without `--output table`, and a
  command the API answers with no body prints one line. JSON and YAML
  now carry the same document, which is stated.
- `--file` and `--payload` were said to be sent as written by both
  update commands. That is `entitlements update`. `licenses entitlements
  update` reads the grant and keeps its allowance whenever
  `--overage-percent` is absent, whatever carries the value, and a file
  or a payload holds only the value there. Each is described on its own.
- The exit codes of a destructive command were missing: 2 when it
  cannot prompt and was not given `--yes`, 1 when the prompt is declined.
- New: what a file or a payload is made of, how YAML is read and what it
  refuses, what an inline `instances update` keeps, and where a license's
  version comes from.
- The audit-trail example filtered on `instance.updated`, a name no
  event has: the API matches the exact event name, INSTANCE_UPDATED.

The Installation and Development sections are left as they are.

Signed-off-by: Alexandre Bergere <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
@Alexkuva
Alex (Alexkuva) requested a review from a team as a code owner October 13, 2026 22:12
@Alexkuva
Alex (Alexkuva) merged commit 7bbfcef into main Oct 14, 2026
7 checks passed
@Alexkuva
Alex (Alexkuva) deleted the fix/yaml-io-dead-flags-and-readme branch October 14, 2026 19:12
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.

3 participants