Skip to content
This repository was archived by the owner on Jun 28, 2018. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
ade683e
Fixes typos.
bfitzsimmons Nov 1, 2015
9694775
prefix migration files with epoch
dacamp Dec 16, 2015
10d8963
https://github.com/mattn/go-sqlite3 is cgo, so CGO_ENABLED must be true
raizyr Jan 10, 2016
90bab24
gocql doesn't support cassandra > 2.2
raizyr Jan 11, 2016
7f9f7e5
Release OS signals when you're finished with them.
uzimonkey Feb 12, 2016
91a3364
use a non-zero exit code when no command is given
jmhodges Apr 8, 2016
f230ced
typo fixed
meehow May 15, 2016
b5ef068
cassandra: add error checking for bad connection urls
cgilling Jun 12, 2016
907d8cd
Added driver for crate.io database
dereulenspiegel Jun 16, 2016
a7fa9eb
Added README.md for Crate driver
dereulenspiegel Jun 16, 2016
6612806
Crate driver was using wrong url scheme. The migrate CLI never had a …
dereulenspiegel Jun 16, 2016
cd5f75d
Splitting of sql is now more robust and better tested
dereulenspiegel Jun 16, 2016
42b45a6
added consistency as an option
skeswa Jul 23, 2016
cba0cc9
fixed the overflow
skeswa Jul 23, 2016
0cd470e
Adopted @nlacey's suggestion.
skeswa Jul 25, 2016
aa4dc12
Oops! Correcting a renaming error.
skeswa Jul 25, 2016
8630ea7
changed import paths to point to dimag-jfrog
dimag-jfrog Aug 4, 2016
64101a1
Changes that interfere with the Migrate open source code:
dimag-jfrog Aug 8, 2016
5f7b2ca
- Reset all changes to the upstream branch
dimag-jfrog Aug 8, 2016
c71fea9
Relaxed constratint that method receiver has to be of Driver interface.
dimag-jfrog Aug 8, 2016
570e4b4
- redefined mongo db driver to be autonomous and not depending on spe…
dimag-jfrog Aug 9, 2016
866ff82
- registering method receiver directly for the driver
dimag-jfrog Aug 9, 2016
834a096
Added explicit migration method signature validation
dimag-jfrog Aug 10, 2016
e27b9c2
- Refactored project structure to be consistent with original project
dimag-jfrog Aug 10, 2016
e9ede55
Added README.md
dimag-jfrog Aug 10, 2016
9bd4c8c
Checking non-exported migration method
dimag-jfrog Aug 10, 2016
32cb825
specifying version of mongo
dimag-jfrog Aug 10, 2016
d4b56e6
reverted import path from dimag-jfrog to mattes
dimag-jfrog Aug 10, 2016
74b161f
Add Cassandra url format
trietphm Aug 31, 2016
9a558ee
Skip tests requiring a DB connection with the '-short' flag
dacamp Oct 23, 2016
04e1cb0
Bump travis versions to use Go 1.6 and 1.7
dacamp Oct 23, 2016
d290bf9
- docker command should remain 'go-test'
dacamp Oct 23, 2016
9c71722
Merge pull request #114 from skeswa/feature/consistency-in-conn-str
mattes Dec 22, 2016
478fb42
Update README.md
mattes Dec 22, 2016
33aebee
Merge pull request #129 from mattes/mattes-docs-1
mattes Dec 22, 2016
ae018f8
Merge pull request #119 from trietphm/master
mattes Dec 22, 2016
7910a55
Merge pull request #103 from cgilling/better_cassandra_uri_errors
mattes Dec 22, 2016
b94dd6f
Merge pull request #96 from meehow/patch-1
mattes Dec 22, 2016
cb2fa36
Merge pull request #81 from uzimonkey/master
mattes Dec 22, 2016
4926714
Merge pull request #125 from dacamp/travis
mattes Dec 22, 2016
e97cecb
Merge pull request #124 from dacamp/skip
mattes Dec 22, 2016
b4d9b6a
Merge pull request #59 from bfitzsimmons/patch-1
mattes Dec 22, 2016
474d0f5
Merge pull request #90 from jmhodges/fail_on_missing_command
mattes Dec 22, 2016
11b4db8
Merge pull request #73 from uber/create_epoch
mattes Dec 22, 2016
cd15e67
Merge pull request #104 from connctd/crate
mattes Dec 22, 2016
d4796c8
Update README to reflect epoch filenames
dacamp Dec 22, 2016
3e3cef3
Merge pull request #131 from dacamp/patch-1
mattes Dec 22, 2016
5773f75
Add Ql driver
wlcx Jan 5, 2017
966ba84
Merge pull request #133 from wlcx/add-ql-driver
mattes Jan 5, 2017
6496fc4
- Merge branch 'prepare_pr' of https://github.com/dimag-jfrog/migrate
dimag-jfrog Jan 6, 2017
660297c
- Merge branch 'prepare_pr' of https://github.com/dimag-jfrog/migrate
dimag-jfrog Jan 6, 2017
739d0b2
Ensuring uniqueness of the "version" field
dimag-jfrog Jan 6, 2017
686d4f0
prefix migration files with epoch
dacamp Dec 16, 2015
283effd
Added driver for crate.io database
dereulenspiegel Jun 16, 2016
948c06b
Add Ql driver
wlcx Jan 5, 2017
ecab7c3
Reverted the merge, reapplied changes and rebased master
dimag-jfrog Jan 6, 2017
2d7a79d
fixed errors that were introduced in last merge-rebase
dimag-jfrog Jan 6, 2017
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
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ sudo: required
go:
- 1.4
- 1.5
- 1.6
- 1.7

