mf/goosecli
Mike Fridman 2025-02-17 11:57:41 -05:00
parent e26351c134
commit d9db949a2b
No known key found for this signature in database
4 changed files with 102 additions and 68 deletions

View File

@ -23,33 +23,6 @@ func defaultUsageFunc() func(c *cli.Command) string {
}
}
func dirFlag(f *flag.FlagSet) {
f.String("dir", "", "Directory with migration files")
}
func dbStringFlag(f *flag.FlagSet) {
f.String("dbstring", "", "Database connection string")
}
func tableFlag(f *flag.FlagSet) {
f.String("table", goose.DefaultTablename, "Goose migration table name")
}
// commonConnectionFlags are flags that are required for most goose commands which interact with the
// database and open a connection.
func commonConnectionFlags(f *flag.FlagSet) {
dirFlag(f)
dbStringFlag(f)
tableFlag(f)
f.Duration("timeout", 0, "Maximum allowed duration for queries to run; e.g., 1h13m")
// MySQL flags
f.String("certfile", "", "File path to root CA's certificates in pem format (mysql only)")
f.String("ssl-cert", "", "File path to SSL certificates in pem format (mysql only)")
f.String("ssl-key", "", "File path to SSL key in pem format (mysql only)")
}
var downTo = &cli.Command{
UsageFunc: defaultUsageFunc(),
@ -58,13 +31,13 @@ var downTo = &cli.Command{
ShortHelp: "Roll back migrations down to, but not including, the specified version",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
f.Bool("no-versioning", false, "Apply migration commands with no versioning, in file order, from directory pointed to")
f.Bool("json", false, "Output results in JSON format")
jsonFlag(f)
noVersioningFlag(f)
}),
Exec: func(ctx context.Context, s *cli.State) error {
printer := newPrinter(s.Stdout, defaultSeparator)
useJSON := cli.GetFlag[bool](s, "json")
useJSON := cli.GetFlag[bool](s, jsonFlagName)
if len(s.Args) == 0 {
return errors.New("must supply a version to goose down-to")
@ -76,7 +49,7 @@ var downTo = &cli.Command{
provider, err := getProvider(
s,
goose.WithDisableVersioning(cli.GetFlag[bool](s, "no-versioning")),
goose.WithDisableVersioning(cli.GetFlag[bool](s, noVersioningFlagName)),
)
if err != nil {
return err
@ -97,10 +70,7 @@ var down = &cli.Command{
Name: "down",
Usage: "goose down [flags]",
ShortHelp: "Roll back the most recently applied migration",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
f.Bool("no-versioning", false, "Apply migration commands with no versioning, in file order, from directory pointed to")
}),
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {}),
Exec: func(ctx context.Context, s *cli.State) error {
return errors.New("not implemented")
},
@ -114,19 +84,19 @@ var up = &cli.Command{
ShortHelp: "Apply all available migrations",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
f.Bool("allow-missing", false, "Applies missing (out-of-order) migrations")
f.Bool("no-versioning", false, "Apply migration commands with no versioning, in file order, from directory pointed to")
f.Bool("json", false, "Output results in JSON format")
allowMissingFlag(f)
noVersioningFlag(f)
jsonFlag(f)
}),
Exec: func(ctx context.Context, s *cli.State) error {
printer := newPrinter(s.Stdout, defaultSeparator)
useJSON := cli.GetFlag[bool](s, "json")
useJSON := cli.GetFlag[bool](s, jsonFlagName)
provider, err := getProvider(
s,
goose.WithDisableVersioning(cli.GetFlag[bool](s, "no-versioning")),
goose.WithAllowOutofOrder(cli.GetFlag[bool](s, "allow-missing")),
goose.WithDisableVersioning(cli.GetFlag[bool](s, noVersioningFlagName)),
goose.WithAllowOutofOrder(cli.GetFlag[bool](s, allowMissingFlagName)),
)
if err != nil {
return err
@ -153,8 +123,9 @@ var upByOne = &cli.Command{
ShortHelp: "Apply the next available migration",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
f.Bool("allow-missing", false, "Applies missing (out-of-order) migrations")
f.Bool("no-versioning", false, "Apply migration commands with no versioning, in file order, from directory pointed to")
allowMissingFlag(f)
noVersioningFlag(f)
jsonFlag(f)
}),
Exec: func(ctx context.Context, s *cli.State) error {
return errors.New("not implemented")
@ -169,8 +140,9 @@ var upTo = &cli.Command{
ShortHelp: "Apply all available migrations up to, and including, the specified version",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
f.Bool("allow-missing", false, "Applies missing (out-of-order) migrations")
f.Bool("no-versioning", false, "Apply migration commands with no versioning, in file order, from directory pointed to")
allowMissingFlag(f)
noVersioningFlag(f)
jsonFlag(f)
}),
Exec: func(ctx context.Context, s *cli.State) error {
return errors.New("not implemented")
@ -185,12 +157,12 @@ var status = &cli.Command{
ShortHelp: "List the status of all migrations",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
f.Bool("json", false, "Output results in JSON format")
jsonFlag(f)
}),
Exec: func(ctx context.Context, s *cli.State) error {
printer := newPrinter(s.Stdout, defaultSeparator)
useJSON := cli.GetFlag[bool](s, "json")
useJSON := cli.GetFlag[bool](s, jsonFlagName)
provider, err := getProvider(s)
if err != nil {
@ -231,6 +203,7 @@ var version = &cli.Command{
ShortHelp: "Print the current version of the database",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
commonConnectionFlags(f)
jsonFlag(f)
}),
Exec: func(ctx context.Context, s *cli.State) error {
return errors.New("not implemented")
@ -245,8 +218,8 @@ var create = &cli.Command{
ShortHelp: "Create a new migration file",
Flags: cli.FlagsFunc(func(f *flag.FlagSet) {
dirFlag(f)
f.String("s", "", "Use sequential numbering for new migrations")
f.String("type", "sql", "Type of migration to create [sql,go]")
f.String(sequentialFlagName, "", "Use sequential numbering for new migrations")
f.String(typeFlagName, "sql", "Type of migration to create [sql,go] (default: sql)")
}),
Exec: func(ctx context.Context, s *cli.State) error {
return errors.New("not implemented")

View File

@ -0,0 +1,64 @@
package goosecli
import (
"flag"
"github.com/pressly/goose/v3"
)
const (
dirFlagName = "dir"
dbStringFlagName = "dbstring"
tableFlagName = "table"
timeoutFlagName = "timeout"
certfileFlagName = "certfile"
sslCertFlagName = "ssl-cert"
sslKeyFlagName = "ssl-key"
jsonFlagName = "json"
noVersioningFlagName = "no-versioning"
allowMissingFlagName = "allow-missing"
sequentialFlagName = "s"
typeFlagName = "type"
)
func dirFlag(f *flag.FlagSet) {
f.String(dirFlagName, "", "Directory with migration files")
}
func dbStringFlag(f *flag.FlagSet) {
f.String(dbStringFlagName, "", "Database connection string")
}
func tableFlag(f *flag.FlagSet) {
f.String(tableFlagName, goose.DefaultTablename, "Goose migration table name")
}
func allowMissingFlag(f *flag.FlagSet) {
f.Bool(allowMissingFlagName, false, "Applies missing (out-of-order) migrations")
}
func noVersioningFlag(f *flag.FlagSet) {
f.Bool(noVersioningFlagName, false, "Apply migration commands with no versioning, in file order, from directory pointed to")
}
func jsonFlag(f *flag.FlagSet) {
f.Bool(jsonFlagName, false, "Output results in JSON format")
}
func timeoutFlag(f *flag.FlagSet) {
f.Duration(timeoutFlagName, 0, "Maximum allowed duration for queries to run; e.g., 1h13m")
}
// commonConnectionFlags are flags that are required for most goose commands which interact with the
// database and open a connection.
func commonConnectionFlags(f *flag.FlagSet) {
dirFlag(f)
dbStringFlag(f)
tableFlag(f)
timeoutFlag(f)
// MySQL flags
f.String(certfileFlagName, "", "File path to root CA's certificates in pem format (mysql only)")
f.String(sslCertFlagName, "", "File path to SSL certificates in pem format (mysql only)")
f.String(sslKeyFlagName, "", "File path to SSL key in pem format (mysql only)")
}

View File

@ -2,6 +2,11 @@ package goosecli
import "io"
// Option is a configuration option for the CLI.
type Option interface {
apply(*config)
}
// WithStdout sets the writer to use for stdout.
func WithStdout(w io.Writer) Option {
return optionFunc(func(cfg *config) {
@ -16,10 +21,6 @@ func WithStderr(w io.Writer) Option {
})
}
type Option interface {
apply(*config)
}
type optionFunc func(*config)
func (f optionFunc) apply(cfg *config) { f(cfg) }

View File

@ -11,7 +11,17 @@ import (
)
var root = &cli.Command{
UsageFunc: rootUsageFunc(),
UsageFunc: func(c *cli.Command) string {
return newHelp().
add("", shortHelpSection).
add("USAGE", usageSection).
add("COMMANDS", commandsSection).
add("GLOBAL FLAGS", flagsSection).
add("SUPPORTED DATABASES", databasesSection).
add("ENVIRONMENT VARIABLES (flags take precedence)", envVarsSection).
add("LEARN MORE", learnMoreSection).
build(c)
},
Name: "goose",
ShortHelp: "A database migration tool for SQL databases.",
@ -36,17 +46,3 @@ var root = &cli.Command{
return nil
},
}
func rootUsageFunc() func(c *cli.Command) string {
return func(c *cli.Command) string {
return newHelp().
add("", shortHelpSection).
add("USAGE", usageSection).
add("COMMANDS", commandsSection).
add("GLOBAL FLAGS", flagsSection).
add("SUPPORTED DATABASES", databasesSection).
add("ENVIRONMENT VARIABLES (flags take precedence)", envVarsSection).
add("LEARN MORE", learnMoreSection).
build(c)
}
}