Skip to content

Commit 616c22a

Browse files
committed
refactor: migrate from urfave/cli to Cobra
- Replace urfave/cli with spf13/cobra for CLI framework - Add dynamic completion for deploy command (collection names and env flag) - Use Cobra's built-in completion (bash, zsh, fish, powershell) - Simplify main.go - no more arg reordering needed - Update banner logic to work with Cobra's command structure - All business logic unchanged - only CLI framework changed Benefits: - Better flag completion (no timeouts!) - Industry standard framework (kubectl, docker, gh) - Dynamic completion for collection names and flags - Support for 4 shells out of the box
1 parent bc7c9dc commit 616c22a

10 files changed

Lines changed: 208 additions & 270 deletions

File tree

cmd/autocomplete/bash_autocomplete

Lines changed: 0 additions & 35 deletions
This file was deleted.

cmd/autocomplete/zsh_autocomplete

Lines changed: 0 additions & 20 deletions
This file was deleted.

cmd/completion.go

Lines changed: 0 additions & 45 deletions
This file was deleted.

cmd/deploy.go

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import (
66
"path/filepath"
77

88
"github.com/charmbracelet/lipgloss"
9+
"github.com/spf13/cobra"
910
"github.com/stevengregory/musing-cli/internal/config"
1011
"github.com/stevengregory/musing-cli/internal/health"
1112
"github.com/stevengregory/musing-cli/internal/mongo"
1213
"github.com/stevengregory/musing-cli/internal/ui"
13-
"github.com/urfave/cli/v2"
1414
)
1515

1616
// Styles using Lip Gloss (matching monitor.go)
@@ -24,29 +24,48 @@ var (
2424
MarginBottom(1)
2525
)
2626

27-
func DeployCommand() *cli.Command {
28-
return &cli.Command{
29-
Name: "deploy",
30-
Usage: "Deploy MongoDB data collections",
31-
ArgsUsage: "[collection] (use 'all' or specific collection name)",
32-
Flags: []cli.Flag{
33-
&cli.StringFlag{
34-
Name: "env",
35-
Aliases: []string{"e"},
36-
Usage: "Environment: dev or prod",
37-
Value: "dev",
38-
},
39-
},
40-
Action: func(c *cli.Context) error {
41-
collection := "all"
42-
if c.NArg() > 0 {
43-
collection = c.Args().Get(0)
44-
}
45-
46-
env := c.String("env")
47-
return deployData(collection, env)
48-
},
49-
}
27+
var deployCmd = &cobra.Command{
28+
Use: "deploy [collection]",
29+
Short: "Deploy MongoDB data collections",
30+
Long: `Deploy MongoDB data collections to development or production environment.`,
31+
Args: cobra.MaximumNArgs(1),
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
collection := "all"
34+
if len(args) > 0 {
35+
collection = args[0]
36+
}
37+
38+
env, _ := cmd.Flags().GetString("env")
39+
return deployData(collection, env)
40+
},
41+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
42+
// Dynamic completion for collection names
43+
config.MustFindProjectRoot()
44+
cfg := config.GetConfig()
45+
if cfg == nil {
46+
return nil, cobra.ShellCompDirectiveNoFileComp
47+
}
48+
49+
collections, err := mongo.DiscoverCollections(cfg.Database.DataDir)
50+
if err != nil {
51+
return nil, cobra.ShellCompDirectiveNoFileComp
52+
}
53+
54+
var names []string
55+
for name := range collections {
56+
names = append(names, name)
57+
}
58+
return names, cobra.ShellCompDirectiveNoFileComp
59+
},
60+
}
61+
62+
func init() {
63+
deployCmd.Flags().StringP("env", "e", "dev", "Environment: dev or prod")
64+
65+
// Add completion for env flag
66+
deployCmd.RegisterFlagCompletionFunc("env", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
67+
return []string{"dev", "prod"}, cobra.ShellCompDirectiveNoFileComp
68+
})
5069
}
5170

