From 884f382e5c10b74757adfaf3f7e71f9b2db886cb Mon Sep 17 00:00:00 2001 From: moshimorschi Date: Thu, 1 Oct 2026 11:18:53 +0200 Subject: [PATCH 1/2] docs: add the command conventions guide - docs/COMMAND_CONVENTIONS.md: how commands, flags, messages and exit codes are written - AGENTS.md: point coding agents at the guide --- AGENTS.md | 8 +++++ docs/COMMAND_CONVENTIONS.md | 71 +++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 docs/COMMAND_CONVENTIONS.md diff --git a/AGENTS.md b/AGENTS.md index 8e448f97..bac67256 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -69,6 +69,14 @@ Commands follow Cobra CLI patterns with: - Context-based logging: `logging.FromContext(ctx)` - Graceful error reporting to users +### Command Conventions +Follow `docs/COMMAND_CONVENTIONS.md` for every command, flag and message. The short version: +- Short texts are imperative, capitalised, no period; a parent command describes the group +- `Use` shows required arguments bare and optional ones in brackets, no angle brackets; every leaf command declares `Args` +- Errors are lowercase `cannot ...: %w` without Go identifiers, hints in quotes; log lines are capitalised sentences +- Any failure exits non-zero in every output format; never log success after a failed step +- Test the invoked `internal/` function, never the cobra layer, and test behaviour, not message wording + ### AI Integration The CLI includes AI-powered features for: - Twig template upgrades (`extension ai twig-upgrade`) diff --git a/docs/COMMAND_CONVENTIONS.md b/docs/COMMAND_CONVENTIONS.md new file mode 100644 index 00000000..5d659e7c --- /dev/null +++ b/docs/COMMAND_CONVENTIONS.md @@ -0,0 +1,71 @@ +# Command conventions + +How commands, flags, messages and exit codes are written in `shopware-cli`. Follow these rules for new commands and when touching existing ones, so the CLI keeps one voice. When a rule and existing code disagree, the code gets fixed. + +## Commands + +**Short** + +- Imperative, capitalised, no trailing period, under 80 characters: `Build and install Administration assets`. +- A parent command without `RunE` describes the group, not one child: `Manage the project configuration file`, `Manage installed Shopware extensions`. + +**Long** + +- Full sentences in the imperative, same voice as the Short. Say what the command needs that is not obvious, for example `Requires a Docker environment`. +- Examples go into the `Example` field, never into `Long`. Cobra prints them under its own heading. +- No empty `Long: ""` fields. + +**Use and arguments** + +- Required arguments are bare, optional ones are in brackets, variadic ones get three dots: `validate path`, `fix [path]`, `activate name...`, `package path [branch]`. No angle brackets. +- Every leaf command declares `Args`. A command without positional arguments uses `cobra.NoArgs`, so a stray argument fails with `unknown command "x" for "..."` instead of being ignored. +- A command that passes arguments through shows that: `console command [args...]`. +- Aliases mirror their siblings: `ls` for every `list`, `rm` for `delete`, `watch-admin` beside `admin-watch`. +- Deprecate with the same lowercase sentence cobra uses for flags: `use "project upgrade" instead, will be removed in October 2026`. Always name the replacement. + +## Flags + +- Usage text is capitalised, has no trailing period, and does not repeat the default; pflag prints `(default ...)` itself. +- Enumerated values are listed in parentheses with commas and no "or": `(summary, json, github, gitlab, junit, markdown)`, `(plugin, theme)`. +- Lists are `(comma-separated, e.g. phpstan,eslint)`. The example must be pasteable: lowercase, real tool names. +- Values in help are lowercase. `--format` values are parsed case-insensitively, so `--format JSON` works, but the help keeps `json`. Other enumerated flags are strict. +- A flag that several sibling commands share (`--only`, `--exclude`, `--format`, `--no-copy`, `--allow-non-git`, `--dry-run`) has the same sentence on each of them. +- Register a flag on the commands that read it. A persistent flag that a subcommand ignores is a bug in the help. +- A `NoOptDefVal` sentinel shows up in the help as `[="..."]`, so pick a word that reads well there (`select`), never a space or an internal marker. +- Numbers are numeric flags (`Uint`, `Int`) unless the value is handed through to another tool as a string. +- Flag deprecations: `use --with-elasticsearch=false instead`, lowercase, naming the replacement. + +## Errors + +- Returned errors are lowercase and start with `cannot `: `cannot read project config %s: %w`. Older `failed to` and `could not` wording is not rewritten for its own sake, but new and touched messages use `cannot`. Wrap with `%w`, not `%v`. +- No Go identifiers in messages: not `ReadConfig(%s)`, not `cannot InstallExtension`. +- Hints use the existing forms: `, use shopware-cli project config init to create one`, `: run "shopware-cli account login"`, `(pass --force to overwrite)`. Quotes, never backticks. +- Name config keys as they are in the schema (`environments..admin_api`) and the preferred file (`.config/shopware-project.yml`). Product names as written: `Admin API`. +- Invalid user input (a config value, a pattern, a flag value) returns an error. It never panics. + +## Log lines + +- Log lines are capitalised sentences with a colon before the value: `Installed %s`, `Cannot parse URL %s: %s`. +- A failed step keeps the established shape: `Activation of %s failed with error: %v`. +- Log a failure or return it, not both. The root command prints every returned error once. +- Never log a success line after a failed step. In a loop, `continue` after a failure. + +## Exit codes and output + +- Any failure exits non-zero, in every output format. `--format json` has the same exit code as the table. +- Nothing succeeds silently on a wrong assumption: an explicit `--project-config` that does not exist is an error, not a fallback. +- When the error was already printed as part of the output (a failed verification check with its hint), return a sentinel error and add it to the exemption list in `cmd/root.go`, so it is not printed twice. +- Without a terminal, or with `--no-interaction`, a command that would prompt fails fast and names the flag or environment variable that replaces the prompt. + +## Tests + +- New tests target the `internal/` function a command calls, not the cobra layer. Keep `cmd/` thin enough that this is possible. +- Test behaviour: the request a call makes, the value a parser returns, that bad input yields an error instead of a panic. Do not add tests whose only assertion is the wording of a message. +- Table tests with testify, `t.Setenv` for environment variables, `t.Context()` for contexts. + +## Checking your change + +- Help text: dump `--help` for every command before and after and diff them (recurse through "Available Commands:"). Deprecated commands are hidden from that walk, check them by name. +- Arguments: run each touched command with a stray argument and confirm the exit code. +- Enumerated values: paste the example from the help into a shell and make sure it runs. +- Messages: grep the repository, including tests and testdata, for the old text before changing it. From 78dc6ffd16fd2e9d5af0637fea7bf5899f58d431 Mon Sep 17 00:00:00 2001 From: moshimorschi Date: Thu, 1 Oct 2026 12:01:50 +0200 Subject: [PATCH 2/2] docs: address review notes on the conventions guide --- docs/COMMAND_CONVENTIONS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/COMMAND_CONVENTIONS.md b/docs/COMMAND_CONVENTIONS.md index 5d659e7c..6762daaa 100644 --- a/docs/COMMAND_CONVENTIONS.md +++ b/docs/COMMAND_CONVENTIONS.md @@ -11,7 +11,7 @@ How commands, flags, messages and exit codes are written in `shopware-cli`. Foll **Long** -- Full sentences in the imperative, same voice as the Short. Say what the command needs that is not obvious, for example `Requires a Docker environment`. +- Open in the imperative, same voice as the Short. Plain statements of fact are fine after that, for example `Requires a Docker environment`. - Examples go into the `Example` field, never into `Long`. Cobra prints them under its own heading. - No empty `Long: ""` fields. @@ -47,7 +47,7 @@ How commands, flags, messages and exit codes are written in `shopware-cli`. Foll - Log lines are capitalised sentences with a colon before the value: `Installed %s`, `Cannot parse URL %s: %s`. - A failed step keeps the established shape: `Activation of %s failed with error: %v`. -- Log a failure or return it, not both. The root command prints every returned error once. +- Log a failure or return it, not both. The root command prints every returned error once, apart from the sentinel errors described under exit codes. - Never log a success line after a failed step. In a loop, `continue` after a failure. ## Exit codes and output