diff --git a/CHANGELOG.md b/CHANGELOG.md index a33e617..2792403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ and the project adheres to [Semantic Versioning 2.0.0](https://semver.org/spec/v ## [Unreleased] ### Changed +- **`--version` no longer prints the splash logo.** `commitbrief --version` + now emits only the single `commitbrief vX.Y.Z (commit , built )` + line, so the output is trivially parseable by scripts. The branding logo is + unchanged for `--help` and every other invocation; the version line itself + is identical to before. - **Interactive Yes/No confirmation prompts.** On a TTY, every confirmation prompt — the pre-send `.commitbrief/**` guard, the secret-scan warning, the cost preflight, the token/context-window preflight, `cache clear`, and the diff --git a/internal/cli/root.go b/internal/cli/root.go index 11f6b36..c768dbc 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -141,6 +141,22 @@ func newRootCmd() *cobra.Command { return cmd } +// versionFlagRequested reports whether args contain the --version flag +// before a "--" terminator. Cobra owns the flag itself; Execute only +// peeks so it can suppress the branding logo for `commitbrief --version` +// and keep that invocation's output a single parseable line. +func versionFlagRequested(args []string) bool { + for _, a := range args { + if a == "--" { + return false + } + if a == "--version" { + return true + } + } + return false +} + // Execute is the package entry point used by cmd/commitbrief/main.go. func Execute() { // UC-18: on Windows the VT100 escape mode needs to be opted into @@ -160,7 +176,13 @@ func Execute() { // CI logs don't fill up with raw 24-bit color escapes. The version // string is the resolved value (ldflags-injected at release time, // debug.BuildInfo for `go install`, or "dev" for ad-hoc builds). - if ui.ColorEnabled(os.Stderr, ui.ColorAuto) { + // + // Suppressed for `--version`: that flag is meant to emit a single + // machine-parseable line — cobra prints version.Info() to stdout — + // so the logo (which lands on stderr above it on a TTY) must not + // appear. We peek os.Args because the logo prints before cobra + // parses flags; --help and every other invocation keep the logo. + if ui.ColorEnabled(os.Stderr, ui.ColorAuto) && !versionFlagRequested(os.Args[1:]) { logo.Print(os.Stderr, version.Version) } diff --git a/internal/cli/version_logo_test.go b/internal/cli/version_logo_test.go new file mode 100644 index 0000000..8f9c028 --- /dev/null +++ b/internal/cli/version_logo_test.go @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package cli + +import "testing" + +// versionFlagRequested gates whether Execute prints the branding logo: +// `commitbrief --version` must emit a single parseable line (no logo), +// while every other invocation — including --help — keeps the logo. +func TestVersionFlagRequested(t *testing.T) { + cases := []struct { + name string + args []string + want bool + }{ + {"bare", nil, false}, + {"version only", []string{"--version"}, true}, + {"version after subcommand", []string{"diff", "--version"}, true}, + {"version with other flags", []string{"--json", "--version"}, true}, + {"help is not version", []string{"--help"}, false}, + {"staged review", []string{"--staged"}, false}, + // A "--" terminator hands the rest to positional args (e.g. a git + // pathspec for `diff`), so a later --version is not our flag. + {"version after terminator", []string{"diff", "--", "--version"}, false}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + if got := versionFlagRequested(tc.args); got != tc.want { + t.Errorf("versionFlagRequested(%q) = %v, want %v", tc.args, got, tc.want) + } + }) + } +}