Skip to content

Commit

Permalink
overhaul error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
tlhunter committed Jan 7, 2023
1 parent 434bf74 commit 8b6300d
Show file tree
Hide file tree
Showing 15 changed files with 201 additions and 221 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

`mig` isn't yet ready for production. When it is `mig` will hit version 1.0. Some of the required tasks to reach this include:

- [ ] document all exit status codes, ensure all errors return non-zero
- [ ] unit test everything
- [ ] add support for sqlite
- [ ] support JSON output via `--json`
Expand Down
45 changes: 19 additions & 26 deletions commands/all.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package commands

import (
"os"
"errors"

"github.com/fatih/color"

Expand All @@ -11,40 +11,38 @@ import (
)

func CommandAll(cfg config.MigConfig) error {
dbox := database.Connect(cfg.Connection)
dbox, err := database.Connect(cfg.Connection)

if err != nil {
return err
}

defer dbox.Db.Close()

// First call to GetStatus is mostly unused. if it fails then don't continue.
status, err := migrations.GetStatus(cfg, dbox)

if err != nil {
color.Red("Encountered an error trying to get migrations status!\n")
os.Stderr.WriteString(err.Error() + "\n")
return err
return errors.New("Encountered an error trying to get migrations status!")
}

if status.Skipped > 0 {
color.Red("Refusing to run with skipped migrations! Run `mig status` for details.\n")
return nil
return errors.New("Refusing to run with skipped migrations! Run `mig status` for details.")
}

if status.Next == "" {
color.Red("There are no migrations to run.")
return nil
return errors.New("There are no migrations to run.")
}

locked, err := database.ObtainLock(dbox)

if err != nil {
color.Red("Error obtaining lock for running migrations!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Error obtaining lock for running migrations!")
return err
}

if !locked {
color.Red("Unable to obtain lock for running migrations!\n")
return nil
return errors.New("Unable to obtain lock for running migrations!")
}

highest, err := migrations.GetHighestValues(dbox)
Expand All @@ -66,8 +64,7 @@ func CommandAll(cfg config.MigConfig) error {
queries, err := migrations.GetQueriesFromFile(filename)

if err != nil {
color.Red("Error attempting to read next migration file!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Error attempting to read next migration file!")
return err
}

Expand All @@ -82,35 +79,31 @@ func CommandAll(cfg config.MigConfig) error {
_, err = dbox.Db.Exec(query)

if err != nil {
color.Red("Encountered an error while running migration!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Encountered an error while running migration!")
return err
}

color.Green("Migration %s was successfully applied!\n", next)
color.Green("Migration %s was successfully applied!", next)

err = migrations.AddMigrationWithBatch(dbox, next, batchId)

if err != nil {
color.Red("The migration query executed but unable to track it in the migrations table!\n")
color.White("You may want to manually add it and investigate the error.\n")
color.White("Any remaining migrations will not be executed!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("The migration query executed but unable to track it in the migrations table!")
color.White("You may want to manually add it and investigate the error.")
color.White("Any remaining migrations will not be executed!")
return err
}
}

released, err := database.ReleaseLock(dbox)

if err != nil {
color.Red("Error releasing lock for migration!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Error releasing lock for migration!")
return err
}

if !released {
color.Red("Unable to release lock for migration!\n")
return nil
return errors.New("Unable to release lock for migration!")
}

return nil
Expand Down
2 changes: 2 additions & 0 deletions commands/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ func CommandCreate(cfg config.MigConfig, name string) error {

file, err := os.Create(filePath)
if err != nil {
color.Red("Unable to create migration file!")
return err
}

defer file.Close()

_, err = file.WriteString(TEMPLATE)
if err != nil {
color.Red("Unable to write to migration file!")
return err
}

Expand Down
48 changes: 24 additions & 24 deletions commands/dispatch.go
Original file line number Diff line number Diff line change
@@ -1,66 +1,66 @@
package commands

import (
"os"
"errors"
"fmt"

"github.com/fatih/color"
"github.com/tlhunter/mig/config"
)

func Dispatch(cfg config.MigConfig, subcommands []string) {
func Dispatch(cfg config.MigConfig, subcommands []string) error {
var err error
if len(subcommands) == 0 {
color.White("usage: mig <command>")
os.Exit(10)
err = errors.New("usage: mig <command>")
}

switch subcommands[0] {
case "create":
if len(subcommands) >= 2 {
CommandCreate(cfg, subcommands[1])
return
err = CommandCreate(cfg, subcommands[1])
} else {
err = errors.New("usage: mig create \"<migration name>\"")
}
color.White("usage: mig create \"<migration name>\"")
os.Exit(10)

case "init":
CommandInit(cfg)
err = CommandInit(cfg)

case "lock":
CommandLock(cfg)
err = CommandLock(cfg)

case "unlock":
CommandUnlock(cfg)
err = CommandUnlock(cfg)

case "list":
fallthrough
case "ls":
CommandList(cfg)
err = CommandList(cfg)

case "status":
CommandStatus(cfg)
err = CommandStatus(cfg)

case "up":
CommandUp(cfg)
err = CommandUp(cfg)

case "down":
CommandDown(cfg)
err = CommandDown(cfg)

case "all":
CommandAll(cfg)
err = CommandAll(cfg)

case "upto":
if len(subcommands) >= 2 {
CommandUpto(cfg, subcommands[1])
return
err = CommandUpto(cfg, subcommands[1])
} else {
err = errors.New("usage: mig upto \"<migration name>\"")
}
color.White("usage: mig upto \"<migration name>\"")
os.Exit(10)

case "version":
CommandVersion(cfg)
err = CommandVersion(cfg)

default:
color.White("unsupported command %s", subcommands[0])
os.Exit(10)
err = errors.New(fmt.Sprintf("unsupported command %s", subcommands[0]))
}

return err

}
40 changes: 18 additions & 22 deletions commands/down.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package commands

import (
"os"
"errors"

"github.com/fatih/color"
"github.com/tlhunter/mig/config"
Expand All @@ -10,15 +10,18 @@ import (
)

func CommandDown(cfg config.MigConfig) error {
dbox := database.Connect(cfg.Connection)
dbox, err := database.Connect(cfg.Connection)

if err != nil {
return err
}

defer dbox.Db.Close()

status, err := migrations.GetStatus(cfg, dbox)

if err != nil {
color.Red("Encountered an error trying to get migrations status!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Encountered an error trying to get migrations status!")
return err
}

Expand All @@ -29,24 +32,21 @@ func CommandDown(cfg config.MigConfig) error {
queries, err := migrations.GetQueriesFromFile(filename)

if err != nil {
color.Red("Error attempting to read last migration file!\n")
color.White("Normally a missing migration file isn't a big deal but it's a no go for migrating down.\n")
color.White("This file is required before continuing. Perhaps it can be pulled from version control?\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Error attempting to read last migration file!")
color.White("Normally a missing migration file isn't a big deal but it's a no go for migrating down.")
color.White("This file is required before continuing. Perhaps it can be pulled from version control?")
return err
}

locked, err := database.ObtainLock(dbox)

if err != nil {
color.Red("Error obtaining lock for migrating down!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Error obtaining lock for migrating down!")
return err
}

if !locked {
color.Red("Unable to obtain lock for migrating down!\n")
return nil
return errors.New("Unable to obtain lock for migrating down!")
}

var query string
Expand All @@ -60,33 +60,29 @@ func CommandDown(cfg config.MigConfig) error {
_, err = dbox.Db.Exec(query)

if err != nil {
color.Red("Encountered an error while running down migration!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Encountered an error while running down migration!")
return err
}

color.Green("Migration down %s was successfully applied!\n", last.Name)
color.Green("Migration down %s was successfully applied!", last.Name)

err = migrations.RemoveMigration(dbox, last.Name, last.Id)

if err != nil {
color.Red("The migration down query executed but unable to track it in the migrations table!\n")
color.White("You may want to manually remove it and investigate the error.\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("The migration down query executed but unable to track it in the migrations table!")
color.White("You may want to manually remove it and investigate the error.")
return err
}

released, err := database.ReleaseLock(dbox)

if err != nil {
color.Red("Error obtaining lock for down migration!\n")
os.Stderr.WriteString(err.Error() + "\n")
color.Red("Error obtaining lock for down migration!")
return err
}

if !released {
color.Red("Unable to obtain lock for down migration!\n")
return nil
return errors.New("Unable to obtain lock for down migration!")
}

return nil
Expand Down
10 changes: 7 additions & 3 deletions commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ INSERT INTO migrations_lock SET ` + "`index`" + ` = 1, is_locked = 0;`,
)

func CommandInit(cfg config.MigConfig) error {
dbox := database.Connect(cfg.Connection)
dbox, err := database.Connect(cfg.Connection)

if err != nil {
return err
}

defer dbox.Db.Close()

_, err := dbox.Exec(INIT)
_, err = dbox.Exec(INIT)

if err != nil {
color.Red("error initializing mig!", err)
color.Red("error initializing mig!")
return err
}

Expand Down
17 changes: 11 additions & 6 deletions commands/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import (
)

func CommandList(cfg config.MigConfig) error {
dbox := database.Connect(cfg.Connection)
dbox, err := database.Connect(cfg.Connection)

if err != nil {
return err
}

defer dbox.Db.Close()

status, err := migrations.GetStatus(cfg, dbox)
Expand All @@ -20,18 +25,18 @@ func CommandList(cfg config.MigConfig) error {
return err
}

color.White("%5s %-48s %5s %-20s %-20s\n", "ID", "Migration", "Batch", "Time of Run", "Note")
color.White("%5s %-48s %5s %-20s %-20s", "ID", "Migration", "Batch", "Time of Run", "Note")

for _, entry := range status.History {
switch entry.Status {
case "applied":
color.Green("%5d %-48s %5d %20s %-20s\n", entry.Migration.Id, entry.Migration.Name, entry.Migration.Batch, entry.Migration.Time.Format(time.RFC3339), "Applied")
color.Green("%5d %-48s %5d %20s %-20s", entry.Migration.Id, entry.Migration.Name, entry.Migration.Batch, entry.Migration.Time.Format(time.RFC3339), "Applied")
case "skipped":
color.Red("%5s %-48s %5s %20s %-20s\n", "", entry.Migration.Name, "", "", "Migration Skipped!")
color.Red("%5s %-48s %5s %20s %-20s", "", entry.Migration.Name, "", "", "Migration Skipped!")
case "missing":
color.Yellow("%5d %-48s %5d %20s %-20s\n", entry.Migration.Id, entry.Migration.Name, entry.Migration.Batch, entry.Migration.Time.Format(time.RFC3339), "Missing File!")
color.Yellow("%5d %-48s %5d %20s %-20s", entry.Migration.Id, entry.Migration.Name, entry.Migration.Batch, entry.Migration.Time.Format(time.RFC3339), "Missing File!")
case "unapplied":
color.Cyan("%5s %-48s %5s %20s %-20s\n", "", entry.Migration.Name, "", "", "Ready to Run")
color.Cyan("%5s %-48s %5s %20s %-20s", "", entry.Migration.Name, "", "", "Ready to Run")
}
}

Expand Down
Loading

0 comments on commit 8b6300d

Please sign in to comment.