Skip to content

Commit 7130506

Browse files
authored
New command: bootstrap (#414)
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
1 parent 7d88c25 commit 7130506

File tree

4 files changed

+94
-40
lines changed

4 files changed

+94
-40
lines changed

Makefile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ lint:
2020
examples:
2121
@go build
2222
@./pgroll init
23-
@for file in examples/*.json; do \
24-
if [ -f $$file ]; then \
25-
./pgroll start --complete $$file; \
26-
fi \
27-
done
23+
@./pgroll bootstrap examples
2824
@go clean
2925

3026
test:

cmd/bootstrap.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package cmd
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"path/filepath"
9+
"slices"
10+
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var bootstrapCmd = &cobra.Command{
15+
Use: "bootstrap <folder>",
16+
Short: "Bootstrap a new database from a directory of migration files",
17+
Long: `Bootstrap a new database from a directory of migration files. All files in the directory will be executed
18+
in lexicographical order. All migrations are completed.`,
19+
Args: cobra.ExactArgs(1),
20+
RunE: func(cmd *cobra.Command, args []string) error {
21+
migrationsDir := args[0]
22+
23+
m, err := NewRoll(cmd.Context())
24+
if err != nil {
25+
return err
26+
}
27+
defer m.Close()
28+
29+
// open folder and read all json files
30+
files, err := os.ReadDir(migrationsDir)
31+
if err != nil {
32+
return fmt.Errorf("reading migration directory: %w", err)
33+
}
34+
migrationFiles := []string{}
35+
for _, file := range files {
36+
if file.IsDir() || filepath.Ext(file.Name()) != ".json" {
37+
continue
38+
}
39+
migrationFiles = append(migrationFiles, filepath.Join(migrationsDir, file.Name()))
40+
}
41+
slices.Sort(migrationFiles)
42+
43+
for _, fileName := range migrationFiles {
44+
if err := runMigrationFromFile(cmd.Context(), m, fileName, true); err != nil {
45+
return fmt.Errorf("running migration file '%s': %w", fileName, err)
46+
}
47+
}
48+
49+
return nil
50+
},
51+
}

cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ func Execute() error {
7474
rootCmd.AddCommand(analyzeCmd)
7575
rootCmd.AddCommand(initCmd)
7676
rootCmd.AddCommand(statusCmd)
77+
rootCmd.AddCommand(bootstrapCmd)
7778

7879
return rootCmd.Execute()
7980
}

cmd/start.go

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

55
import (
6+
"context"
67
"fmt"
78
"os"
89
"path/filepath"
@@ -32,48 +33,53 @@ func startCmd() *cobra.Command {
3233
}
3334
defer m.Close()
3435

35-
file, err := os.Open(fileName)
36-
if err != nil {
37-
return fmt.Errorf("opening migration file: %w", err)
38-
}
39-
defer file.Close()
36+
return runMigrationFromFile(cmd.Context(), m, fileName, complete)
37+
},
38+
}
4039

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

46-
sp, _ := pterm.DefaultSpinner.WithText("Starting migration...").Start()
47-
cb := func(n int64) {
48-
sp.UpdateText(fmt.Sprintf("%d records complete...", n))
49-
}
42+
return startCmd
43+
}
5044

51-
err = m.Start(cmd.Context(), migration, cb)
52-
if err != nil {
53-
sp.Fail(fmt.Sprintf("Failed to start migration: %s", err))
54-
return err
55-
}
45+
func runMigrationFromFile(ctx context.Context, m *roll.Roll, fileName string, complete bool) error {
46+
file, err := os.Open(fileName)
47+
if err != nil {
48+
return fmt.Errorf("opening migration file: %w", err)
49+
}
5650

57-
if complete {
58-
if err = m.Complete(cmd.Context()); err != nil {
59-
sp.Fail(fmt.Sprintf("Failed to complete migration: %s", err))
60-
return err
61-
}
62-
}
51+
migration, err := migrations.ReadMigration(file)
52+
if err != nil {
53+
file.Close()
54+
return fmt.Errorf("reading migration file: %w", err)
55+
}
56+
file.Close()
6357

64-
version := migration.Name
65-
if version == "" {
66-
version = strings.TrimSuffix(filepath.Base(fileName), filepath.Ext(fileName))
67-
}
68-
viewName := roll.VersionedSchemaName(flags.Schema(), version)
69-
msg := fmt.Sprintf("New version of the schema available under the postgres %q schema", viewName)
70-
sp.Success(msg)
58+
sp, _ := pterm.DefaultSpinner.WithText("Starting migration...").Start()
59+
cb := func(n int64) {
60+
sp.UpdateText(fmt.Sprintf("%d records complete...", n))
61+
}
7162

72-
return nil
73-
},
63+
err = m.Start(ctx, migration, cb)
64+
if err != nil {
65+
sp.Fail(fmt.Sprintf("Failed to start migration: %s", err))
66+
return err
7467
}
7568

76-
startCmd.Flags().BoolVarP(&complete, "complete", "c", false, "Mark the migration as complete")
69+
if complete {
70+
if err = m.Complete(ctx); err != nil {
71+
sp.Fail(fmt.Sprintf("Failed to complete migration: %s", err))
72+
return err
73+
}
74+
}
7775

78-
return startCmd
76+
version := migration.Name
77+
if version == "" {
78+
version = strings.TrimSuffix(filepath.Base(fileName), filepath.Ext(fileName))
79+
}
80+
viewName := roll.VersionedSchemaName(flags.Schema(), version)
81+
msg := fmt.Sprintf("New version of the schema available under the postgres %q schema", viewName)
82+
sp.Success(msg)
83+
84+
return nil
7985
}

0 commit comments

Comments
 (0)