Skip to content

Commit 763dabc

Browse files
Move logic for the status command into the state and migrations 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.
1 parent 34bbb24 commit 763dabc

File tree

5 files changed

+132
-39
lines changed

5 files changed

+132
-39
lines changed

cmd/status.go

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
package cmd
44

55
import (
6-
"context"
76
"encoding/json"
87
"fmt"
98

@@ -13,12 +12,6 @@ import (
1312
"github.com/spf13/cobra"
1413
)
1514

16-
type statusLine struct {
17-
Schema string
18-
Version string
19-
Status string
20-
}
21-
2215
var statusCmd = &cobra.Command{
2316
Use: "status",
2417
Short: "Show pgroll status",
@@ -30,12 +23,12 @@ var statusCmd = &cobra.Command{
3023
}
3124
defer state.Close()
3225

33-
statusLine, err := statusForSchema(ctx, state, flags.Schema())
26+
status, err := state.Status(ctx, flags.Schema())
3427
if err != nil {
3528
return err
3629
}
3730

38-
statusJSON, err := json.MarshalIndent(statusLine, "", " ")
31+
statusJSON, err := json.MarshalIndent(status, "", " ")
3932
if err != nil {
4033
return err
4134
}
@@ -44,33 +37,3 @@ var statusCmd = &cobra.Command{
4437
return nil
4538
},
4639
}
47-
48-
func statusForSchema(ctx context.Context, st *state.State, schema string) (*statusLine, error) {
49-
latestVersion, err := st.LatestVersion(ctx, schema)
50-
if err != nil {
51-
return nil, err
52-
}
53-
if latestVersion == nil {
54-
latestVersion = new(string)
55-
}
56-
57-
isActive, err := st.IsActiveMigrationPeriod(ctx, schema)
58-
if err != nil {
59-
return nil, err
60-
}
61-
62-
var status string
63-
if *latestVersion == "" {
64-
status = "No migrations"
65-
} else if isActive {
66-
status = "In Progress"
67-
} else {
68-
status = "Complete"
69-
}
70-
71-
return &statusLine{
72-
Schema: schema,
73-
Version: *latestVersion,
74-
Status: status,
75-
}, nil
76-
}

pkg/roll/execute_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,78 @@ func TestViewsAreCreatedWithSecurityInvokerTrue(t *testing.T) {
389389
})
390390
}
391391

392+
func TestStatusMethodReturnsCorrectStatus(t *testing.T) {
393+
t.Parallel()
394+
395+
withMigratorAndConnectionToContainer(t, func(mig *roll.Roll, db *sql.DB) {
396+
ctx := context.Background()
397+
398+
// Get the initial migration status before any migrations are run
399+
status, err := mig.Status(ctx, "public")
400+
assert.NoError(t, err)
401+
402+
// Ensure that the status shows "No migrations"
403+
assert.Equal(t, &state.Status{
404+
Schema: "public",
405+
Version: "",
406+
Status: state.NoneMigrationStatus,
407+
}, status)
408+
409+
// Start a migration
410+
err = mig.Start(ctx, &migrations.Migration{
411+
Name: "01_create_table",
412+
Operations: []migrations.Operation{createTableOp("table1")},
413+
})
414+
assert.NoError(t, err)
415+
416+
// Get the migration status
417+
status, err = mig.Status(ctx, "public")
418+
assert.NoError(t, err)
419+
420+
// Ensure that the status shows "In progress"
421+
assert.Equal(t, &state.Status{
422+
Schema: "public",
423+
Version: "01_create_table",
424+
Status: state.InProgressMigrationStatus,
425+
}, status)
426+
427+
// Rollback the migration
428+
err = mig.Rollback(ctx)
429+
assert.NoError(t, err)
430+
431+
// Get the migration status
432+
status, err = mig.Status(ctx, "public")
433+
assert.NoError(t, err)
434+
435+
// Ensure that the status shows "No migrations"
436+
assert.Equal(t, &state.Status{
437+
Schema: "public",
438+
Version: "",
439+
Status: state.NoneMigrationStatus,
440+
}, status)
441+
442+
// Start and complete a migration
443+
err = mig.Start(ctx, &migrations.Migration{
444+
Name: "01_create_table",
445+
Operations: []migrations.Operation{createTableOp("table1")},
446+
})
447+
assert.NoError(t, err)
448+
err = mig.Complete(ctx)
449+
assert.NoError(t, err)
450+
451+
// Get the migration status
452+
status, err = mig.Status(ctx, "public")
453+
assert.NoError(t, err)
454+
455+
// Ensure that the status shows "Complete"
456+
assert.Equal(t, &state.Status{
457+
Schema: "public",
458+
Version: "01_create_table",
459+
Status: state.CompleteMigrationStatus,
460+
}, status)
461+
})
462+
}
463+
392464
func createTableOp(tableName string) *migrations.OpCreateTable {
393465
return &migrations.OpCreateTable{
394466
Name: tableName,

pkg/roll/roll.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ func (m *Roll) PGVersion() PGVersion {
7575
return m.pgVersion
7676
}
7777

78+
func (m *Roll) Status(ctx context.Context, schema string) (*state.Status, error) {
79+
return m.state.Status(ctx, schema)
80+
}
81+
7882
func (m *Roll) Close() error {
7983
err := m.state.Close()
8084
if err != nil {

pkg/state/state.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,37 @@ func (s *State) PreviousVersion(ctx context.Context, schema string) (*string, er
334334
return parent, nil
335335
}
336336

337+
// Status returns the current migration status of the specified schema
338+
func (s *State) Status(ctx context.Context, schema string) (*Status, error) {
339+
latestVersion, err := s.LatestVersion(ctx, schema)
340+
if err != nil {
341+
return nil, err
342+
}
343+
if latestVersion == nil {
344+
latestVersion = new(string)
345+
}
346+
347+
isActive, err := s.IsActiveMigrationPeriod(ctx, schema)
348+
if err != nil {
349+
return nil, err
350+
}
351+
352+
var status MigrationStatus
353+
if *latestVersion == "" {
354+
status = NoneMigrationStatus
355+
} else if isActive {
356+
status = InProgressMigrationStatus
357+
} else {
358+
status = CompleteMigrationStatus
359+
}
360+
361+
return &Status{
362+
Schema: schema,
363+
Version: *latestVersion,
364+
Status: status,
365+
}, nil
366+
}
367+
337368
// ReadSchema reads & returns the current schema from postgres
338369
func ReadSchema(ctx context.Context, conn *sql.DB, stateSchema, schemaname string) (*schema.Schema, error) {
339370
var res schema.Schema

pkg/state/status.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package state
4+
5+
type MigrationStatus string
6+
7+
const (
8+
NoneMigrationStatus MigrationStatus = "No migrations"
9+
InProgressMigrationStatus MigrationStatus = "In progress"
10+
CompleteMigrationStatus MigrationStatus = "Complete"
11+
)
12+
13+
// Status describes the current migration status of a database schema.
14+
type Status struct {
15+
// The schema name.
16+
Schema string `json:"schema"`
17+
18+
// The name of the latest version schema.
19+
Version string `json:"version"`
20+
21+
// The status of the most recent migration.
22+
Status MigrationStatus `json:"status"`
23+
}

0 commit comments

Comments
 (0)