Skip to content

Commit

Permalink
New command: bootstrap (#414)
Browse files Browse the repository at this point in the history
This PR adds a new command called `bootstrap`. It runs all the
migrations in the specified folder. Migration files are JSON files,
ordered alphabetically.

Help:
```
> go run . bootstrap -h
Bootstrap a new database from a directory of migration files. All files in the directory will be executed
in alphabetical order. All migrations are completed.

Usage:
  pgroll bootstrap <folder> [flags]

Flags:
  -h, --help   help for bootstrap
```

Closes #269
  • Loading branch information
kvch authored Oct 18, 2024
1 parent 7d88c25 commit 7130506
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 40 deletions.
6 changes: 1 addition & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ lint:
examples:
@go build
@./pgroll init
@for file in examples/*.json; do \
if [ -f $$file ]; then \
./pgroll start --complete $$file; \
fi \
done
@./pgroll bootstrap examples
@go clean

test:
Expand Down
51 changes: 51 additions & 0 deletions cmd/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"fmt"
"os"
"path/filepath"
"slices"

"github.com/spf13/cobra"
)

var bootstrapCmd = &cobra.Command{
Use: "bootstrap <folder>",
Short: "Bootstrap a new database from a directory of migration files",
Long: `Bootstrap a new database from a directory of migration files. All files in the directory will be executed
in lexicographical order. All migrations are completed.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
migrationsDir := args[0]

m, err := NewRoll(cmd.Context())
if err != nil {
return err
}
defer m.Close()

// open folder and read all json files
files, err := os.ReadDir(migrationsDir)
if err != nil {
return fmt.Errorf("reading migration directory: %w", err)
}
migrationFiles := []string{}
for _, file := range files {
if file.IsDir() || filepath.Ext(file.Name()) != ".json" {
continue
}
migrationFiles = append(migrationFiles, filepath.Join(migrationsDir, file.Name()))
}
slices.Sort(migrationFiles)

for _, fileName := range migrationFiles {
if err := runMigrationFromFile(cmd.Context(), m, fileName, true); err != nil {
return fmt.Errorf("running migration file '%s': %w", fileName, err)
}
}

return nil
},
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func Execute() error {
rootCmd.AddCommand(analyzeCmd)
rootCmd.AddCommand(initCmd)
rootCmd.AddCommand(statusCmd)
rootCmd.AddCommand(bootstrapCmd)

return rootCmd.Execute()
}
76 changes: 41 additions & 35 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package cmd

import (
"context"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -32,48 +33,53 @@ func startCmd() *cobra.Command {
}
defer m.Close()

file, err := os.Open(fileName)
if err != nil {
return fmt.Errorf("opening migration file: %w", err)
}
defer file.Close()
return runMigrationFromFile(cmd.Context(), m, fileName, complete)
},
}

migration, err := migrations.ReadMigration(file)
if err != nil {
return fmt.Errorf("reading migration file: %w", err)
}
startCmd.Flags().BoolVarP(&complete, "complete", "c", false, "Mark the migration as complete")

sp, _ := pterm.DefaultSpinner.WithText("Starting migration...").Start()
cb := func(n int64) {
sp.UpdateText(fmt.Sprintf("%d records complete...", n))
}
return startCmd
}

err = m.Start(cmd.Context(), migration, cb)
if err != nil {
sp.Fail(fmt.Sprintf("Failed to start migration: %s", err))
return err
}
func runMigrationFromFile(ctx context.Context, m *roll.Roll, fileName string, complete bool) error {
file, err := os.Open(fileName)
if err != nil {
return fmt.Errorf("opening migration file: %w", err)
}

if complete {
if err = m.Complete(cmd.Context()); err != nil {
sp.Fail(fmt.Sprintf("Failed to complete migration: %s", err))
return err
}
}
migration, err := migrations.ReadMigration(file)
if err != nil {
file.Close()
return fmt.Errorf("reading migration file: %w", err)
}
file.Close()

version := migration.Name
if version == "" {
version = strings.TrimSuffix(filepath.Base(fileName), filepath.Ext(fileName))
}
viewName := roll.VersionedSchemaName(flags.Schema(), version)
msg := fmt.Sprintf("New version of the schema available under the postgres %q schema", viewName)
sp.Success(msg)
sp, _ := pterm.DefaultSpinner.WithText("Starting migration...").Start()
cb := func(n int64) {
sp.UpdateText(fmt.Sprintf("%d records complete...", n))
}

return nil
},
err = m.Start(ctx, migration, cb)
if err != nil {
sp.Fail(fmt.Sprintf("Failed to start migration: %s", err))
return err
}

startCmd.Flags().BoolVarP(&complete, "complete", "c", false, "Mark the migration as complete")
if complete {
if err = m.Complete(ctx); err != nil {
sp.Fail(fmt.Sprintf("Failed to complete migration: %s", err))
return err
}
}

return startCmd
version := migration.Name
if version == "" {
version = strings.TrimSuffix(filepath.Base(fileName), filepath.Ext(fileName))
}
viewName := roll.VersionedSchemaName(flags.Schema(), version)
msg := fmt.Sprintf("New version of the schema available under the postgres %q schema", viewName)
sp.Success(msg)

return nil
}

0 comments on commit 7130506

Please sign in to comment.