Goose is a database migration tool. Manage your database schema by creating incremental SQL changes or Go functions.
github.com/grailbio-external/goose
is a fork of github.com/pressly/goose
with the following changes:
- Adds an
-include-missing
flag to anygoose up
-related command (which includesup
,up-to
, orup-by-one
). This flag applies missing migrations. - Adds a
-show-unapplied-only
flag togoose status
, which shows only migrations that have not been applied (either ones that have been skipped or normal future migrations). - Adds a
-dry-run
flag to anygoose up
-related command that lists the migrations that will be applied without applying them. - Adds a fatal error when any
goose up
-related command is called but there are missing migrations. - Updates
goose status
to show the message(SKIPPED)
next to migrations that were missed. - Updates migration error messages to show the filename of the migration where the error occurred.
- Updates messages and errors to be more consistently formatted.
$ go get -u github.com/grailbio-external/goose/cmd/goose
This will install the goose
binary to your $GOPATH/bin
directory.
For a lite version of the binary without DB connection dependent commands, use the exclusive build tags:
$ go build -tags='no_mysql no_sqlite no_psql' -i -o goose ./cmd/goose
Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
Drivers:
postgres
mysql
sqlite3
redshift
Commands:
up Migrate the DB to the most recent version available. Use [-include-missing] to include migrations that were missed and [-dry-run] to see which migrations the command would apply without actually applying them
up-by-one Migrate up by a single version
up-to VERSION Migrate the DB to a specific VERSION. Use [-include-missing] to include migrations that were missed and [-dry-run] to see which migrations the command would apply without actually applying them
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. Use [-show-unapplied-only] option to show only migrations that were not applied
version Print the current version of the database
create NAME [sql|go] Creates new migration file with the current timestamp
Options:
-dir string
directory with migration files (default ".")
-show-unapplied-only
for status command - show only migrations that were not applied
-include-missing
for up or up-to command - include migrations that were missed
-dry-run
for up, up-to, or up-by-one command - prints out the migrations it would apply and exits before applying them
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?parseTime=true" status
goose redshift "postgres://user:[email protected]:5439/db" status
goose tidb "user:password@/dbname?parseTime=true" status
Create a new SQL migration.
$ goose create add_some_column sql
$ Created new file: 20170506082420_add_some_column.sql
Edit the newly created file to define the behavior of your migration.
You can also create a Go migration, if you then invoke it with your own goose binary:
$ goose create fetch_user_data go
$ Created new file: 20170506082421_fetch_user_data.go
Apply all available migrations.
$ goose up
$ goose: migrating db environment 'development', current version: 0, target: 3
$ OK 001_basics.sql
$ OK 002_next.sql
$ OK 003_and_again.go
Migrate up to a specific version.
$ goose up-to 20170506082420
$ OK 20170506082420_create_table.sql
Roll back a single migration from the current version.
$ goose down
$ goose: migrating db environment 'development', current version: 3, target: 2
$ OK 003_and_again.go
Roll back migrations to a specific version.
$ goose down-to 20170506082527
$ OK 20170506082527_alter_column.sql
Roll back the most recently applied migration, then run it again.
$ goose redo
$ goose: migrating db environment 'development', current version: 3, target: 2
$ OK 003_and_again.go
$ goose: migrating db environment 'development', current version: 2, target: 3
$ OK 003_and_again.go
Print the status of all migrations:
$ goose status
$ goose: status for environment 'development'
$ Applied At Migration
$ =======================================
$ Sun Jan 6 11:25:03 2013 -- 001_basics.sql
$ Sun Jan 6 11:25:03 2013 -- 002_next.sql
$ Pending -- 003_and_again.go
Note: for MySQL parseTime flag must be enabled.
Print the current version of the database:
$ goose version
$ goose: version 002
goose supports migrations written in SQL or in Go.
A sample SQL migration looks like:
-- +goose Up
CREATE TABLE post (
id int NOT NULL,
title text,
body text,
PRIMARY KEY(id)
);
-- +goose Down
DROP TABLE post;
Notice the annotations in the comments. Any statements following -- +goose Up
will be executed as part of a forward migration, and any statements following -- +goose Down
will be executed as part of a rollback.
By default, all migrations are run within a transaction. Some statements like CREATE DATABASE
, however, cannot be run within a transaction. You may optionally add -- +goose NO TRANSACTION
to the top of your migration
file in order to skip transactions within that specific migration file. Both Up and Down migrations within this file will be run without transactions.
By default, SQL statements are delimited by semicolons - in fact, query statements must end with a semicolon to be properly recognized by goose.
More complex statements (PL/pgSQL) that have semicolons within them must be annotated with -- +goose StatementBegin
and -- +goose StatementEnd
to be properly recognized. For example:
-- +goose Up
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
returns void AS $$
DECLARE
create_query text;
BEGIN
FOR create_query IN SELECT
'CREATE TABLE IF NOT EXISTS histories_'
|| TO_CHAR( d, 'YYYY_MM' )
|| ' ( CHECK( created_at >= timestamp '''
|| TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
|| ''' AND created_at < timestamp '''
|| TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
|| ''' ) ) inherits ( histories );'
FROM generate_series( $1, $2, '1 month' ) AS d
LOOP
EXECUTE create_query;
END LOOP; -- LOOP END
END; -- FUNCTION END
$$
language plpgsql;
-- +goose StatementEnd
- Create your own goose binary, see example
- Import
github.com/grailbio-external/goose
- Register your migration functions
- Run goose command, ie.
goose.Up(db *sql.DB, dir string)
A sample Go migration 00002_users_add_email.go file looks like:
package migrations
import (
"database/sql"
"github.com/grailbio-external/goose"
)
func init() {
goose.AddMigration(Up, Down)
}
func Up(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
if err != nil {
return err
}
return nil
}
func Down(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
if err != nil {
return err
}
return nil
}
Please, read the versioning problem first.
We strongly recommend adopting a hybrid versioning approach, using both timestamps and sequential numbers. Migrations created during the development process are timestamped and sequential versions are ran on production. We believe this method will prevent the problem of conflicting versions when writing software in a team environment.
To help you adopt this approach, create
will use the current timestamp as the migration version. When you're ready to deploy your migrations in a production environment, we also provide a helpful fix
command to convert your migrations into sequential order, while preserving the timestamp ordering. We recommend running fix
in the CI pipeline, and only when the migrations are ready for production.
Licensed under MIT License