Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing migrations handling. BMP-596 #72

Closed
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,12 @@
cmd/goose/goose*
*.swp
*.test

# IDE
.vscode/
*.iml
.idea

# Mac
.DS_Store

38 changes: 12 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,12 @@ Goose is a database migration tool. Manage your database schema by creating incr

### Goals of this fork

`github.com/pressly/goose` is a fork of `bitbucket.org/liamstask/goose` with the following changes:
- No config files
- [Default goose binary](./cmd/goose/main.go) can migrate SQL files only
- Go migrations:
- We don't `go build` Go migrations functions on-the-fly
from within the goose binary
- Instead, we let you
[create your own custom goose binary](examples/go-migrations),
register your Go migration functions explicitly and run complex
migrations with your own `*sql.DB` connection
- Go migration functions let you run your code within
an SQL transaction, if you use the `*sql.Tx` argument
- The goose pkg is decoupled from the binary:
- goose pkg doesn't register any SQL drivers anymore,
thus no driver `panic()` conflict within your codebase!
- goose pkg doesn't have any vendor dependencies anymore
- We encourage using sequential versioning of migration files
(rather than timestamps-based versioning) to prevent version
mismatch and migration colissions
`github.com/mc2soft/goose` is a fork of `github.com/pressly/goose` with the following changes:
- Applying all missing migrations, regardless of latest migration version.

# Install

$ go get -u github.com/pressly/goose/cmd/goose
$ go get -u github.com/mc2soft/goose/cmd/goose
Copy link
Collaborator

@VojtechVitek VojtechVitek Oct 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't expect us to merge this change github.com/mc2soft/goose, do you? :)

Can you iron this PR out and provide a high-level overview of what is this PR supposed to solve? Thanks!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR resolves #73. Ok, i will iron it to avoid "mc2soft" mentions)) But pls give me feedback, do you consider such issue?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So in the high-level, this would find all the missing migrations -- ie. all migrations that are available but were not applied in the DB, right?

You can

  1. list them
  2. apply them

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, with new commands:

  1. status-missing
  2. up-missing

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, do we need 1. at all? Can't goose status show these migrations as well by default?

Imho, 2. is explicit enough. I like it. It might even help people who insist on using Timestamp based migrations #63.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status show all migrations (could be a lot of them!), including missing ("pending"). But the new status-missing shows only missing migrations.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like someone from #63 to test this feature. I don't really have the same use case. Can you ping these guys, once you have the PR ready?


This will install the `goose` binary to your `$GOPATH/bin` directory.

Expand All @@ -46,10 +29,13 @@ Drivers:
Commands:
up Migrate the DB to the most recent version available
up-to VERSION Migrate the DB to a specific VERSION
up-missing Migrate only missing migrations
Warning! Do not use any other up* commands after this!
down Roll back the version by 1
down-to VERSION Roll back to a specific VERSION
redo Re-run the latest migration
status Dump the migration status for the current DB
status-missing Find out all migrations, missing from the current DB
version Print the current version of the database
create NAME [sql|go] Creates new migration file with next version

Expand Down Expand Up @@ -204,7 +190,7 @@ language plpgsql;
## Go Migrations

1. Create your own goose binary, see [example](./examples/go-migrations)
2. Import `github.com/pressly/goose`
2. Import `github.com/mc2soft/goose`
3. Register your migration functions
4. Run goose command, ie. `goose.Up(db *sql.DB, dir string)`

Expand All @@ -216,7 +202,7 @@ package migrations
import (
"database/sql"

"github.com/pressly/goose"
"github.com/mc2soft/goose"
)

