diff --git a/cmd/db-migrator/main.go b/cmd/db-migrator/main.go index 2106664..037f064 100644 --- a/cmd/db-migrator/main.go +++ b/cmd/db-migrator/main.go @@ -9,14 +9,14 @@ package main import ( + "context" "fmt" "os" - "slices" _ "github.com/lib/pq" "github.com/raoptimus/db-migrator.go/internal/migrator" "github.com/raoptimus/db-migrator.go/pkg/console" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) var ( @@ -28,120 +28,108 @@ var ( func main() { options := migrator.Options{} - app := cli.NewApp() - app.Name = "DB Service" - app.Usage = "up/down/redo command for migrates the different db" - app.Version = fmt.Sprintf("%s.rev[%s]", Version, GitCommit) - app.Commands = commands(&options) - app.Before = func(context *cli.Context) error { - dbService = migrator.New(&options) - return nil + cmd := &cli.Command{ + Name: "DB Service", + Usage: "up/down/redo command for migrates the different db", + Version: fmt.Sprintf("%s.rev[%s]", Version, GitCommit), + Commands: commands(), + DefaultCommand: "help", + Flags: flags(&options), + Before: func(ctx context.Context, cmd *cli.Command) (context.Context, error) { + dbService = migrator.New(&options) + + return ctx, nil + }, } - if err := app.Run(os.Args); err != nil { + if err := cmd.Run(context.Background(), os.Args); err != nil { console.Std.Fatal(err) } } -func commands(options *migrator.Options) []*cli.Command { - defaultFlags := flags(options) - allFlags := slices.Concat(defaultFlags, addsFlags(options)) - +func commands() []*cli.Command { return []*cli.Command{ { - Name: "up", - Flags: allFlags, - Action: func(ctx *cli.Context) error { + Name: "up", + Action: func(ctx context.Context, cmd *cli.Command) error { if a, err := dbService.Upgrade(); err != nil { return err } else { - return a.Run(ctx) + return a.Run(ctx, cmd.Args()) } }, }, { - Name: "down", - Flags: allFlags, - Action: func(ctx *cli.Context) error { + Name: "down", + Action: func(ctx context.Context, cmd *cli.Command) error { if a, err := dbService.Downgrade(); err != nil { return err } else { - return a.Run(ctx) + return a.Run(ctx, cmd.Args()) } }, }, { - Name: "redo", - Flags: allFlags, - Action: func(ctx *cli.Context) error { + Name: "redo", + Action: func(ctx context.Context, cmd *cli.Command) error { if a, err := dbService.Redo(); err != nil { return err } else { - return a.Run(ctx) + return a.Run(ctx, cmd.Args()) } }, }, { - Name: "create", - Flags: defaultFlags, - Action: func(ctx *cli.Context) error { - return dbService.Create().Run(ctx) + Name: "create", + Action: func(ctx context.Context, cmd *cli.Command) error { + return dbService.Create().Run(ctx, cmd.Args()) }, }, { - Name: "history", - Flags: allFlags, - Action: func(ctx *cli.Context) error { + Name: "history", + Action: func(ctx context.Context, cmd *cli.Command) error { if a, err := dbService.History(); err != nil { return err } else { - return a.Run(ctx) + return a.Run(ctx, cmd.Args()) } }, }, { - Name: "new", - Flags: allFlags, - Action: func(ctx *cli.Context) error { + Name: "new", + Action: func(ctx context.Context, cmd *cli.Command) error { if a, err := dbService.HistoryNew(); err != nil { return err } else { - return a.Run(ctx) + return a.Run(ctx, cmd.Args()) } }, }, { - Name: "to", - Flags: allFlags, - Action: func(ctx *cli.Context) error { + Name: "to", + Action: func(ctx context.Context, cmd *cli.Command) error { if a, err := dbService.To(); err != nil { return err } else { - return a.Run(ctx) + return a.Run(ctx, cmd.Args()) } }, }, } } -func addsFlags(options *migrator.Options) []cli.Flag { +func flags(options *migrator.Options) []cli.Flag { return []cli.Flag{ &cli.StringFlag{ Name: "dsn", - EnvVars: []string{"DSN"}, + Sources: cli.EnvVars("DSN"), Aliases: []string{"d"}, Usage: "DB connection string", Destination: &options.DSN, - Required: true, }, - } -} - -func flags(options *migrator.Options) []cli.Flag { - return []cli.Flag{ &cli.StringFlag{ Name: "migrationPath", - EnvVars: []string{"MIGRATION_PATH"}, + Sources: cli.EnvVars("MIGRATION_PATH"), Aliases: []string{"p"}, Value: "./migrations", Usage: "Directory for migrated files", @@ -149,7 +137,7 @@ func flags(options *migrator.Options) []cli.Flag { }, &cli.StringFlag{ Name: "migrationTable", - EnvVars: []string{"MIGRATION_TABLE"}, + Sources: cli.EnvVars("MIGRATION_TABLE"), Aliases: []string{"t"}, Value: "migration", Usage: "Table name for history of migrates", @@ -157,7 +145,7 @@ func flags(options *migrator.Options) []cli.Flag { }, &cli.StringFlag{ Name: "migrationClusterName", - EnvVars: []string{"MIGRATION_CLUSTER_NAME"}, + Sources: cli.EnvVars("MIGRATION_CLUSTER_NAME"), Aliases: []string{"cn"}, Value: "", Usage: "Cluster name for history of migrates", @@ -165,7 +153,7 @@ func flags(options *migrator.Options) []cli.Flag { }, &cli.BoolFlag{ Name: "compact", - EnvVars: []string{"COMPACT"}, + Sources: cli.EnvVars("COMPACT"), Aliases: []string{"c"}, Usage: "Indicates whether the console output should be compacted.", Value: false, @@ -173,7 +161,7 @@ func flags(options *migrator.Options) []cli.Flag { }, &cli.BoolFlag{ Name: "interactive", - EnvVars: []string{"INTERACTIVE"}, + Sources: cli.EnvVars("INTERACTIVE"), Aliases: []string{"i"}, Usage: "Whether to run the command interactively", Value: true, diff --git a/go.mod b/go.mod index d9bb97e..6a27f5b 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/raoptimus/db-migrator.go/pkg/timex v0.0.0-20240503100150-5445e535daaf github.com/stretchr/testify v1.10.0 github.com/urfave/cli/v2 v2.27.5 + github.com/urfave/cli/v3 v3.0.0-beta1 ) require ( diff --git a/go.sum b/go.sum index 4a4ebcd..c177b0d 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/ClickHouse/clickhouse-go/v2 v2.30.0 h1:AG4D/hW39qa58+JHQIFOSnxyL46H6h github.com/ClickHouse/clickhouse-go/v2 v2.30.0/go.mod h1:i9ZQAojcayW3RsdCb3YR+n+wC2h65eJsZCscZ1Z1wyo= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -73,20 +71,16 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= +github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= diff --git a/internal/action/common_test.go b/internal/action/common_test.go index adf0ed8..2d17dfe 100644 --- a/internal/action/common_test.go +++ b/internal/action/common_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) var time230527213123 = time.Date( diff --git a/internal/action/create.go b/internal/action/create.go index e2199b5..e17085e 100644 --- a/internal/action/create.go +++ b/internal/action/create.go @@ -9,13 +9,14 @@ package action import ( + "context" "fmt" "os" "regexp" "github.com/pkg/errors" "github.com/raoptimus/db-migrator.go/pkg/timex" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) const fileModeExecutable = 0o755 @@ -46,8 +47,8 @@ func NewCreate( } } -func (c *Create) Run(ctx *cli.Context) error { - migrationName := ctx.Args().Get(0) +func (c *Create) Run(_ context.Context, cmdArgs cli.Args) error { + migrationName := cmdArgs.Get(0) if !regexpFileName.MatchString(migrationName) { return ErrInvalidFileName } diff --git a/internal/action/downgrade.go b/internal/action/downgrade.go index 16b08b4..5c18ee4 100644 --- a/internal/action/downgrade.go +++ b/internal/action/downgrade.go @@ -9,11 +9,12 @@ package action import ( + "context" "fmt" "github.com/raoptimus/db-migrator.go/internal/args" "github.com/raoptimus/db-migrator.go/internal/console" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Downgrade struct { @@ -34,13 +35,13 @@ func NewDowngrade( } } -func (d *Downgrade) Run(ctx *cli.Context) error { - limit, err := args.ParseStepStringOrDefault(ctx.Args().Get(0), minLimit) +func (d *Downgrade) Run(ctx context.Context, cmdArgs cli.Args) error { + limit, err := args.ParseStepStringOrDefault(cmdArgs.Get(0), minLimit) if err != nil { return err } - migrations, err := d.service.Migrations(ctx.Context, limit) + migrations, err := d.service.Migrations(ctx, limit) if err != nil { return err } @@ -72,7 +73,7 @@ func (d *Downgrade) Run(ctx *cli.Context) error { migration := &migrations[i] fileName, safely := d.fileNameBuilder.Down(migration.Version, false) - if err := d.service.RevertFile(ctx.Context, migration, fileName, safely); err != nil { + if err := d.service.RevertFile(ctx, migration, fileName, safely); err != nil { console.Errorf( "%d from %d %s reverted.\n"+ "Migration failed. The rest of the migrations are canceled.\n", diff --git a/internal/action/history.go b/internal/action/history.go index 2da4e92..4925060 100644 --- a/internal/action/history.go +++ b/internal/action/history.go @@ -9,9 +9,11 @@ package action import ( + "context" + "github.com/raoptimus/db-migrator.go/internal/args" "github.com/raoptimus/db-migrator.go/internal/console" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) const defaultGetHistoryLimit = 10 @@ -28,13 +30,13 @@ func NewHistory( } } -func (h *History) Run(ctx *cli.Context) error { - limit, err := args.ParseStepStringOrDefault(ctx.Args().Get(0), defaultGetHistoryLimit) +func (h *History) Run(ctx context.Context, cmdArgs cli.Args) error { + limit, err := args.ParseStepStringOrDefault(cmdArgs.Get(0), defaultGetHistoryLimit) if err != nil { return err } - migrations, err := h.service.Migrations(ctx.Context, limit) + migrations, err := h.service.Migrations(ctx, limit) if err != nil { return err } diff --git a/internal/action/history_new.go b/internal/action/history_new.go index 350f036..5e965cd 100644 --- a/internal/action/history_new.go +++ b/internal/action/history_new.go @@ -9,9 +9,11 @@ package action import ( + "context" + "github.com/raoptimus/db-migrator.go/internal/args" "github.com/raoptimus/db-migrator.go/internal/console" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type HistoryNew struct { @@ -26,13 +28,13 @@ func NewHistoryNew( } } -func (h *HistoryNew) Run(ctx *cli.Context) error { - limit, err := args.ParseStepStringOrDefault(ctx.Args().Get(0), defaultGetHistoryLimit) +func (h *HistoryNew) Run(ctx context.Context, cmdArgs cli.Args) error { + limit, err := args.ParseStepStringOrDefault(cmdArgs.Get(0), defaultGetHistoryLimit) if err != nil { return err } - migrations, err := h.service.NewMigrations(ctx.Context) + migrations, err := h.service.NewMigrations(ctx) if err != nil { return err } diff --git a/internal/action/redo.go b/internal/action/redo.go index 4b89116..b858b7d 100644 --- a/internal/action/redo.go +++ b/internal/action/redo.go @@ -9,12 +9,13 @@ package action import ( + "context" "fmt" "github.com/raoptimus/db-migrator.go/internal/args" "github.com/raoptimus/db-migrator.go/internal/console" "github.com/raoptimus/db-migrator.go/internal/dal/entity" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type Redo struct { @@ -35,13 +36,13 @@ func NewRedo( } } -func (r *Redo) Run(ctx *cli.Context) error { - limit, err := args.ParseStepStringOrDefault(ctx.Args().Get(0), minLimit) +func (r *Redo) Run(ctx context.Context, cmdArgs cli.Args) error { + limit, err := args.ParseStepStringOrDefault(cmdArgs.Get(0), minLimit) if err != nil { return err } - migrations, err := r.service.Migrations(ctx.Context, limit) + migrations, err := r.service.Migrations(ctx, limit) if err != nil { return err } @@ -72,7 +73,7 @@ func (r *Redo) Run(ctx *cli.Context) error { migration := &migrations[i] fileName, safely := r.fileNameBuilder.Down(migration.Version, false) - if err := r.service.RevertFile(ctx.Context, migration, fileName, safely); err != nil { + if err := r.service.RevertFile(ctx, migration, fileName, safely); err != nil { console.ErrorLn("Migration failed. The rest of the migrations are canceled.") return err } @@ -84,7 +85,7 @@ func (r *Redo) Run(ctx *cli.Context) error { migration := &reversedMigrations[i] fileName, safely := r.fileNameBuilder.Up(migration.Version, false) - if err := r.service.ApplyFile(ctx.Context, migration, fileName, safely); err != nil { + if err := r.service.ApplyFile(ctx, migration, fileName, safely); err != nil { console.ErrorLn("Migration failed. The rest of the migrations are canceled.\n") return err } diff --git a/internal/action/to.go b/internal/action/to.go index 0a179c9..3b500a7 100644 --- a/internal/action/to.go +++ b/internal/action/to.go @@ -1,8 +1,10 @@ package action import ( + "context" + "github.com/raoptimus/db-migrator.go/internal/console" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) type To struct { @@ -23,7 +25,7 @@ func NewTo( } } -func (t *To) Run(ctx *cli.Context) error { +func (t *To) Run(_ context.Context, _ cli.Args) error { // version string from args console.Info("coming soon") return nil diff --git a/internal/action/upgrade.go b/internal/action/upgrade.go index 3883680..3c8c3c4 100644 --- a/internal/action/upgrade.go +++ b/internal/action/upgrade.go @@ -9,10 +9,11 @@ package action import ( + "context" "fmt" "github.com/raoptimus/db-migrator.go/internal/args" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) const ( @@ -40,13 +41,13 @@ func NewUpgrade( } } -func (u *Upgrade) Run(ctx *cli.Context) error { - limit, err := args.ParseStepStringOrDefault(ctx.Args().Get(0), defaultUpgradeLimit) +func (u *Upgrade) Run(ctx context.Context, cmdArgs cli.Args) error { + limit, err := args.ParseStepStringOrDefault(cmdArgs.Get(0), defaultUpgradeLimit) if err != nil { return err } - migrations, err := u.service.NewMigrations(ctx.Context) + migrations, err := u.service.NewMigrations(ctx) if err != nil { return err } @@ -90,7 +91,7 @@ func (u *Upgrade) Run(ctx *cli.Context) error { migration := &migrations[i] fileName, safely := u.fileNameBuilder.Up(migration.Version, false) - if err := u.service.ApplyFile(ctx.Context, migration, fileName, safely); err != nil { + if err := u.service.ApplyFile(ctx, migration, fileName, safely); err != nil { u.console.Errorf("%d from %d %s applied.\n", applied, migrations.Len(), diff --git a/internal/migrator/db_service_test.go b/internal/migrator/db_service_test.go index 137f3bb..ea640cc 100644 --- a/internal/migrator/db_service_test.go +++ b/internal/migrator/db_service_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/urfave/cli/v2" + "github.com/urfave/cli/v3" ) func TestDBService_Create_ReturnsAction(t *testing.T) { diff --git a/internal/service/migration.go b/internal/service/migration.go index 2521073..7ac29ab 100644 --- a/internal/service/migration.go +++ b/internal/service/migration.go @@ -163,7 +163,10 @@ func (m *Migration) ApplySQL( } m.console.Warnf("*** applying %s\n", version) scanner := sqlio.NewScanner(strings.NewReader(upSQL)) - elapsedTime, err := m.apply(ctx, scanner, safely) + + start := time.Now() + err := m.apply(ctx, scanner, safely) + elapsedTime := time.Since(start) if err != nil { m.console.Errorf("*** failed to apply %s (time: %.3fs)\n", version, elapsedTime.Seconds()) return err @@ -188,9 +191,12 @@ func (m *Migration) RevertSQL( } m.console.Warnf("*** reverting %s\n", version) scanner := sqlio.NewScanner(strings.NewReader(downSQL)) - elapsedTime, err := m.apply(ctx, scanner, safely) + start := time.Now() + err := m.apply(ctx, scanner, safely) + elapsedTime := time.Since(start) if err != nil { m.console.Errorf("*** failed to reverted %s (time: %.3fs)\n", version, elapsedTime.Seconds()) + return err } if err := m.repo.RemoveMigration(ctx, version); err != nil { @@ -209,15 +215,20 @@ func (m *Migration) ApplyFile(ctx context.Context, entity *entity.Migration, fil if err != nil { return err } - elapsedTime, err := m.apply(ctx, scanner, safely) + + start := time.Now() + err = m.apply(ctx, scanner, safely) + elapsedTime := time.Since(start) if err != nil { m.console.Errorf("*** failed to apply %s (time: %.3fs)\n", entity.Version, elapsedTime.Seconds()) + return err } if err := m.repo.InsertMigration(ctx, entity.Version); err != nil { return err } m.console.Successf("*** applied %s (time: %.3fs)\n", entity.Version, elapsedTime.Seconds()) + return nil } @@ -231,7 +242,9 @@ func (m *Migration) RevertFile(ctx context.Context, entity *entity.Migration, fi return err } - elapsedTime, err := m.apply(ctx, scanner, safely) + start := time.Now() + err = m.apply(ctx, scanner, safely) + elapsedTime := time.Since(start) if err != nil { m.console.Errorf("*** failed to reverted %s (time: %.3fs)\n", entity.Version, elapsedTime.Seconds()) @@ -279,12 +292,7 @@ func (m *Migration) EndCommand(start time.Time) { } } -func (m *Migration) apply( - ctx context.Context, - scanner *sqlio.Scanner, - safely bool, -) (time.Duration, error) { - start := time.Now() +func (m *Migration) apply(ctx context.Context, scanner *sqlio.Scanner, safely bool) error { processScanFunc := func(ctx context.Context) error { var q string for scanner.Scan() { @@ -305,8 +313,8 @@ func (m *Migration) apply( } else { err = processScanFunc(ctx) } - elapsedTime := time.Since(start) - return elapsedTime, err + + return err } func (m *Migration) scannerByFile(fileName string) (*sqlio.Scanner, error) {