Skip to content

Commit

Permalink
[Feature] Pass migrations directory by flag (#17)
Browse files Browse the repository at this point in the history
Changed the way migrations directory is passed - now passed by flag.
Renamed validate and generate command's variables with names folderName to dir.
Updated readme.
  • Loading branch information
atedesch1 authored May 18, 2022
1 parent d3a9713 commit bc67cfe
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 44 deletions.
34 changes: 23 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

An agnostic tool that abstracts migration operations

### Suported databases
- **postgres**
- **mysql**

## How to use

### Requirements
Expand All @@ -23,20 +27,24 @@ make build

### Run commands

#### Set needed variables

- **database**: Database URL. <br/>
Set through `DB_HOST` environment variable or by using command flag `--database`.

- **driver**: Driver name. <br/>
Defaults to **postgres**. <br/>
Set through command flag `--driver`.

- **dir**: Migrations directory. <br/>
Set through command flag `--dir`.
### Execute migrations

Execute migrations by running
```bash
./bin/mgr8 <migrations_folder> <driver>
./bin/mgr8 apply <up|down>
```
Currently supported drivers: **postgres** and **mysql**.
<br/>
Defaults to **postgres**.
<br/>
Make sure you either have `DB_HOST` environment variable with you database connection string or you pass it in by using the flag `--database`.
<br/>
Example connection string: `postgres://root:root@localhost:5432/database_name?sslmode=disable`

Needs: **database**, **dir**, **driver**
## Develop

### Requirements
Expand All @@ -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**.
<br/>
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`.
Expand All @@ -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
```

32 changes: 15 additions & 17 deletions cmd/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,21 @@ type MigrationFile struct {
}

type CommandArgs struct {
migrationFiles []MigrationFile
migrationType string
migrationType string
}

type Migrations struct {
files []MigrationFile
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
Expand All @@ -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
}
Expand All @@ -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")
}

Expand All @@ -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
}
Expand Down Expand Up @@ -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)
}
}
Expand Down
11 changes: 6 additions & 5 deletions cmd/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
5 changes: 4 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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)

Expand Down
12 changes: 6 additions & 6 deletions cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit bc67cfe

Please sign in to comment.