Skip to content

Commit 05595f2

Browse files
authored
Merge pull request #1 from wallester/feature/initial-implementation
Initial implementation
2 parents 161d601 + 70c8f94 commit 05595f2

File tree

339 files changed

+150075
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

339 files changed

+150075
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# Folders
77
_obj
88
_test
9+
.idea
910

1011
# Architecture specific extensions/prefixes
1112
*.[568vq]
@@ -22,3 +23,10 @@ _testmain.go
2223
*.exe
2324
*.test
2425
*.prof
26+
27+
# Built binary
28+
migrate
29+
30+
# Coverage output
31+
coverage.cov
32+
coverage.html

Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
build: fmt
3+
@go build
4+
5+
fmt:
6+
@go fmt ./...
7+
8+
lint:
9+
@gometalinter ./... --deadline=5m --vendor --enable misspell --enable goimports --disable aligncheck --concurrency 4
10+
11+
test:
12+
@go list ./... | grep -v vendor | xargs go test
13+
14+
install:
15+
@go install
16+
17+
cov:
18+
@go test -test.covermode=count -test.coverprofile coverage.cov
19+
@go tool cover -html=coverage.cov -o coverage.html

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,18 @@
11
# migrate
22
Command line tool for PostgreSQL migrations
3+
4+
## Features
5+
6+
* Runs migrations in transactions
7+
* Stores migration version details in auto-generated table ``schema_migrations``.
8+
9+
## Usage
10+
11+
```bash
12+
migrate -url postgres://user@host:port/database -path ./db/migrations create add_field_to_table
13+
migrate -url postgres://user@host:port/database -path ./db/migrations up
14+
migrate -url postgres://user@host:port/database -path ./db/migrations up 1
15+
migrate -url postgres://user@host:port/database -path ./db/migrations down
16+
migrate -url postgres://user@host:port/database -path ./db/migrations down 1
17+
migrate help # for more info
18+
```

app/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../Makefile

app/app.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package app
2+
3+
import (
4+
"github.com/urfave/cli"
5+
"github.com/wallester/migrate/commander"
6+
"github.com/wallester/migrate/driver/postgres"
7+
"github.com/wallester/migrate/flag"
8+
"github.com/wallester/migrate/migrator"
9+
"github.com/wallester/migrate/printer"
10+
)
11+
12+
// New returns new cli.App instance
13+
func New() *cli.App {
14+
cmd := commander.New(migrator.New(postgres.New(), printer.New()))
15+
16+
app := cli.NewApp()
17+
app.Name = "migrate"
18+
app.Usage = "Command line tool for PostgreSQL migrations"
19+
app.Version = "1.0.0"
20+
app.Commands = []cli.Command{
21+
cli.Command{
22+
Name: "create",
23+
Usage: "Create a new migration",
24+
ArgsUsage: "<name>",
25+
Action: cmd.Create,
26+
Flags: []cli.Flag{
27+
flag.Path,
28+
},
29+
},
30+
cli.Command{
31+
Name: "up",
32+
Usage: "Apply <n> or all up migrations",
33+
Action: cmd.Up,
34+
ArgsUsage: "<n>",
35+
Flags: []cli.Flag{
36+
flag.Path,
37+
flag.URL,
38+
},
39+
},
40+
cli.Command{
41+
Name: "down",
42+
Usage: "Apply <n> or all down migrations",
43+
Action: cmd.Down,
44+
ArgsUsage: "<n>",
45+
Flags: []cli.Flag{
46+
flag.Path,
47+
flag.URL,
48+
},
49+
},
50+
}
51+
app.Flags = []cli.Flag{
52+
flag.Path,
53+
flag.URL,
54+
}
55+
return app
56+
}