5271
func deployData(collection, env string) error {

cmd/dev.go

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import (
77
"time"
88

99
"github.com/charmbracelet/lipgloss"
10+
"github.com/spf13/cobra"
1011
"github.com/stevengregory/musing-cli/internal/config"
1112
"github.com/stevengregory/musing-cli/internal/docker"
1213
"github.com/stevengregory/musing-cli/internal/health"
1314
"github.com/stevengregory/musing-cli/internal/ui"
14-
"github.com/urfave/cli/v2"
1515
)
1616

1717
// Styles using Lip Gloss (matching monitor.go)
@@ -25,38 +25,32 @@ var (
2525
MarginBottom(1)
2626
)
2727

28-
func DevCommand() *cli.Command {
29-
return &cli.Command{
30-
Name: "dev",
31-
Usage: "Manage development stack",
32-
Flags: []cli.Flag{
33-
&cli.BoolFlag{
34-
Name: "rebuild",
35-
Usage: "Force rebuild all Docker images",
36-
},
37-
&cli.BoolFlag{
38-
Name: "data",
39-
Usage: "Deploy MongoDB data after starting services",
40-
},
41-
&cli.BoolFlag{
42-
Name: "logs",
43-
Usage: "Follow logs after starting services",
44-
},
45-
&cli.BoolFlag{
46-
Name: "stop",
47-
Usage: "Stop all services and exit",
48-
},
49-
},
50-
Action: func(c *cli.Context) error {
51-
// Handle stop flag
52-
if c.Bool("stop") {
53-
return stopServices()
54-
}
28+
var devCmd = &cobra.Command{
29+
Use: "dev",
30+
Short: "Manage development stack",
31+
Long: `Start, stop, and manage the development stack with Docker Compose.`,
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
// Handle stop flag
34+
stop, _ := cmd.Flags().GetBool("stop")
35+
if stop {
36+
return stopServices()
37+
}
5538

56-
// Start services
57-
return startServices(c.Bool("rebuild"), c.Bool("data"), c.Bool("logs"))
58-
},
59-
}
39+
// Get other flags
40+
rebuild, _ := cmd.Flags().GetBool("rebuild")
41+
data, _ := cmd.Flags().GetBool("data")
42+
logs, _ := cmd.Flags().GetBool("logs")
43+
44+
// Start services
45+
return startServices(rebuild, data, logs)
46+
},
47+
}
48+
49+
func init() {
50+
devCmd.Flags().Bool("rebuild", false, "Force rebuild all Docker images")
51+
devCmd.Flags().Bool("data", false, "Deploy MongoDB data after starting services")
52+
devCmd.Flags().Bool("logs", false, "Follow logs after starting services")
53+
devCmd.Flags().Bool("stop", false, "Stop all services and exit")
6054
}
6155

6256
func stopServices() error {

cmd/monitor.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import (
1010
"github.com/charmbracelet/lipgloss"
1111
figure "github.com/common-nighthawk/go-figure"
1212
"github.com/evertras/bubble-table/table"
13+
"github.com/spf13/cobra"
1314
"github.com/stevengregory/musing-cli/internal/config"
1415
"github.com/stevengregory/musing-cli/internal/docker"
1516
"github.com/stevengregory/musing-cli/internal/health"
1617
"github.com/stevengregory/musing-cli/internal/ui"
17-
"github.com/urfave/cli/v2"
1818
)
1919

2020
// Service name constants
@@ -81,14 +81,13 @@ type monitorModel struct {
8181
height int
8282
}
8383

84-
func MonitorCommand() *cli.Command {
85-
return &cli.Command{
86-
Name: "monitor",
87-
Usage: "Live monitoring dashboard for development stack",
88-
Action: func(c *cli.Context) error {
89-
return runMonitor()
90-
},
91-
}
84+
var monitorCmd = &cobra.Command{
85+
Use: "monitor",
86+
Short: "Live monitoring dashboard for development stack",
87+
Long: `Display a live monitoring dashboard showing the status of Docker, database, API services, and frontend.`,
88+
RunE: func(cmd *cobra.Command, args []string) error {
89+
return runMonitor()
90+
},
9291
}
9392

9493
func runMonitor() error {

0 commit comments

Comments
 (0)