From 4038da4dad115a2b23a576075609404a84a72779 Mon Sep 17 00:00:00 2001 From: OZAWA Sakuro <10973+sakuro@users.noreply.github.com> Date: Sun, 6 Sep 2026 06:09:13 +0900 Subject: [PATCH] :sparkles: Replace version subcommand with --version flag - Set root.Version and a bare-string SetVersionTemplate so --version prints just the version number, matching the old version subcommand's output; --version now bypasses --log-level validation and the config precheck since cobra resolves it before PersistentPreRunE runs - Update unit and e2e tests accordingly; the legacy-migration e2e case switches from version to man to keep exercising the boot-time config precheck for a command that never builds the app - Document --version in the man page's GLOBAL OPTIONS and remove the factorix version COMMANDS entry Closes #210 --- CHANGELOG.md | 8 ++++++++ doc/factorix.1 | 5 +++-- e2e/cases/config/legacy-migration/case.yaml | 2 +- e2e/cases/version/default/case.yaml | 2 +- internal/cli/cli.go | 16 +++------------ internal/cli/cli_test.go | 22 ++++++++++----------- 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 861439a5..3bca0fc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## [Unreleased] +### Added + +- `--version` global flag prints the Factorix version (#210) + +### Removed + +- `version` subcommand, replaced by the `--version` flag (#210) + ## [0.23.0] - 2026-08-29 ### Changed diff --git a/doc/factorix.1 b/doc/factorix.1 index 9d5b6c42..92021a22 100644 --- a/doc/factorix.1 +++ b/doc/factorix.1 @@ -27,9 +27,10 @@ Suppress non-essential output. .TP .BR \-h ", " \-\-help Print help information. +.TP +.B \-\-version +Print the Factorix version and exit. Root command only. .SH COMMANDS -.SS factorix version -Display Factorix version. .SS factorix man Display this manual page using the system's man command. .SS factorix path diff --git a/e2e/cases/config/legacy-migration/case.yaml b/e2e/cases/config/legacy-migration/case.yaml index 35fcfd54..96616030 100644 --- a/e2e/cases/config/legacy-migration/case.yaml +++ b/e2e/cases/config/legacy-migration/case.yaml @@ -1,4 +1,4 @@ -command: [version] +command: [man] files: - {from: files/config.rb, to: xdg-config/factorix/config.rb} expect: diff --git a/e2e/cases/version/default/case.yaml b/e2e/cases/version/default/case.yaml index 8e148bef..9d7d12b3 100644 --- a/e2e/cases/version/default/case.yaml +++ b/e2e/cases/version/default/case.yaml @@ -1,4 +1,4 @@ -command: [version] +command: [--version] expect: status: 0 stdout: diff --git a/internal/cli/cli.go b/internal/cli/cli.go index d26ec472..85383757 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -64,6 +64,7 @@ func NewRootCommand() (root *cobra.Command, reportError func(error)) { root = &cobra.Command{ Use: "factorix", Short: "Manage Factorio MODs, settings, and game control", + Version: Version, SilenceUsage: true, SilenceErrors: true, // Ruby validates --log-level values at option-parse time for every @@ -88,12 +89,13 @@ func NewRootCommand() (root *cobra.Command, reportError func(error)) { }, } + root.SetVersionTemplate("{{.Version}}\n") + root.PersistentFlags().StringVarP(&c.configPath, "config-path", "c", "", "Path to configuration file") root.PersistentFlags().StringVar(&c.logLevel, "log-level", "", "Set log level (debug, info, warn, error, fatal)") root.PersistentFlags().BoolVarP(&c.quiet, "quiet", "q", false, "Suppress non-essential output") root.AddCommand( - newVersionCommand(), newPathCommand(c), newDownloadCommand(c), newLaunchCommand(c), @@ -127,15 +129,3 @@ type bootError struct{ err error } func (b bootError) Error() string { return b.err.Error() } func (b bootError) Unwrap() error { return b.err } - -func newVersionCommand() *cobra.Command { - return &cobra.Command{ - Use: "version", - Short: "Display Factorix version", - RunE: func(cmd *cobra.Command, _ []string) error { - // Not cmd.Println, which writes to stderr by cobra default. - fmt.Fprintln(cmd.OutOrStdout(), Version) - return nil - }, - } -} diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index a65545e8..702ebd36 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -187,36 +187,36 @@ func runCLIWithStdin(t *testing.T, stdin string, args ...string) (string, error) return out.String(), err } -func TestVersionCommand(t *testing.T) { - out, err := runCLI(t, "version") +func TestVersionFlag(t *testing.T) { + out, err := runCLI(t, "--version") require.NoError(t, err) assert.Equal(t, "dev\n", out) } -// TestVersionCommandNeverBuildsApp guards against PersistentPostRun's +// TestVersionFlagNeverBuildsApp guards against PersistentPostRun's // Close() forcing application construction (config load, log file -// creation) for a command that never calls c.App() itself. -func TestVersionCommandNeverBuildsApp(t *testing.T) { +// creation) for a flag that never calls c.App() itself. +func TestVersionFlagNeverBuildsApp(t *testing.T) { s := newSandbox(t) - _, err := runCLI(t, "version") + _, err := runCLI(t, "--version") require.NoError(t, err) logPath := filepath.Join(s.root, "xdg-state", "factorix", "factorix.log") _, statErr := os.Stat(logPath) - assert.ErrorIs(t, statErr, os.ErrNotExist, "version must not trigger app construction") + assert.ErrorIs(t, statErr, os.ErrNotExist, "--version must not trigger app construction") } // Invalid --log-level values must fail at parse time on every command, -// including ones like version that never build the application. +// including ones like man that never build the application. func TestInvalidLogLevelRejectedAtParseTime(t *testing.T) { - _, err := runCLI(t, "version", "--log-level", "bogus") + _, err := runCLI(t, "man", "--log-level", "bogus") require.Error(t, err) assert.Contains(t, err.Error(), "invalid log level") - out, err := runCLI(t, "version", "--log-level", "debug") + out, err := runCLI(t, "man", "--log-level", "debug") require.NoError(t, err) - assert.Equal(t, "dev\n", out) + assert.Contains(t, out, "factorix") } func TestPathCommand(t *testing.T) {