Skip to content

Commit

Permalink
Add migration status action
Browse files Browse the repository at this point in the history
  • Loading branch information
qbart committed Dec 5, 2021
1 parent a8f8e95 commit b74411d
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 44 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
github.com/agext/levenshtein v1.2.3 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/hashicorp/hcl/v2 v2.6.0
github.com/hashicorp/hcl2 v0.0.0-20191002203319-fb75b3253c80
github.com/jackc/pgx/v4 v4.11.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
Expand Down
109 changes: 109 additions & 0 deletions krab/action_migrate_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package krab

import (
"context"
"fmt"

"github.com/emirpasic/gods/sets/hashset"
"github.com/ohkrab/krab/cli"
"github.com/ohkrab/krab/cliargs"
"github.com/ohkrab/krab/krabdb"
"github.com/ohkrab/krab/krabtpl"
"github.com/ohkrab/krab/tpls"
"github.com/pkg/errors"
"github.com/wzshiming/ctc"
)

// ActionMigrateStatus keeps data needed to perform this action.
type ActionMigrateStatus struct {
Ui cli.UI
Set *MigrationSet
Connection krabdb.Connection
}

func (a *ActionMigrateStatus) Help() string {
return fmt.Sprint(
`Usage: krab migrate status [set]`,
"\n\n",
a.Set.Arguments.Help(),
`
View migration status for given set.
`,
)
}

func (a *ActionMigrateStatus) Synopsis() string {
return fmt.Sprintf("Migration status for `%s`", a.Set.RefName)
}

// Run in CLI.
func (a *ActionMigrateStatus) Run(args []string) int {
ui := a.Ui
flags := cliargs.New(args)
flags.RequireNonFlagArgs(0)

for _, arg := range a.Set.Arguments.Args {
flags.Add(arg.Name)
}

err := flags.Parse()
if err != nil {
ui.Output(a.Help())
ui.Error(err.Error())
return 1
}

err = a.Set.Arguments.Validate(flags.Values())
if err != nil {
ui.Output(a.Help())
ui.Error(err.Error())
return 1
}

templates := tpls.New(flags.Values(), krabtpl.Functions)

err = a.Connection.Get(func(db krabdb.DB) error {
return a.Do(context.Background(), db, templates, ui)
})

if err != nil {
ui.Error(err.Error())
return 1
}

return 0
}

