diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a98f04..c26b00a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,19 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## Unreleased +## [5.1.0](https://github.com/elwinar/rambler/releases/tag/5.1.0) - 2019-08-28 +### Added +- `dru-run` flag ## [5.0.0](https://github.com/elwinar/rambler/releases/tag/5.0.0) - 2019-05-26 ### Added - PostgreSQL support for schemas ### Changed - It is no longer an error if no configuration file is provided as option and - the default one doesn't exists. + the default one doesn't exists ### Internal - Split the general configuration and the driver configuration to allow a - better structure. + better structure ## [4.2.1](https://github.com/elwinar/rambler/releases/tag/4.2.1) - 2018-08-09 ### Fixed @@ -51,7 +53,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [4.0.0](https://github.com/elwinar/rambler/releases/tag/4.0.0) - 2016-10-30 ### Added -- MySQL driver now use the migration name as primary key (necessary for Percona XtraDB clusters) +- MySQL driver now use the migration name as primary key (necessary for Percona + XtraDB clusters) ## [3.4.0](https://github.com/elwinar/rambler/releases/tag/v3.4.0) - 2016-10-27 ### Added @@ -97,7 +100,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Removed - The command-line options to override the configuration -- Possibility of using alternatives configuration file types (namely YAML and TOML) +- Possibility of using alternatives configuration file types (namely YAML and + TOML) ### Fixed - Behavior of the transactions diff --git a/README.md b/README.md index 82c6976..3a6d0e2 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,10 @@ Rambler will log a few important informations for monitoring what is happening on stdout. If you suspect something of being wrong, you can also use the debug mode by adding `--debug` to your command line. +### Dry-run + +The `--dry-run` flag will print statements instead of executing them. + ## CONTRIBUTORS - [cjhubert](https://github.com/cjhubert) diff --git a/bootstrap.go b/bootstrap.go index 484454e..87e9ec6 100644 --- a/bootstrap.go +++ b/bootstrap.go @@ -12,10 +12,10 @@ import ( // Bootstrap do the initialization job, and finish by setting the // `service` global var that will be used by other commands. func Bootstrap(ctx *cli.Context) error { - return bootstrap(ctx.GlobalString("configuration"), ctx.GlobalString("environment"), ctx.GlobalBool("debug")) + return bootstrap(ctx.GlobalString("configuration"), ctx.GlobalString("environment"), ctx.GlobalBool("debug"), ctx.GlobalBool("dry-run")) } -func bootstrap(configuration, environment string, debug bool) (err error) { +func bootstrap(configuration, environment string, debug, dryRun bool) (err error) { logger = log.NewLogger(func(l *log.Logger) { l.PrintDebug = debug }) @@ -42,7 +42,7 @@ func bootstrap(configuration, environment string, debug bool) (err error) { } logger.Debug("initializing service") - service, err = NewService(env) + service, err = NewService(env, dryRun) if err != nil { return fmt.Errorf("unable to initialize the migration service: %s", err) } diff --git a/bootstrap_test.go b/bootstrap_test.go index 05f21c1..dc10c10 100644 --- a/bootstrap_test.go +++ b/bootstrap_test.go @@ -41,7 +41,7 @@ func TestBootstrap(t *testing.T) { service = nil logger = nil - err := bootstrap(c.configuration, c.environment, false) + err := bootstrap(c.configuration, c.environment, false, false) if (err != nil) != c.err { t.Error("case", n, "got unexpected error:", err) continue diff --git a/main.go b/main.go index 0d51ef6..e993705 100644 --- a/main.go +++ b/main.go @@ -48,6 +48,10 @@ func main() { Name: "debug", Usage: "display debug messages", }, + cli.BoolFlag{ + Name: "dry-run", + Usage: "don't execute any statement, only display them", + }, } app.Before = Bootstrap diff --git a/service.go b/service.go index 5e73589..4752163 100644 --- a/service.go +++ b/service.go @@ -21,12 +21,13 @@ var ( // Service is the struct that gather operations to manipulate the // database and migrations on disk type Service struct { - conn driver.Conn - env Environment + conn driver.Conn + env Environment + dryRun bool } // NewService initialize a new service with the given environment -func NewService(env Environment) (*Service, error) { +func NewService(env Environment, dryRun bool) (*Service, error) { fi, err := os.Stat(env.Directory) if err != nil { return nil, fmt.Errorf("directory %s unavailable: %s", env.Directory, err.Error()) @@ -47,8 +48,9 @@ func NewService(env Environment) (*Service, error) { } return &Service{ - conn: conn, - env: env, + conn: conn, + env: env, + dryRun: dryRun, }, nil } @@ -118,12 +120,21 @@ func (s Service) Apply(migration *Migration) error { } for _, statement := range migration.Up() { + if s.dryRun { + logger.Info("statement: %s", statement) + continue + } + err := s.conn.Execute(statement) if err != nil { return fmt.Errorf("unable to apply migration %s: %s\n%s", migration.Name, err, statement) } } + if s.dryRun { + return nil + } + err := s.conn.AddApplied(migration.Name) if err != nil { return fmt.Errorf("unable to mark migration %s as applied: %s", migration.Name, err) @@ -140,12 +151,21 @@ func (s Service) Reverse(migration *Migration) error { } for _, statement := range migration.Down() { + if s.dryRun { + logger.Info("statement: %s", statement) + continue + } + err := s.conn.Execute(statement) if err != nil { return fmt.Errorf("unable to reverse migration %s: %s\n%s", migration.Name, err, statement) } } + if s.dryRun { + return nil + } + err := s.conn.RemoveApplied(migration.Name) if err != nil { return fmt.Errorf("unable to mark migration %s as not applied: %s", migration.Name, err) diff --git a/service_test.go b/service_test.go index 3f92b4d..f14494d 100644 --- a/service_test.go +++ b/service_test.go @@ -43,7 +43,7 @@ func TestNewService(t *testing.T) { } for n, c := range cases { - _, err := NewService(c.input) + _, err := NewService(c.input, false) if (err != nil) != c.err { t.Error("case", n, "got unexpected error:", err) }