diff --git a/.golangci.yaml b/.golangci.yaml index f0a97075..71109c39 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -20,6 +20,7 @@ linters-settings: - github.com/mattn/go-sqlite3 - github.com/mitchellh/cli - github.com/olekukonko/tablewriter + - github.com/posener/complete - github.com/rubenv/sql-migrate exhaustive: default-signifies-exhaustive: true diff --git a/go.mod b/go.mod index 4f7404cc..ccb2c210 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.19 github.com/mitchellh/cli v1.1.5 github.com/olekukonko/tablewriter v0.0.5 + github.com/posener/complete v1.2.3 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 ) @@ -38,7 +39,6 @@ require ( github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/posener/complete v1.2.3 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect diff --git a/sql-migrate/command_down.go b/sql-migrate/command_down.go index 7e727553..d57077c3 100644 --- a/sql-migrate/command_down.go +++ b/sql-migrate/command_down.go @@ -4,6 +4,8 @@ import ( "flag" "strings" + "github.com/posener/complete" + migrate "github.com/rubenv/sql-migrate" ) @@ -31,6 +33,20 @@ func (*DownCommand) Synopsis() string { return "Undo a database migration" } +func (*DownCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (*DownCommand) AutocompleteFlags() complete.Flags { + f := complete.Flags{ + "-limit": complete.PredictAnything, + "-version": complete.PredictAnything, + "-dryrun": complete.PredictNothing, + } + ConfigFlagsCompletions(f) + return f +} + func (c *DownCommand) Run(args []string) int { var limit int var version int64 diff --git a/sql-migrate/command_new.go b/sql-migrate/command_new.go index 4ae7ee55..6666559f 100644 --- a/sql-migrate/command_new.go +++ b/sql-migrate/command_new.go @@ -9,6 +9,8 @@ import ( "strings" "text/template" "time" + + "github.com/posener/complete" ) var templateContent = ` @@ -39,6 +41,16 @@ func (*NewCommand) Synopsis() string { return "Create a new migration" } +func (*NewCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (*NewCommand) AutocompleteFlags() complete.Flags { + f := complete.Flags{} + ConfigFlagsCompletions(f) + return f +} + func (c *NewCommand) Run(args []string) int { cmdFlags := flag.NewFlagSet("new", flag.ContinueOnError) cmdFlags.Usage = func() { ui.Output(c.Help()) } diff --git a/sql-migrate/command_redo.go b/sql-migrate/command_redo.go index 4df12cc6..99510245 100644 --- a/sql-migrate/command_redo.go +++ b/sql-migrate/command_redo.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "github.com/posener/complete" + migrate "github.com/rubenv/sql-migrate" ) @@ -30,6 +32,18 @@ func (*RedoCommand) Synopsis() string { return "Reapply the last migration" } +func (*RedoCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (*RedoCommand) AutocompleteFlags() complete.Flags { + f := complete.Flags{ + "-dryrun": complete.PredictNothing, + } + ConfigFlagsCompletions(f) + return f +} + func (c *RedoCommand) Run(args []string) int { var dryrun bool diff --git a/sql-migrate/command_skip.go b/sql-migrate/command_skip.go index 3dc79f99..300c42bf 100644 --- a/sql-migrate/command_skip.go +++ b/sql-migrate/command_skip.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "github.com/posener/complete" + migrate "github.com/rubenv/sql-migrate" ) @@ -30,6 +32,18 @@ func (*SkipCommand) Synopsis() string { return "Sets the database level to the most recent version available, without running the migrations" } +func (*SkipCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (*SkipCommand) AutocompleteFlags() complete.Flags { + f := complete.Flags{ + "-limit": complete.PredictAnything, + } + ConfigFlagsCompletions(f) + return f +} + func (c *SkipCommand) Run(args []string) int { var limit int diff --git a/sql-migrate/command_status.go b/sql-migrate/command_status.go index 9ac2f278..f52509aa 100644 --- a/sql-migrate/command_status.go +++ b/sql-migrate/command_status.go @@ -8,6 +8,7 @@ import ( "time" "github.com/olekukonko/tablewriter" + "github.com/posener/complete" migrate "github.com/rubenv/sql-migrate" ) @@ -33,6 +34,16 @@ func (*StatusCommand) Synopsis() string { return "Show migration status" } +func (*StatusCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (*StatusCommand) AutocompleteFlags() complete.Flags { + f := complete.Flags{} + ConfigFlagsCompletions(f) + return f +} + func (c *StatusCommand) Run(args []string) int { cmdFlags := flag.NewFlagSet("status", flag.ContinueOnError) cmdFlags.Usage = func() { ui.Output(c.Help()) } diff --git a/sql-migrate/command_up.go b/sql-migrate/command_up.go index 301a8b3a..a000e26e 100644 --- a/sql-migrate/command_up.go +++ b/sql-migrate/command_up.go @@ -4,6 +4,8 @@ import ( "flag" "strings" + "github.com/posener/complete" + migrate "github.com/rubenv/sql-migrate" ) @@ -31,6 +33,20 @@ func (*UpCommand) Synopsis() string { return "Migrates the database to the most recent version available" } +func (*UpCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (*UpCommand) AutocompleteFlags() complete.Flags { + f := complete.Flags{ + "-dryrun": complete.PredictNothing, + "-limit": complete.PredictAnything, + "-version": complete.PredictAnything, + } + ConfigFlagsCompletions(f) + return f +} + func (c *UpCommand) Run(args []string) int { var limit int var version int64 diff --git a/sql-migrate/config.go b/sql-migrate/config.go index 6947a534..8dc2b876 100644 --- a/sql-migrate/config.go +++ b/sql-migrate/config.go @@ -9,6 +9,7 @@ import ( "runtime/debug" "github.com/go-gorp/gorp/v3" + "github.com/posener/complete" "gopkg.in/yaml.v2" migrate "github.com/rubenv/sql-migrate" @@ -34,6 +35,26 @@ func ConfigFlags(f *flag.FlagSet) { f.StringVar(&ConfigEnvironment, "env", "development", "Environment to use.") } +func ConfigFlagsCompletions(f complete.Flags) { + f["-config"] = complete.PredictOr(complete.PredictFiles("*.yaml"), complete.PredictFiles("*.yml")) + f["-env"] = complete.PredictFunc(func(args complete.Args) []string { + cf := flag.NewFlagSet("", flag.ContinueOnError) + ConfigFlags(cf) + if err := cf.Parse(args.All); err != nil { + return nil + } + config, err := ReadConfig() + if err != nil { + return nil + } + envs := make([]string, 0, len(config)) + for k := range config { + envs = append(envs, k) + } + return envs + }) +} + type Environment struct { Dialect string `yaml:"dialect"` DataSource string `yaml:"datasource"` diff --git a/sql-migrate/main.go b/sql-migrate/main.go index ad8248c3..14ce6189 100644 --- a/sql-migrate/main.go +++ b/sql-migrate/main.go @@ -16,33 +16,30 @@ var ui cli.Ui func realMain() int { ui = &cli.BasicUi{Writer: os.Stdout} - cli := &cli.CLI{ - Args: os.Args[1:], - Commands: map[string]cli.CommandFactory{ - "up": func() (cli.Command, error) { - return &UpCommand{}, nil - }, - "down": func() (cli.Command, error) { - return &DownCommand{}, nil - }, - "redo": func() (cli.Command, error) { - return &RedoCommand{}, nil - }, - "status": func() (cli.Command, error) { - return &StatusCommand{}, nil - }, - "new": func() (cli.Command, error) { - return &NewCommand{}, nil - }, - "skip": func() (cli.Command, error) { - return &SkipCommand{}, nil - }, + c := cli.NewCLI("sql-migrate", GetVersion()) + c.Args = os.Args[1:] + c.Commands = map[string]cli.CommandFactory{ + "up": func() (cli.Command, error) { + return &UpCommand{}, nil + }, + "down": func() (cli.Command, error) { + return &DownCommand{}, nil + }, + "redo": func() (cli.Command, error) { + return &RedoCommand{}, nil + }, + "status": func() (cli.Command, error) { + return &StatusCommand{}, nil + }, + "new": func() (cli.Command, error) { + return &NewCommand{}, nil + }, + "skip": func() (cli.Command, error) { + return &SkipCommand{}, nil }, - HelpFunc: cli.BasicHelpFunc("sql-migrate"), - Version: GetVersion(), } - exitCode, err := cli.Run() + exitCode, err := c.Run() if err != nil { _, _ = fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error()) return 1