services:
- docker
Expand Down
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
TESTFLAGS?=
IMAGE=mattes/migrate
DCR=docker-compose run --rm
.PHONY: clean test build release docker-build docker-push run
GOTEST=go test $(TESTFLAGS) `go list ./... | grep -v "/vendor/"`

.PHONY: clean test build release docker-build docker-push run
all: release

clean:
rm -f migrate

test:
fmt:
@gofmt -s -w `go list -f {{.Dir}} ./... | grep -v "/vendor/"`

test: fmt
$(DCR) go-test

go-test: fmt
@$(GOTEST)

build:
$(DCR) go-build

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ __Features__
* [Cassandra](https://github.com/mattes/migrate/tree/master/driver/cassandra)
* [SQLite](https://github.com/mattes/migrate/tree/master/driver/sqlite3)
* [MySQL](https://github.com/mattes/migrate/tree/master/driver/mysql) ([experimental](https://github.com/mattes/migrate/issues/1#issuecomment-58728186))
* [Ql](https://github.com/mattes/migrate/tree/master/driver/ql)
* Bash (planned)

Need another driver? Just implement the [Driver interface](http://godoc.org/github.com/mattes/migrate/driver#Driver) and open a PR.
Expand Down Expand Up @@ -100,15 +101,15 @@ go migrate.Up(pipe, "driver://url", "./path")
The format of migration files looks like this:

```
001_initial_plan_to_do_sth.up.sql # up migration instructions
001_initial_plan_to_do_sth.down.sql # down migration instructions
002_xxx.up.sql
002_xxx.down.sql
1481574547_initial_plan_to_do_sth.up.sql # up migration instructions
1481574547_initial_plan_to_do_sth.down.sql # down migration instructions
1482438365_xxx.up.sql
1482438365_xxx.down.sql
...
```

Why two files? This way you could still do sth like
``psql -f ./db/migrations/001_initial_plan_to_do_sth.up.sql`` and there is no
``psql -f ./db/migrations/1481574547_initial_plan_to_do_sth.up.sql`` and there is no
need for any custom markup language to divide up and down migrations. Please note
that the filename extension depends on the driver.

Expand Down
10 changes: 9 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ go-test:
- postgres
- mysql
- cassandra
- crate
- mongo
go-build:
<<: *go
command: sh -c 'go get -v && go build -ldflags ''-s'' -o migrater'
Expand All @@ -21,6 +23,12 @@ mysql:
image: mysql
environment:
MYSQL_DATABASE: migratetest
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
cassandra:
image: cassandra:2.2
crate:
image: crate
mongo:
image: mongo:3.2.6


7 changes: 6 additions & 1 deletion driver/cassandra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ migrate -url cassandra://host:port/keyspace -path ./db/migrations up
migrate help # for more info
```

Url format
- Authentication: `cassandra://username:password@host:port/keyspace`
- Cassandra v3.x: `cassandra://host:port/keyspace?protocol=4`


## Authors

* Paul Bergeron, https://github.com/dinedal
* Johnny Bergström, https://github.com/balboah
* pateld982, http://github.com/pateld982
* pateld982, http://github.com/pateld982
39 changes: 37 additions & 2 deletions driver/cassandra/cassandra.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,36 @@ const (
)

// Cassandra Driver URL format:
// cassandra://host:port/keyspace?protocol=version
// cassandra://host:port/keyspace?protocol=version&consistency=level
//
// Example:
// Examples:
// cassandra://localhost/SpaceOfKeys?protocol=4
// cassandra://localhost/SpaceOfKeys?protocol=4&consistency=all
// cassandra://localhost/SpaceOfKeys?consistency=quorum
func (driver *Driver) Initialize(rawurl string) error {
u, err := url.Parse(rawurl)
if err != nil {
return fmt.Errorf("failed to parse connectil url: %v", err)
}

if u.Path == "" {
return fmt.Errorf("no keyspace provided in connection url")
}

cluster := gocql.NewCluster(u.Host)
cluster.Keyspace = u.Path[1:len(u.Path)]
cluster.Consistency = gocql.All
cluster.Timeout = 1 * time.Minute

if len(u.Query().Get("consistency")) > 0 {
consistency, err := parseConsistency(u.Query().Get("consistency"))
if err != nil {
return err
}

cluster.Consistency = consistency
}

if len(u.Query().Get("protocol")) > 0 {
protoversion, err := strconv.Atoi(u.Query().Get("protocol"))
if err != nil {
Expand Down Expand Up @@ -169,3 +187,20 @@ func (driver *Driver) Version() (uint64, error) {
func init() {
driver.RegisterDriver("cassandra", &Driver{})
}

// ParseConsistency wraps gocql.ParseConsistency to return an error
// instead of a panicing.
func parseConsistency(consistencyStr string) (consistency gocql.Consistency, err error) {
defer func() {
if r := recover(); r != nil {
var ok bool
err, ok = r.(error)
if !ok {
err = fmt.Errorf("Failed to parse consistency \"%s\": %v", consistencyStr, r)
}
}
}()
consistency = gocql.ParseConsistency(consistencyStr)

return consistency, nil
}
34 changes: 34 additions & 0 deletions driver/cassandra/cassandra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import (
)

func TestMigrate(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}

var session *gocql.Session

host := os.Getenv("CASSANDRA_PORT_9042_TCP_ADDR")
Expand Down Expand Up @@ -112,5 +116,35 @@ func TestMigrate(t *testing.T) {
if err := d.Close(); err != nil {
t.Fatal(err)
}
}

func TestInitializeReturnsErrorsForBadUrls(t *testing.T) {
var session *gocql.Session

host := os.Getenv("CASSANDRA_PORT_9042_TCP_ADDR")
port := os.Getenv("CASSANDRA_PORT_9042_TCP_PORT")

cluster := gocql.NewCluster(host)
cluster.Consistency = gocql.All
cluster.Timeout = 1 * time.Minute

session, err := cluster.CreateSession()
if err != nil {
t.Fatal(err)
}
defer session.Close()
if err := session.Query(`CREATE KEYSPACE IF NOT EXISTS migrate WITH REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 1};`).Exec(); err != nil {
t.Fatal(err)
}

d := &Driver{}
invalidURL := "sdf://asdf://as?df?a"
if err := d.Initialize(invalidURL); err == nil {
t.Errorf("expected an error to be returned if url could not be parsed")
}

noKeyspace := "cassandra://" + host + ":" + port
if err := d.Initialize(noKeyspace); err == nil {
t.Errorf("expected an error to be returned if no keyspace provided")
}
}
15 changes: 15 additions & 0 deletions driver/crate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Crate driver

This is a driver for the [Crate](https://crate.io) database. It is based on the Crate
sql driver by [herenow](https://github.com/herenow/go-crate).

This driver does not use transactions! This is not a limitation of the driver, but a
limitation of Crate. So handle situations with failed migrations with care!

## Usage

```bash
migrate -url http://host:port -path ./db/migrations create add_field_to_table
migrate -url http://host:port -path ./db/migrations up
migrate help # for more info
```
115 changes: 115 additions & 0 deletions driver/crate/crate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Package crate implements a driver for the Crate.io database
package crate

import (
"database/sql"
"fmt"
"strings"

_ "github.com/herenow/go-crate"
"github.com/mattes/migrate/driver"
"github.com/mattes/migrate/file"
"github.com/mattes/migrate/migrate/direction"
)

func init() {
driver.RegisterDriver("crate", &Driver{})
}

type Driver struct {
db *sql.DB
}

const tableName = "schema_migrations"

func (driver *Driver) Initialize(url string) error {
url = strings.Replace(url, "crate", "http", 1)
db, err := sql.Open("crate", url)
if err != nil {
return err
}
if err := db.Ping(); err != nil {
return err
}
driver.db = db

if err := driver.ensureVersionTableExists(); err != nil {
return err
}
return nil
}

func (driver *Driver) Close() error {
if err := driver.db.Close(); err != nil {
return err
}
return nil
}

func (driver *Driver) FilenameExtension() string {
return "sql"
}

func (driver *Driver) Version() (uint64, error) {
var version uint64
err := driver.db.QueryRow("SELECT version FROM " + tableName + " ORDER BY version DESC LIMIT 1").Scan(&version)
switch {
case err == sql.ErrNoRows:
return 0, nil
case err != nil:
return 0, err
default:
return version, nil
}
}

func (driver *Driver) Migrate(f file.File, pipe chan interface{}) {
defer close(pipe)
pipe <- f

if err := f.ReadContent(); err != nil {
pipe <- err
return
}

lines := splitContent(string(f.Content))
for _, line := range lines {
_, err := driver.db.Exec(line)
if err != nil {
pipe <- err
return
}
}

if f.Direction == direction.Up {
if _, err := driver.db.Exec("INSERT INTO "+tableName+" (version) VALUES (?)", f.Version); err != nil {
pipe <- err
return
}
} else if f.Direction == direction.Down {
if _, err := driver.db.Exec("DELETE FROM "+tableName+" WHERE version=?", f.Version); err != nil {
pipe <- err
return
}
}
}

func splitContent(content string) []string {
lines := strings.Split(content, ";")
resultLines := make([]string, 0, len(lines))
for i, line := range lines {
line = strings.Replace(lines[i], ";", "", -1)
line = strings.TrimSpace(line)
if line != "" {
resultLines = append(resultLines, line)
}
}
return resultLines
}

func (driver *Driver) ensureVersionTableExists() error {
if _, err := driver.db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (version INTEGER PRIMARY KEY)", tableName)); err != nil {
return err
}
return nil
}
Loading