Use standard help handling for the version command

This commit is contained in:
2026-10-07 14:43:38 +00:00
parent 561a84fcf8
commit 8d416558a3
4 changed files with 17 additions and 18 deletions

View File

@@ -30,8 +30,9 @@ overlay is loaded beside the main file, not used to locate profile files.
`audita version` prints `audita <version>` and a newline to stdout, with no `audita version` prints `audita <version>` and a newline to stdout, with no
application configuration or provider setup. It returns `0` on success with application configuration or provider setup. It returns `0` on success with
empty stderr. `help version`, `version -h`, and `version --help` print command empty stderr. `help version`, `version -h`, and `version --help` print command
usage to stdout and return `0`; unexpected arguments and unknown flags return usage to stdout and return `0`. Help follows standard flag parsing and can
`2` with a usage error on stderr. The command uses ReleaseKit's public short-circuit trailing arguments. Other invalid invocations return `2` with a
usage error on stderr. The command uses ReleaseKit's public
`buildinfo.Version()` accessor. It reports an injected release identifier when `buildinfo.Version()` accessor. It reports an injected release identifier when
present, otherwise the executable's main-module version when available and not present, otherwise the executable's main-module version when available and not
`(devel)`, and `dev` when neither source provides a release identifier. `(devel)`, and `dev` when neither source provides a release identifier.

View File

@@ -4,8 +4,8 @@
`3c405f0524ec6c098d00d4e371abbace7648d446`. `3c405f0524ec6c098d00d4e371abbace7648d446`.
**Scope:** ReleaseKit adoption commits after `721365e`, including CLI version **Scope:** ReleaseKit adoption commits after `721365e`, including CLI version
reporting, local release wiring, CI delivery, tests, and documentation. reporting, local release wiring, CI delivery, tests, and documentation.
**Status:** Findings pending remediation; no implementation changes made by this **Status:** R1 addressed; R2–R3 pending. The findings below describe the reviewed
review. baseline; completed work is recorded under Resolution Record.
## Architecture Assessment ## Architecture Assessment
@@ -128,3 +128,11 @@ matrix.
deployment work rather than an implementation finding or source-release gate. deployment work rather than an implementation finding or source-release gate.
- No tags, pushes, hosted uploads, or LLM calls were made. Remediation should - No tags, pushes, hosted uploads, or LLM calls were made. Remediation should
remain bounded to the findings above and add no new release gates. remain bounded to the findings above and add no new release gates.
## Resolution Record
- **R1:** The version command now uses one standard flag-parsing path. Successful
help is written once to stdout, with no stderr usage, and help can short-circuit
trailing arguments. Non-help usage errors retain status `2`. Regression tests
reproduced both defects before the fix; `go test ./internal/cli ./cmd/audita`
passed afterward. The CLI contract reflects ordinary help behavior.

View File

@@ -71,26 +71,15 @@ func Run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
} }
func runVersion(args []string, stdout, stderr io.Writer) int { func runVersion(args []string, stdout, stderr io.Writer) int {
if len(args) == 1 && (args[0] == "-h" || args[0] == "--help") {
writeVersionUsage(stdout)
return 0
}
for _, arg := range args {
if arg == "-h" || arg == "--help" {
fmt.Fprintln(stderr, "audita version: help flags cannot be combined with other arguments")
fmt.Fprintln(stderr)
writeVersionUsage(stderr)
return 2
}
}
flags := flag.NewFlagSet("version", flag.ContinueOnError) flags := flag.NewFlagSet("version", flag.ContinueOnError)
flags.SetOutput(stderr) flags.SetOutput(stderr)
flags.Usage = func() { writeVersionUsage(stderr) } flags.Usage = func() {} // Route usage after parsing so help stays on stdout.
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
if err == flag.ErrHelp { if err == flag.ErrHelp {
writeVersionUsage(stdout) writeVersionUsage(stdout)
return 0 return 0
} }
writeVersionUsage(stderr)
return 2 return 2
} }
if positional := flags.Args(); len(positional) > 0 { if positional := flags.Args(); len(positional) > 0 {

View File

@@ -34,6 +34,8 @@ func TestVersionCommandHelp(t *testing.T) {
{name: "help version", args: []string{"help", "version"}, want: "audita version"}, {name: "help version", args: []string{"help", "version"}, want: "audita version"},
{name: "short flag", args: []string{"version", "-h"}, want: "audita version"}, {name: "short flag", args: []string{"version", "-h"}, want: "audita version"},
{name: "long flag", args: []string{"version", "--help"}, want: "audita version"}, {name: "long flag", args: []string{"version", "--help"}, want: "audita version"},
{name: "parser help", args: []string{"version", "--h"}, want: "audita version"},
{name: "help short circuits", args: []string{"version", "-h", "--help", "extra"}, want: "audita version"},
} { } {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
@@ -54,7 +56,6 @@ func TestVersionCommandRejectsUnexpectedArguments(t *testing.T) {
for _, args := range [][]string{ for _, args := range [][]string{
{"version", "extra"}, {"version", "extra"},
{"version", "--unknown"}, {"version", "--unknown"},
{"version", "--help", "extra"},
} { } {
t.Run(strings.Join(args, " "), func(t *testing.T) { t.Run(strings.Join(args, " "), func(t *testing.T) {
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer