diff --git a/README.md b/README.md index 8142255..b13eb72 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ An agnostic tool that abstracts migration operations +### Suported databases +- **postgres** +- **mysql** + ## How to use ### Requirements @@ -23,20 +27,24 @@ make build ### Run commands +#### Set needed variables + +- **database**: Database URL.
+Set through `DB_HOST` environment variable or by using command flag `--database`. + +- **driver**: Driver name.
+Defaults to **postgres**.
+Set through command flag `--driver`. + +- **dir**: Migrations directory.
+Set through command flag `--dir`. ### Execute migrations Execute migrations by running ```bash -./bin/mgr8 +./bin/mgr8 apply ``` -Currently supported drivers: **postgres** and **mysql**. -
-Defaults to **postgres**. -
-Make sure you either have `DB_HOST` environment variable with you database connection string or you pass it in by using the flag `--database`. -
-Example connection string: `postgres://root:root@localhost:5432/database_name?sslmode=disable` - +Needs: **database**, **dir**, **driver** ## Develop ### Requirements @@ -54,6 +62,10 @@ Available databases: postgres, mysql Passing the `-d` flag is optional and will run the container in detached mode, it won't block the terminal but you won't see database logs nor be able to close the container by using ctrl+c. +Point to database by setting env **DB_HOST**. +
+For postgres use DB_HOST=`postgres://root:root@localhost:5432/database_name?sslmode=disable` + ### Testing Use `make test`, `make display-coverage` and `make coverage-report`. @@ -62,11 +74,11 @@ Use `make test`, `make display-coverage` and `make coverage-report`. Executing migrations with postgres driver ```bash -./bin/mgr8 apply --database=postgres://root:root@localhost:5432/core?sslmode=disable ./migrations +./bin/mgr8 apply up --database=postgres://root:root@localhost:5432/core?sslmode=disable --dir=./migrations ``` Executing migrations with mysql driver ```bash -./bin/mgr8 apply --database=root:root@tcp\(localhost:3306\)/core ./migrations mysql +./bin/mgr8 apply up --database=root:root@tcp\(localhost:3306\)/core --dir=./migrations --driver=mysql ``` diff --git a/cmd/apply.go b/cmd/apply.go index cdacc00..0ef5596 100644 --- a/cmd/apply.go +++ b/cmd/apply.go @@ -22,8 +22,7 @@ type MigrationFile struct { } type CommandArgs struct { - migrationFiles []MigrationFile - migrationType string + migrationType string } type Migrations struct { @@ -31,7 +30,13 @@ type Migrations struct { isUpType bool } -func (a *apply) execute(args []string, databaseURL string, driver domain.Driver) error { +func (a *apply) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error { + dir := migrationsDir + migrationFiles, err := getMigrationsFiles(dir) + if err != nil { + return err + } + commandArgs, err := parseArgs(args) if err != nil { return err @@ -43,7 +48,7 @@ func (a *apply) execute(args []string, databaseURL string, driver domain.Driver) return err } - migrationsToRun, err := getMigrationsToRun(commandArgs) + migrationsToRun, err := getMigrationsToRun(migrationFiles, commandArgs.migrationType) if err != nil { return err } @@ -64,7 +69,7 @@ func (a *apply) execute(args []string, databaseURL string, driver domain.Driver) func parseArgs(args []string) (CommandArgs, error) { var commandArgs CommandArgs - if len(args) < 2 { + if len(args) == 0 { return commandArgs, errors.New("arguments missing") } @@ -73,14 +78,7 @@ func parseArgs(args []string) (CommandArgs, error) { return commandArgs, errors.New("apply's first argument should be either up/down") } - dir := args[1] - migrationFiles, err := getMigrationsFiles(dir) - if err != nil { - return commandArgs, err - } - commandArgs.migrationType = migrationType - commandArgs.migrationFiles = migrationFiles return commandArgs, nil } @@ -131,19 +129,19 @@ func sortMigrationFiles(files []MigrationFile, isUpType bool) []MigrationFile { } // returns migrations files in folder that match type specified (up/down) -func getMigrationsToRun(args CommandArgs) (Migrations, error) { +func getMigrationsToRun(migrationFiles []MigrationFile, migrationType string) (Migrations, error) { var migrations Migrations - isUpType := args.migrationType == "up" + isUpType := migrationType == "up" var files []MigrationFile - for _, file := range args.migrationFiles { - migrationType, err := applications.GetMigrationType(file.name) + for _, file := range migrationFiles { + fileMigrationType, err := applications.GetMigrationType(file.name) if err != nil { return migrations, err } - if migrationType == args.migrationType { + if migrationType == fileMigrationType { files = append(files, file) } } diff --git a/cmd/command.go b/cmd/command.go index add36ae..c9f4724 100644 --- a/cmd/command.go +++ b/cmd/command.go @@ -12,13 +12,14 @@ import ( var defaultDriverName = string(drivers.Postgres) type CommandExecutor interface { - execute(args []string, databaseURL string, driver domain.Driver) error + execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error } type Command struct { - driverName string - databaseURL string - cmd CommandExecutor + driverName string + databaseURL string + migrationsDir string + cmd CommandExecutor } func (c *Command) Execute(cmd *cobra.Command, args []string) { @@ -29,7 +30,7 @@ func (c *Command) Execute(cmd *cobra.Command, args []string) { fmt.Printf("Driver %s started\n", c.driverName) - err = c.cmd.execute(args, c.databaseURL, driver) + err = c.cmd.execute(args, c.databaseURL, c.migrationsDir, driver) if err != nil { log.Fatal(err) } diff --git a/cmd/generate.go b/cmd/generate.go index 282d3d1..787f96d 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -9,11 +9,11 @@ import ( type generate struct{} -func (g *generate) execute(args []string, databaseURL string, driver domain.Driver) error { - fileName := args[0] - content, err := os.ReadFile(fileName) +func (g *generate) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error { + filePath := args[0] + content, err := os.ReadFile(filePath) if err != nil { - return fmt.Errorf("could not read from file: %s", err) + return fmt.Errorf("could not read from file with path: %s", err) } _, err = driver.ParseMigration(string(content)) diff --git a/cmd/root.go b/cmd/root.go index 1db7bae..9319929 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -25,16 +25,18 @@ func Execute() { } generateCmd.Flags().StringVar(&generateCommand.databaseURL, "database", os.Getenv("DB_HOST"), "Database URL") generateCmd.Flags().StringVar(&generateCommand.driverName, "driver", defaultDriverName, "Driver Name") + generateCmd.Flags().StringVar(&generateCommand.migrationsDir, "dir", "", "Migrations Directory") applyCommand := Command{cmd: &apply{}} applyCmd := &cobra.Command{ Use: "apply", Short: "apply runs migrations in the selected database", Run: applyCommand.Execute, - Args: cobra.MinimumNArgs(2), + Args: cobra.MinimumNArgs(1), } applyCmd.Flags().StringVar(&applyCommand.databaseURL, "database", os.Getenv("DB_HOST"), "Database URL") applyCmd.Flags().StringVar(&applyCommand.driverName, "driver", defaultDriverName, "Driver Name") + applyCmd.Flags().StringVar(&applyCommand.migrationsDir, "dir", "", "Migrations Directory") validateCommand := Command{cmd: &validate{}} validateCmd := &cobra.Command{ @@ -45,6 +47,7 @@ func Execute() { } validateCmd.Flags().StringVar(&validateCommand.databaseURL, "database", os.Getenv("DB_HOST"), "Database URL") validateCmd.Flags().StringVar(&validateCommand.driverName, "driver", defaultDriverName, "Driver Name") + validateCmd.Flags().StringVar(&validateCommand.migrationsDir, "dir", "", "Migrations Directory") rootCmd.AddCommand(applyCmd, generateCmd, validateCmd) diff --git a/cmd/validate.go b/cmd/validate.go index aa2278d..13fd618 100644 --- a/cmd/validate.go +++ b/cmd/validate.go @@ -11,29 +11,29 @@ import ( type validate struct{} -func (v *validate) execute(args []string, databaseURL string, driver domain.Driver) error { - folderName := args[0] +func (v *validate) execute(args []string, databaseURL string, migrationsDir string, driver domain.Driver) error { + dir := args[0] return driver.ExecuteTransaction(databaseURL, func() error { previousMigrationNumber, err := applications.GetPreviousMigrationNumber(driver) if err != nil { return err } - _, err = validateFolderMigrations(folderName, previousMigrationNumber, driver) + _, err = validateDirMigrations(dir, previousMigrationNumber, driver) return err }) } -func validateFolderMigrations(folderName string, previousMigrationNumber int, driver domain.Driver) (int, error) { - items, err := ioutil.ReadDir(folderName) +func validateDirMigrations(dir string, previousMigrationNumber int, driver domain.Driver) (int, error) { + items, err := ioutil.ReadDir(dir) if err != nil { return 0, err } for _, item := range items { fileName := item.Name() - fullName := path.Join(folderName, fileName) + fullName := path.Join(dir, fileName) version, err := applications.GetMigrationNumber(fileName) if err != nil {