diff --git a/cmd/bd/main.go b/cmd/bd/main.go index 1a40303a..cfa53a0a 100644 --- a/cmd/bd/main.go +++ b/cmd/bd/main.go @@ -94,12 +94,24 @@ func init() { rootCmd.PersistentFlags().BoolVar(&noAutoImport, "no-auto-import", false, "Disable automatic JSONL import when newer than DB") rootCmd.PersistentFlags().BoolVar(&sandboxMode, "sandbox", false, "Sandbox mode: disables daemon and auto-sync") rootCmd.PersistentFlags().BoolVar(&noDb, "no-db", false, "Use no-db mode: load from JSONL, no SQLite") + + // Add --version flag to root command (same behavior as version subcommand) + rootCmd.Flags().BoolP("version", "v", false, "Print version information") } var rootCmd = &cobra.Command{ Use: "bd", Short: "bd - Dependency-aware issue tracker", Long: `Issues chained together like beads. A lightweight issue tracker with first-class dependency support.`, + Run: func(cmd *cobra.Command, args []string) { + // Handle --version flag on root command + if v, _ := cmd.Flags().GetBool("version"); v { + fmt.Printf("bd version %s (%s)\n", Version, Build) + return + } + // No subcommand - show help + _ = cmd.Help() + }, PersistentPreRun: func(cmd *cobra.Command, args []string) { // Apply viper configuration if flags weren't explicitly set // Priority: flags > viper (config file + env vars) > defaults diff --git a/cmd/bd/version_test.go b/cmd/bd/version_test.go index 3402793b..1a05eb69 100644 --- a/cmd/bd/version_test.go +++ b/cmd/bd/version_test.go @@ -76,3 +76,69 @@ func TestVersionCommand(t *testing.T) { // Restore default jsonOutput = false } + +func TestVersionFlag(t *testing.T) { + // Save original stdout + oldStdout := os.Stdout + defer func() { os.Stdout = oldStdout }() + + t.Run("--version flag", func(t *testing.T) { + // Create a pipe to capture output + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("Failed to create pipe: %v", err) + } + os.Stdout = w + + // Set version flag and run root command + rootCmd.SetArgs([]string{"--version"}) + rootCmd.Execute() + + // Close writer and read output + w.Close() + var buf bytes.Buffer + buf.ReadFrom(r) + output := buf.String() + + // Verify output contains version info + if !strings.Contains(output, "bd version") { + t.Errorf("Expected output to contain 'bd version', got: %s", output) + } + if !strings.Contains(output, Version) { + t.Errorf("Expected output to contain version %s, got: %s", Version, output) + } + + // Reset args + rootCmd.SetArgs(nil) + }) + + t.Run("-v shorthand", func(t *testing.T) { + // Create a pipe to capture output + r, w, err := os.Pipe() + if err != nil { + t.Fatalf("Failed to create pipe: %v", err) + } + os.Stdout = w + + // Set version flag and run root command + rootCmd.SetArgs([]string{"-v"}) + rootCmd.Execute() + + // Close writer and read output + w.Close() + var buf bytes.Buffer + buf.ReadFrom(r) + output := buf.String() + + // Verify output contains version info + if !strings.Contains(output, "bd version") { + t.Errorf("Expected output to contain 'bd version', got: %s", output) + } + if !strings.Contains(output, Version) { + t.Errorf("Expected output to contain version %s, got: %s", Version, output) + } + + // Reset args + rootCmd.SetArgs(nil) + }) +}