// Run performs the action.
func (a *ActionMigrateStatus) Do(ctx context.Context, db krabdb.DB, tpl *tpls.Templates, ui cli.UI) error {
versions := NewSchemaMigrationTable(tpl.Render(a.Set.Schema))

hooksRunner := HookRunner{}
err := hooksRunner.SetSearchPath(ctx, db, tpl.Render(a.Set.Schema))
if err != nil {
return errors.Wrap(err, "Failed to run SetSearchPath hook")
}
migrationRefsInDb, err := versions.SelectAll(ctx, db)
if err != nil {
return err
}

appliedMigrations := hashset.New()

for _, migration := range migrationRefsInDb {
appliedMigrations.Add(migration.Version)
}

for _, migration := range a.Set.Migrations {
pending := !appliedMigrations.Contains(migration.Version)

if pending {
ui.Error(fmt.Sprint("- ", migration.Version, " ", migration.RefName))
} else {
ui.Output(fmt.Sprint(ctc.ForegroundGreen, "+ ", ctc.Reset, migration.Version, " ", migration.RefName))
}

}

return nil
}
4 changes: 4 additions & 0 deletions krabcli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ func (a *App) RegisterAll() {
for _, set := range a.Config.MigrationSets {
localSet := set

a.RegisterCmd(fmt.Sprintln("migrate", "status", set.RefName), func() Command {
return &krab.ActionMigrateStatus{Ui: a.Ui, Set: localSet, Connection: a.connection}
})

a.RegisterCmd(fmt.Sprintln("migrate", "up", set.RefName), func() Command {
return &krab.ActionMigrateUp{Ui: a.Ui, Set: localSet, Connection: a.connection}
})
Expand Down
20 changes: 5 additions & 15 deletions spec/action_migrate_down_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,8 @@ migration_set "public" {
`))
defer c.Teardown()
c.AssertSuccessfulRun(t, []string{"migrate", "up", "public"})
c.AssertOutputContains(t,
`
create_animals v1
add_column v2
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv1 create_animals")
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv2 add_column")
c.AssertSchemaMigrationTable(t, "public", "v1", "v2")
c.Insert(t, "animals", "name, emoji", "('Elephant', '🐘')")
cols, rows := c.Query(t, "SELECT * from animals")
Expand All @@ -48,7 +43,7 @@ Done
}

c.AssertSuccessfulRun(t, []string{"migrate", "down", "public", "-version", "v2"})
c.AssertOutputContains(t, `Done`)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv2 add_column")
c.AssertSchemaMigrationTable(t, "public", "v1")

cols, rows = c.Query(t, "SELECT * from animals")
Expand Down Expand Up @@ -84,13 +79,8 @@ migration_set "public" {
`))
defer c.Teardown()
c.AssertSuccessfulRun(t, []string{"migrate", "up", "public"})
c.AssertOutputContains(t,
`
create_animals v1
add_column v2
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv1 create_animals")
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv2 add_column")
c.AssertSchemaMigrationTable(t, "public", "v1", "v2")
c.Insert(t, "animals", "name, emoji", "('Elephant', '🐘')")
cols, rows := c.Query(t, "SELECT * from animals")
Expand Down
13 changes: 2 additions & 11 deletions spec/action_migrate_dsl_index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,7 @@ migration_set "animals" {
defer c.Teardown()
if c.AssertSuccessfulRun(t, []string{"migrate", "up", "animals"}) {
c.AssertSchemaMigrationTable(t, "public", "v1")
c.AssertOutputContains(t,
`
create_animals v1
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv1 create_animals")
c.AssertSQLContains(t, `
CREATE TABLE "animals"(
"id" bigint,
Expand All @@ -80,11 +75,7 @@ CREATE INDEX CONCURRENTLY "idx_heavy_animals" ON "animals" ("weight_kg") WHERE (

if c.AssertSuccessfulRun(t, []string{"migrate", "down", "animals", "-version", "v1"}) {
c.AssertSchemaMigrationTable(t, "public")
c.AssertOutputContains(t,
`
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv1 create_animals")
c.AssertSQLContains(t, `DROP INDEX "public"."idx_uniq_name" CASCADE`)
c.AssertSQLContains(t, `DROP INDEX CONCURRENTLY "idx_heavy_animals"`)
c.AssertSQLContains(t, `DROP TABLE "animals"`)
Expand Down
15 changes: 3 additions & 12 deletions spec/action_migrate_dsl_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,8 @@ migration_set "animals" {
defer c.Teardown()
if c.AssertSuccessfulRun(t, []string{"migrate", "up", "animals"}) {
c.AssertSchemaMigrationTable(t, "public", "v1", "v2")
c.AssertOutputContains(t,
`
create_categories v1
create_animals v2
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv1 create_categories")
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv2 create_animals")
c.AssertSQLContains(t, `
CREATE TABLE "categories"(
"id" bigint,
Expand All @@ -126,11 +121,7 @@ CREATE UNLOGGED TABLE "animals"(

if c.AssertSuccessfulRun(t, []string{"migrate", "down", "animals", "-version", "v2"}) {
c.AssertSchemaMigrationTable(t, "public", "v1")
c.AssertOutputContains(t,
`
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv2 create_animals")
c.AssertSQLContains(t, `
DROP TABLE "animals"
`)
Expand Down
31 changes: 31 additions & 0 deletions spec/action_migrate_status_arguments_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package spec

import (
"testing"
)

func TestActionMigrateStatusArguments(t *testing.T) {
c := mockCli(mockConfig(`
migration "create_animals" {
version = "v1"
up { sql = "CREATE TABLE animals(name VARCHAR)" }
down { sql = "DROP TABLE animals" }
}
migration_set "animals" {
arguments {
arg "schema" {}
}
schema = "{{.Args.schema}}"
migrations = [migration.create_animals]
}
`))
defer c.Teardown()

c.AssertSuccessfulRun(t, []string{"migrate", "up", "animals", "-schema", "custom"})
c.AssertSuccessfulRun(t, []string{"migrate", "status", "animals", "-schema", "custom"})
c.AssertOutputContains(t, "\x1b[0;32m+ \x1b[0mv1 create_animals")
}
8 changes: 2 additions & 6 deletions spec/action_migrate_up_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ migration_set "public" {
`))
defer c.Teardown()
c.AssertSuccessfulRun(t, []string{"migrate", "up", "public"})
c.AssertOutputContains(t,
`
do_nothing v1
Done
`,
)
c.AssertOutputContains(t, "\x1b[0;32mOK \x1b[0mv1 do_nothing")
c.AssertSchemaMigrationTable(t, "public", "v1")
}

Expand All @@ -47,6 +42,7 @@ migration_set "public" {
`))

c.AssertFailedRun(t, []string{"migrate", "up", "public"})
c.AssertOutputContains(t, "\x1b[0;31mERR \x1b[0mv1 do_nothing")
c.AssertUiErrorOutputContains(t,
`column "invalid" does not exist`,
)
Expand Down

0 comments on commit b74411d

Please sign in to comment.