app/app_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package app
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/urfave/cli"
8+
)
9+
10+
func Test_New_ReturnsInstance_InCaseOfSuccess(t *testing.T) {
11+
// Act
12+
app := New()
13+
14+
// Assert
15+
assert.NotNil(t, app)
16+
assert.Equal(t, "migrate", app.Name)
17+
assert.Equal(t, "Command line tool for PostgreSQL migrations", app.Usage)
18+
assert.NotNil(t, app.Commands)
19+
assert.True(t, hasCommand("create", app.Commands))
20+
assert.True(t, hasCommand("up", app.Commands))
21+
assert.True(t, hasCommand("down", app.Commands))
22+
assert.NotNil(t, app.Flags)
23+
assert.True(t, hasFlag("path", app.Flags))
24+
assert.True(t, hasFlag("url", app.Flags))
25+
}
26+
27+
func hasCommand(name string, commands []cli.Command) bool {
28+
for _, command := range commands {
29+
if command.Name == name {
30+
return true
31+
}
32+
}
33+
34+
return false
35+
}
36+
37+
func hasFlag(name string, flags []cli.Flag) bool {
38+
for _, flag := range flags {
39+
if flag.GetName() == name {
40+
return true
41+
}
42+
}
43+
44+
return false
45+
}

commander/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../Makefile

commander/commander.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package commander
2+
3+
import (
4+
"strconv"
5+
6+
"github.com/juju/errors"
7+
"github.com/urfave/cli"
8+
"github.com/wallester/migrate/direction"
9+
"github.com/wallester/migrate/flag"
10+
"github.com/wallester/migrate/migrator"
11+
)
12+
13+
// Commander represents app commands
14+
type Commander interface {
15+
Create(c *cli.Context) error
16+
Up(c *cli.Context) error
17+
Down(c *cli.Context) error
18+
}
19+
20+
type commander struct {
21+
m migrator.Migrator
22+
}
23+
24+
// New returns new instance
25+
func New(m migrator.Migrator) Commander {
26+
return &commander{m}
27+
}
28+
29+
// Create creates new migration files
30+
func (cmd *commander) Create(c *cli.Context) error {
31+
name := c.Args().First()
32+
if name == "" {
33+
return errors.New("please specify migration name")
34+
}
35+
36+
path := flag.Get(c, flag.FlagPath)
37+
if path == "" {
38+
return flag.NewRequiredFlagError(flag.FlagPath)
39+
}
40+
41+
if _, err := cmd.m.Create(name, path); err != nil {
42+
return errors.Annotate(err, "creating migration failed")
43+
}
44+
45+
return nil
46+
}
47+
48+
// Up migrates up
49+
func (cmd *commander) Up(c *cli.Context) error {
50+
args, err := parseMigrateArguments(c)
51+
if err != nil {
52+
return errors.Annotate(err, "parsing parameters failed")
53+
}
54+
55+
if err := cmd.m.Migrate(args.path, args.url, direction.Up, args.steps); err != nil {
56+
return errors.Annotate(err, "migrating up failed")
57+
}
58+
59+
return nil
60+
}
61+
62+
// Down migrates down
63+
func (cmd *commander) Down(c *cli.Context) error {
64+
args, err := parseMigrateArguments(c)
65+
if err != nil {
66+
return errors.Annotate(err, "parsing parameters failed")
67+
}
68+
69+
if err := cmd.m.Migrate(args.path, args.url, direction.Down, args.steps); err != nil {
70+
return errors.Annotate(err, "migrating down failed")
71+
}
72+
73+
return nil
74+
}
75+
76+
type migrateArguments struct {
77+
path string
78+
url string
79+
steps int
80+
}
81+
82+
func parseMigrateArguments(c *cli.Context) (*migrateArguments, error) {
83+
path := flag.Get(c, flag.FlagPath)
84+
if path == "" {
85+
return nil, flag.NewRequiredFlagError(flag.FlagPath)
86+
}
87+
88+
url := flag.Get(c, flag.FlagURL)
89+
if url == "" {
90+
return nil, flag.NewRequiredFlagError(flag.FlagURL)
91+
}
92+
93+
var steps int
94+
s := c.Args().First()
95+
if s != "" {
96+
n, err := strconv.Atoi(s)
97+
if err != nil {
98+
return nil, errors.Annotate(err, "parsing <n> failed")
99+
}
100+
101+
steps = n
102+
}
103+
104+
return &migrateArguments{
105+
path: path,
106+
url: url,
107+
steps: steps,
108+
}, nil
109+
}

0 commit comments

Comments
 (0)