func init() {
Expand Down Expand Up @@ -244,7 +230,7 @@ func Down(tx *sql.Tx) error {

Licensed under [MIT License](./LICENSE)

[GoDoc]: https://godoc.org/github.com/pressly/goose
[GoDoc Widget]: https://godoc.org/github.com/pressly/goose?status.svg
[Travis]: https://travis-ci.org/pressly/goose
[Travis Widget]: https://travis-ci.org/pressly/goose.svg?branch=master
[GoDoc]: https://godoc.org/github.com/mc2soft/goose
[GoDoc Widget]: https://godoc.org/github.com/mc2soft/goose?status.svg
[Travis]: https://travis-ci.org/mc2soft/goose
[Travis Widget]: https://travis-ci.org/mc2soft/goose.svg?branch=master
2 changes: 1 addition & 1 deletion cmd/goose/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"log"
"os"

"github.com/pressly/goose"
"github.com/mc2soft/goose"

// Init DB drivers.
_ "github.com/go-sql-driver/mysql"
Expand Down
2 changes: 1 addition & 1 deletion create.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ var goSQLMigrationTemplate = template.Must(template.New("goose.go-migration").Pa

import (
"database/sql"
"github.com/pressly/goose"
"github.com/mc2soft/goose"
)

func init() {
Expand Down
16 changes: 16 additions & 0 deletions examples/go-migrations-package/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SQL + Go migrations

## This example: Best practice: Split migrations into a standalone package

```bash
$ go run main.go -dir ./db/migrations sqlite3 ./db/foo.db up-missing
OK 00001_create_users_table.sql
OK 00002_rename_root.go
OK 00004_rename_admin.go
```
Remove "_" at _00003 and _00005 migrations, migrate again:
```bash
$ go run main.go -dir ./db/migrations sqlite3 ./db/foo.db up-missing
OK 00003_rename_admin.go
OK 00005_rename_admin.go
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- +goose NO TRANSACTION
-- +goose Up
CREATE TABLE users (
id int NOT NULL PRIMARY KEY,
username text,
name text,
surname text
);

INSERT INTO users VALUES
(0, 'root', '', ''),
(1, 'stepych', 'Stepan', 'Bayburtyan');

-- +goose Down
DROP TABLE users;
27 changes: 27 additions & 0 deletions examples/go-migrations-package/db/migrations/00002_rename_root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package migrations

import (
"database/sql"

"github.com/mc2soft/goose"
)

func init() {
goose.AddMigration(Up00002, Down00002)
}

func Up00002(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
if err != nil {
return err
}
return nil
}

func Down00002(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
if err != nil {
return err
}
return nil
}
27 changes: 27 additions & 0 deletions examples/go-migrations-package/db/migrations/00004_rename_admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package migrations

import (
"database/sql"

"github.com/mc2soft/goose"
)

func init() {
goose.AddMigration(Up00004, Down00004)
}

func Up00004(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin4' WHERE username='admin';")
if err != nil {
return err
}
return nil
}

func Down00004(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='admin4';")
if err != nil {
return err
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package migrations

import (
"database/sql"

"github.com/mc2soft/goose"
)

func init() {
goose.AddMigration(Up00003, Down00003)
}

func Up00003(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin3' WHERE username='admin4';")
if err != nil {
return err
}
return nil
}

func Down00003(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin4' WHERE username='admin3';")
if err != nil {
return err
}
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package migrations

import (
"database/sql"

"github.com/mc2soft/goose"
)

func init() {
goose.AddMigration(Up00005, Down00005)
}

func Up00005(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin5' WHERE username='admin3';")
if err != nil {
return err
}
return nil
}

func Down00005(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin3' WHERE username='admin5';")
if err != nil {
return err
}
return nil
}
Binary file not shown.
126 changes: 126 additions & 0 deletions examples/go-migrations-package/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package main

import (
"database/sql"
"flag"
"fmt"
"log"
"os"

"github.com/mc2soft/goose"

// Init all Go migrations
_ "github.com/mc2soft/goose/examples/go-migrations-package/db/migrations"

// Init DB drivers.
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
_ "github.com/ziutek/mymysql/godrv"
)

var (
flags = flag.NewFlagSet("goose", flag.ExitOnError)
dir = flags.String("dir", ".", "directory with migration files")
)

func main() {
flags.Usage = usage
flags.Parse(os.Args[1:])

args := flags.Args()

if len(args) > 1 && args[0] == "create" {
if err := goose.Run("create", nil, *dir, args[1:]...); err != nil {
log.Fatalf("goose run: %v", err)
}
return
}

if len(args) < 3 {
flags.Usage()
return
}

if args[0] == "-h" || args[0] == "--help" {
flags.Usage()
return
}

driver, dbstring, command := args[0], args[1], args[2]

switch driver {
case "postgres", "mysql", "sqlite3", "redshift":
if err := goose.SetDialect(driver); err != nil {
log.Fatal(err)
}
default:
log.Fatalf("%q driver not supported\n", driver)
}

switch dbstring {
case "":
log.Fatalf("-dbstring=%q not supported\n", dbstring)
default:
}

if driver == "redshift" {
driver = "postgres"
}

db, err := sql.Open(driver, dbstring)
if err != nil {
log.Fatalf("-dbstring=%q: %v\n", dbstring, err)
}

arguments := []string{}
if len(args) > 3 {
arguments = append(arguments, args[3:]...)
}

if err := goose.Run(command, db, *dir, arguments...); err != nil {
log.Fatalf("goose run: %v", err)
}
}

func usage() {
fmt.Print(usagePrefix)
flags.PrintDefaults()
fmt.Print(usageCommands)
}

var (
usagePrefix = `Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND

Drivers:
postgres
mysql
sqlite3
redshift

Examples:
goose sqlite3 ./foo.db status
goose sqlite3 ./foo.db create init sql
goose sqlite3 ./foo.db create add_some_column sql
goose sqlite3 ./foo.db create fetch_user_data go
goose sqlite3 ./foo.db up

goose postgres "user=postgres dbname=postgres sslmode=disable" status
goose mysql "user:password@/dbname" status
goose redshift "postgres://user:[email protected]:5439/db" status

Options:
`

usageCommands = `
Commands:
up Migrate the DB to the most recent version available
up-to VERSION Migrate the DB to a specific VERSION
down Roll back the version by 1
down-to VERSION Roll back to a specific VERSION
redo Re-run the latest migration
status Dump the migration status for the current DB
version Print the current version of the database
create NAME [sql|go] Creates new migration file with next version
`
)
2 changes: 1 addition & 1 deletion examples/go-migrations/00002_rename_root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"database/sql"

"github.com/pressly/goose"
"github.com/mc2soft/goose"
)

func init() {
Expand Down
2 changes: 1 addition & 1 deletion examples/go-migrations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ $
```go
import (
// Invoke init() functions within migrations pkg.
_ "github.com/pressly/goose/example/migrations-go"
_ "github.com/mc2soft/goose/example/migrations-go"
)
```
Binary file removed examples/go-migrations/goose
Binary file not shown.
Loading