Short and single-letter names in application code become full words (tests keep theirs). Wrapped calls, signatures and composite literals put one item per line, and one-line function bodies are expanded. Exported names and groups of constants get doc comments, and comments refer to the renamed identifiers.
108 lines
2.6 KiB
Go
108 lines
2.6 KiB
Go
package migrate
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"path/filepath"
|
|
"text/tabwriter"
|
|
|
|
"github.com/pressly/goose/v3"
|
|
"github.com/spf13/cobra"
|
|
|
|
"git.avsdev.uk/Go/job-search/internal/cli"
|
|
"git.avsdev.uk/Go/job-search/internal/store"
|
|
)
|
|
|
|
// printStatus lists every migration as applied (with when) or pending,
|
|
// after a summary line, e.g.
|
|
//
|
|
// Database version 4 of 6 (2 pending)
|
|
// 1 applied 2026-10-07 10:12:01 00001_create_opportunities_table.sql
|
|
// ...
|
|
// 5 pending 00005_create_opportunity_classifications_table.sql
|
|
func printStatus(ctx context.Context, out io.Writer, migrator *goose.Provider) error {
|
|
statuses, err := migrator.Status(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
current, err := migrator.GetDBVersion(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
latest := store.LatestVersion(migrator)
|
|
|
|
pending := 0
|
|
for _, status := range statuses {
|
|
if status.State == goose.StatePending {
|
|
pending++
|
|
}
|
|
}
|
|
|
|
output := &errWriter{
|
|
w: out,
|
|
}
|
|
switch {
|
|
case current > latest:
|
|
output.printf(
|
|
"Database version %d is newer than this build (latest %d)\n",
|
|
current,
|
|
latest,
|
|
)
|
|
case pending == 0:
|
|
output.printf("Database version %d of %d (up-to-date)\n", current, latest)
|
|
default:
|
|
output.printf("Database version %d of %d (%d pending)\n", current, latest, pending)
|
|
}
|
|
if output.err != nil {
|
|
return output.err
|
|
}
|
|
|
|
table := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)
|
|
output = &errWriter{
|
|
w: table,
|
|
}
|
|
for _, status := range statuses {
|
|
applied := ""
|
|
if status.State == goose.StateApplied {
|
|
applied = status.AppliedAt.Local().Format("2006-01-02 15:04:05")
|
|
}
|
|
output.printf(
|
|
" %d\t%s\t%s\t%s\n",
|
|
status.Source.Version,
|
|
status.State,
|
|
applied,
|
|
filepath.Base(status.Source.Path),
|
|
)
|
|
}
|
|
return errors.Join(output.err, table.Flush())
|
|
}
|
|
|
|
func commandStatus(opts *cli.Options) *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "status",
|
|
Short: "Show which migrations have been applied to the SQLite database",
|
|
Args: cobra.NoArgs,
|
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
|
slog.Debug("command persistent pre-run", "command", "migrate.status")
|
|
},
|
|
PersistentPostRun: func(cmd *cobra.Command, args []string) {
|
|
slog.Debug("command persistent post-run", "command", "migrate.status")
|
|
},
|
|
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
|
slog.Debug("command run", "command", "migrate.status")
|
|
|
|
migrator, db, err := openMigrator(cmd, opts, false, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer closeDB(db, &err)
|
|
|
|
return printStatus(cmd.Context(), cmd.OutOrStdout(), migrator)
|
|
},
|
|
}
|
|
}
|