Skip to content

Commit

Permalink
Move logic for the status command into the state and migrations
Browse files Browse the repository at this point in the history
… packages (#205)

Move the logic for the `pgroll status` command out of the CLI and into
the `migrations` and `state` package and add tests for it.

This makes it possible to consume migration status information from
packages using `pgroll` as a module.
  • Loading branch information
andrew-farries committed Nov 22, 2023
1 parent 34bbb24 commit 763dabc
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 39 deletions.
41 changes: 2 additions & 39 deletions cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package cmd

import (
"context"
"encoding/json"
"fmt"

Expand All @@ -13,12 +12,6 @@ import (
"github.com/spf13/cobra"
)

type statusLine struct {
Schema string
Version string
Status string
}

var statusCmd = &cobra.Command{
Use: "status",
Short: "Show pgroll status",
Expand All @@ -30,12 +23,12 @@ var statusCmd = &cobra.Command{
}
defer state.Close()

statusLine, err := statusForSchema(ctx, state, flags.Schema())
status, err := state.Status(ctx, flags.Schema())
if err != nil {
return err
}

statusJSON, err := json.MarshalIndent(statusLine, "", " ")
statusJSON, err := json.MarshalIndent(status, "", " ")
if err != nil {
return err
}
Expand All @@ -44,33 +37,3 @@ var statusCmd = &cobra.Command{
return nil
},
}

func statusForSchema(ctx context.Context, st *state.State, schema string) (*statusLine, error) {
latestVersion, err := st.LatestVersion(ctx, schema)
if err != nil {
return nil, err
}
if latestVersion == nil {
latestVersion = new(string)
}

isActive, err := st.IsActiveMigrationPeriod(ctx, schema)
if err != nil {
return nil, err
}

var status string
if *latestVersion == "" {
status = "No migrations"
} else if isActive {
status = "In Progress"
} else {
status = "Complete"
}

return &statusLine{
Schema: schema,
Version: *latestVersion,
Status: status,
}, nil
}
72 changes: 72 additions & 0 deletions pkg/roll/execute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,78 @@ func TestViewsAreCreatedWithSecurityInvokerTrue(t *testing.T) {
})
}

func TestStatusMethodReturnsCorrectStatus(t *testing.T) {
t.Parallel()

withMigratorAndConnectionToContainer(t, func(mig *roll.Roll, db *sql.DB) {
ctx := context.Background()

// Get the initial migration status before any migrations are run
status, err := mig.Status(ctx, "public")
assert.NoError(t, err)

// Ensure that the status shows "No migrations"
assert.Equal(t, &state.Status{
Schema: "public",
Version: "",
Status: state.NoneMigrationStatus,
}, status)

// Start a migration
err = mig.Start(ctx, &migrations.Migration{
Name: "01_create_table",
Operations: []migrations.Operation{createTableOp("table1")},
})
assert.NoError(t, err)

// Get the migration status
status, err = mig.Status(ctx, "public")
assert.NoError(t, err)

// Ensure that the status shows "In progress"
assert.Equal(t, &state.Status{
Schema: "public",
Version: "01_create_table",
Status: state.InProgressMigrationStatus,
}, status)

// Rollback the migration
err = mig.Rollback(ctx)
assert.NoError(t, err)

// Get the migration status
status, err = mig.Status(ctx, "public")
assert.NoError(t, err)

// Ensure that the status shows "No migrations"
assert.Equal(t, &state.Status{
Schema: "public",
Version: "",
Status: state.NoneMigrationStatus,
}, status)

// Start and complete a migration
err = mig.Start(ctx, &migrations.Migration{
Name: "01_create_table",
Operations: []migrations.Operation{createTableOp("table1")},
})
assert.NoError(t, err)
err = mig.Complete(ctx)
assert.NoError(t, err)

// Get the migration status
status, err = mig.Status(ctx, "public")
assert.NoError(t, err)

// Ensure that the status shows "Complete"
assert.Equal(t, &state.Status{
Schema: "public",
Version: "01_create_table",
Status: state.CompleteMigrationStatus,
}, status)
})
}

func createTableOp(tableName string) *migrations.OpCreateTable {
return &migrations.OpCreateTable{
Name: tableName,
Expand Down
4 changes: 4 additions & 0 deletions pkg/roll/roll.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ func (m *Roll) PGVersion() PGVersion {
return m.pgVersion
}

func (m *Roll) Status(ctx context.Context, schema string) (*state.Status, error) {
return m.state.Status(ctx, schema)
}

func (m *Roll) Close() error {
err := m.state.Close()
if err != nil {
Expand Down
31 changes: 31 additions & 0 deletions pkg/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,37 @@ func (s *State) PreviousVersion(ctx context.Context, schema string) (*string, er
return parent, nil
}

// Status returns the current migration status of the specified schema
func (s *State) Status(ctx context.Context, schema string) (*Status, error) {
latestVersion, err := s.LatestVersion(ctx, schema)
if err != nil {
return nil, err
}
if latestVersion == nil {
latestVersion = new(string)
}

isActive, err := s.IsActiveMigrationPeriod(ctx, schema)
if err != nil {
return nil, err
}

var status MigrationStatus
if *latestVersion == "" {
status = NoneMigrationStatus
} else if isActive {
status = InProgressMigrationStatus
} else {
status = CompleteMigrationStatus
}

return &Status{
Schema: schema,
Version: *latestVersion,
Status: status,
}, nil
}

// ReadSchema reads & returns the current schema from postgres
func ReadSchema(ctx context.Context, conn *sql.DB, stateSchema, schemaname string) (*schema.Schema, error) {
var res schema.Schema
Expand Down
23 changes: 23 additions & 0 deletions pkg/state/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: Apache-2.0

package state

type MigrationStatus string

const (
NoneMigrationStatus MigrationStatus = "No migrations"
InProgressMigrationStatus MigrationStatus = "In progress"
CompleteMigrationStatus MigrationStatus = "Complete"
)

// Status describes the current migration status of a database schema.
type Status struct {
// The schema name.
Schema string `json:"schema"`

// The name of the latest version schema.
Version string `json:"version"`

// The status of the most recent migration.
Status MigrationStatus `json:"status"`
}

0 comments on commit 763dabc

Please sign in to comment.