feat(sql-migrate): add sync subcommand

Adds `sql-migrate sync` which outputs a shell script that refreshes
the local migrations.log from the DB by running _migrations.sql.
Uses `|| true` so a fresh DB with no _migrations table yields an
empty log (all migrations pending) rather than an error.

Usage:
  sql-migrate -d ./db/migrations sync | sh
  sql-migrate -d ./db/migrations up | sh
This commit is contained in:
AJ ONeal 2026-03-23 11:32:25 -06:00
parent b50696f64d
commit 1f61095873
No known key found for this signature in database

View File

@ -83,6 +83,7 @@ USAGE
EXAMPLE EXAMPLE
sql-migrate -d ./sql/migrations/ init --sql-command <psql|mariadb|mysql> sql-migrate -d ./sql/migrations/ init --sql-command <psql|mariadb|mysql>
sql-migrate -d ./sql/migrations/ create <kebab-case-description> sql-migrate -d ./sql/migrations/ create <kebab-case-description>
sql-migrate -d ./sql/migrations/ sync
sql-migrate -d ./sql/migrations/ status sql-migrate -d ./sql/migrations/ status
sql-migrate -d ./sql/migrations/ up 99 sql-migrate -d ./sql/migrations/ up 99
sql-migrate -d ./sql/migrations/ down 1 sql-migrate -d ./sql/migrations/ down 1
@ -93,6 +94,7 @@ COMMANDS
and query for migrations and query for migrations
create - creates a new, canonically-named up/down file pair in the create - creates a new, canonically-named up/down file pair in the
migrations directory, with corresponding insert migrations directory, with corresponding insert
sync - create a script to reload migrations.log from the DB
status - shows the same output as if processing a forward-migration status - shows the same output as if processing a forward-migration
up [n] - create a script to run pending migrations (ALL by default) up [n] - create a script to run pending migrations (ALL by default)
down [n] - create a script to roll back migrations (ONE by default) down [n] - create a script to roll back migrations (ONE by default)
@ -184,7 +186,7 @@ func main() {
fsSub = flag.NewFlagSet("init", flag.ExitOnError) fsSub = flag.NewFlagSet("init", flag.ExitOnError)
fsSub.StringVar(&cfg.logPath, "migrations-log", "", fmt.Sprintf("migration log file (default: %s) relative to and saved in %s", defaultLogPath, M_MIGRATOR_NAME)) fsSub.StringVar(&cfg.logPath, "migrations-log", "", fmt.Sprintf("migration log file (default: %s) relative to and saved in %s", defaultLogPath, M_MIGRATOR_NAME))
fsSub.StringVar(&cfg.sqlCommand, "sql-command", sqlCommandPSQL, "construct scripts with this to execute SQL files: 'psql', 'mysql', 'mariadb', or custom arguments") fsSub.StringVar(&cfg.sqlCommand, "sql-command", sqlCommandPSQL, "construct scripts with this to execute SQL files: 'psql', 'mysql', 'mariadb', or custom arguments")
case "create", "up", "down", "status", "list": case "create", "sync", "up", "down", "status", "list":
fsSub = flag.NewFlagSet(subcmd, flag.ExitOnError) fsSub = flag.NewFlagSet(subcmd, flag.ExitOnError)
default: default:
log.Printf("unknown command %s", subcmd) log.Printf("unknown command %s", subcmd)
@ -275,6 +277,11 @@ func main() {
switch subcmd { switch subcmd {
case "init": case "init":
break break
case "sync":
if err := syncLog(&state); err != nil {
log.Fatal(err)
}
return
case "create": case "create":
if len(leafArgs) == 0 { if len(leafArgs) == 0 {
log.Fatal("create requires a description") log.Fatal("create requires a description")
@ -844,6 +851,20 @@ func fixupMigration(dir string, basename string) (up, down bool, warn error, err
return up, down, nil, nil return up, down, nil, nil
} }
func syncLog(state *State) error {
getMigsPath := filepath.Join(state.MigrationsDir, LOG_QUERY_NAME)
getMigsPath = filepathUnclean(getMigsPath)
getMigs := strings.Replace(state.SQLCommand, "%s", getMigsPath, 1)
logPath := filepathUnclean(state.LogPath)
fmt.Printf(shHeader)
fmt.Println("")
fmt.Println("# SYNC: reload migrations log from DB")
fmt.Printf("%s > %s || true\n", getMigs, logPath)
fmt.Printf("cat %s\n", logPath)
return nil
}
func up(state *State, ups []string, n int) error { func up(state *State, ups []string, n int) error {
var pending []string var pending []string
for _, mig := range ups { for _, mig := range ups {