db-migrate 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.travis.yml +6 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +46 -0
- data/LICENSE +20 -0
- data/README.md +60 -0
- data/bin/migrate +136 -0
- data/lib/migrate.rb +9 -0
- data/lib/migrate/config.rb +104 -0
- data/lib/migrate/errors.rb +4 -0
- data/lib/migrate/lang.rb +10 -0
- data/lib/migrate/lang/go.rb +37 -0
- data/lib/migrate/lang/javascript.rb +25 -0
- data/lib/migrate/lang/lang.rb +15 -0
- data/lib/migrate/lang/python.rb +25 -0
- data/lib/migrate/lang/ruby.rb +25 -0
- data/lib/migrate/lang/sql.rb +26 -0
- data/lib/migrate/logger.rb +39 -0
- data/lib/migrate/migrator.rb +144 -0
- data/lib/migrate/storage.rb +7 -0
- data/lib/migrate/storage/db.rb +150 -0
- data/lib/migrate/storage/mysql.rb +77 -0
- data/lib/migrate/storage/postgres.rb +74 -0
- data/migrate.gemspec +21 -0
- data/spec/lib/config_spec.rb +103 -0
- data/spec/lib/fixtures/go/down.go +7 -0
- data/spec/lib/fixtures/go/up.go +7 -0
- data/spec/lib/fixtures/js/down.js +1 -0
- data/spec/lib/fixtures/js/up.js +1 -0
- data/spec/lib/fixtures/py/down.py +1 -0
- data/spec/lib/fixtures/py/up.py +1 -0
- data/spec/lib/fixtures/rb/down.rb +1 -0
- data/spec/lib/fixtures/rb/up.rb +1 -0
- data/spec/lib/fixtures/sql/down.sql +1 -0
- data/spec/lib/fixtures/sql/up.sql +1 -0
- data/spec/lib/lang/lang_spec.rb +46 -0
- data/spec/lib/migrator_spec.rb +103 -0
- data/spec/lib/storage/db_spec.rb +104 -0
- data/spec/spec_helper.rb +109 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9d20012ab53ae15b7b98fec15bb8eae3abd9914e
|
4
|
+
data.tar.gz: e02941b8c31643efaa71774d67b22aba0c4f2bc8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d316f5e858dcdfad7e16449cd78abf3a8a44e51111cb26411467d89bdbaf2cf8900728abebe1f697d05b6553e1dd8839400957ba310d9bb4e4b6066625c13ce
|
7
|
+
data.tar.gz: 8538758ab5dc8d23e9b1923b777187cbb7321d58e7efbe97bd26aa3fca37f32a033bfe795bb6d56f2830e46d9141fc3ee85572cf1a42ade898fe19dd5cc822a6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
migrate (0.0.1)
|
5
|
+
colorize (= 0.7.7)
|
6
|
+
highline (= 1.7.8)
|
7
|
+
json (= 1.8.3)
|
8
|
+
mysql2 (= 0.4.2)
|
9
|
+
parseconfig (= 1.0.6)
|
10
|
+
pg (= 0.18.4)
|
11
|
+
thor (= 0.19.1)
|
12
|
+
|
13
|
+
GEM
|
14
|
+
remote: https://rubygems.org/
|
15
|
+
specs:
|
16
|
+
colorize (0.7.7)
|
17
|
+
diff-lcs (1.2.5)
|
18
|
+
highline (1.7.8)
|
19
|
+
json (1.8.3)
|
20
|
+
mysql2 (0.4.2)
|
21
|
+
parseconfig (1.0.6)
|
22
|
+
pg (0.18.4)
|
23
|
+
rspec (3.4.0)
|
24
|
+
rspec-core (~> 3.4.0)
|
25
|
+
rspec-expectations (~> 3.4.0)
|
26
|
+
rspec-mocks (~> 3.4.0)
|
27
|
+
rspec-core (3.4.1)
|
28
|
+
rspec-support (~> 3.4.0)
|
29
|
+
rspec-expectations (3.4.0)
|
30
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
31
|
+
rspec-support (~> 3.4.0)
|
32
|
+
rspec-mocks (3.4.0)
|
33
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
34
|
+
rspec-support (~> 3.4.0)
|
35
|
+
rspec-support (3.4.1)
|
36
|
+
thor (0.19.1)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
migrate!
|
43
|
+
rspec
|
44
|
+
|
45
|
+
BUNDLED WITH
|
46
|
+
1.10.6
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Ivan Pusic
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# migrate
|
2
|
+
|
3
|
+
Tool for managing and executing your database migrations.
|
4
|
+
|
5
|
+
### How it works?
|
6
|
+
It saves metadata about your migrations to database. It uses that metadata for executing and creating new migrations.
|
7
|
+
|
8
|
+
It supports multiple databases and multiple languages for executing migrations.
|
9
|
+
|
10
|
+
#### Supported databases
|
11
|
+
- PostgreSQL
|
12
|
+
- MySQL
|
13
|
+
|
14
|
+
#### Supported languages
|
15
|
+
- SQL
|
16
|
+
- Ruby
|
17
|
+
- Python
|
18
|
+
- Javascript (Node.js)
|
19
|
+
- Go
|
20
|
+
|
21
|
+
### What I can do with it?
|
22
|
+
```
|
23
|
+
Commands:
|
24
|
+
migrate init # make configuration file
|
25
|
+
migrate new [DESCRIPTION] # generate files for new migration
|
26
|
+
migrate up # Upgrade database schema
|
27
|
+
migrate down # Downgrade database schema
|
28
|
+
migrate list # Show list of all migrations
|
29
|
+
migrate delete [VERSION] # Will delete migration data
|
30
|
+
migrate version # Show current version
|
31
|
+
migrate help [COMMAND] # Describe available commands or one specific
|
32
|
+
Options:
|
33
|
+
-r, [--root=ROOT] # Sepcify migration root directory, where config file is located
|
34
|
+
# Default: .
|
35
|
+
-c, [--config=CONFIG] # Specify custom configuration file name
|
36
|
+
# Default: migrate.conf
|
37
|
+
```
|
38
|
+
|
39
|
+
### How to use it?
|
40
|
+
|
41
|
+
First thing you have to do is to make initial configuration with **migrate init** command.
|
42
|
+
After that you can start generating migrations by using **migrate new** command. This will generate migration script for you based on your prefered language.
|
43
|
+
|
44
|
+
When you are done with writing your `up` and `down` migration script, you can execute **migrate up** to run up migration script for new version. You can also execute multiple migrations in single call by providing `--to n` argument, where `n` is highest version where you want to navigate.
|
45
|
+
|
46
|
+
You can also use **migrate down** to go one version back. `down` comand also accepts `--to n` argument, but in this case `n` is lowest version where you want to navigate.
|
47
|
+
|
48
|
+
If you are asking yourself about current version, use **migrate version** to find out current version.
|
49
|
+
|
50
|
+
If you don't need some migration, use **migrate delete n** to remove version `n`.
|
51
|
+
|
52
|
+
You can see list of your migrations by running **migrate list**. This command also provides some additional options for filtering results.
|
53
|
+
|
54
|
+
## Contributing
|
55
|
+
- do ruby magic
|
56
|
+
- write tests!
|
57
|
+
- send pull request
|
58
|
+
|
59
|
+
## License
|
60
|
+
*MIT*
|
data/bin/migrate
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
require "json"
|
5
|
+
require "highline"
|
6
|
+
require_relative "../lib/migrate"
|
7
|
+
|
8
|
+
include Migrate
|
9
|
+
$asker = HighLine.new
|
10
|
+
|
11
|
+
class CLI < Thor
|
12
|
+
method_option :root, {
|
13
|
+
:aliases => "-r",
|
14
|
+
:default => ".",
|
15
|
+
:desc => "Sepcify migration root directory, where config file is located"
|
16
|
+
}
|
17
|
+
method_option :config, {
|
18
|
+
:aliases => "-c",
|
19
|
+
:default => "migrate.conf",
|
20
|
+
:desc => "Specify custom configuration file name"
|
21
|
+
}
|
22
|
+
def initialize(*args)
|
23
|
+
super
|
24
|
+
@config = Config.new(options["root"], options["config"])
|
25
|
+
|
26
|
+
init_invoked = ARGV.length > 0 && ARGV[0] == "init"
|
27
|
+
if not init_invoked and @config.exists?
|
28
|
+
@config.load!
|
29
|
+
@migrator = Migrator.new(@config)
|
30
|
+
elsif not init_invoked
|
31
|
+
Log.error("Configuration not found in `#{Pathname.new(@config.root).expand_path}`. " \
|
32
|
+
"Make sure you are in right directory or " \
|
33
|
+
"run `migrate init` to create configuration.")
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "init", "make configuration file"
|
39
|
+
def init
|
40
|
+
Log.info("Creating configuration...")
|
41
|
+
|
42
|
+
storage = nil
|
43
|
+
$asker.choose do |menu|
|
44
|
+
menu.prompt = "Which database do you prefer?"
|
45
|
+
|
46
|
+
menu.choice(:mysql) { storage = "mysql" }
|
47
|
+
menu.choices(:pg) { storage = "pg" }
|
48
|
+
end
|
49
|
+
|
50
|
+
db_defaults = case storage
|
51
|
+
when "mysql"
|
52
|
+
{ :port => "3306", :user => "root" }
|
53
|
+
when "pg"
|
54
|
+
{ :port => "5432", :user => "postgres" }
|
55
|
+
end
|
56
|
+
|
57
|
+
lang = nil
|
58
|
+
$asker.choose do |menu|
|
59
|
+
menu.prompt = "What language would you like use for your migration scripts?"
|
60
|
+
|
61
|
+
menu.choice(:sql) { lang = "sql" }
|
62
|
+
menu.choices(:ruby) { lang = "ruby" }
|
63
|
+
menu.choice(:javascript) { lang = "javascript" }
|
64
|
+
menu.choice(:go) { lang = "go" }
|
65
|
+
menu.choice(:python) { lang = "python" }
|
66
|
+
end
|
67
|
+
|
68
|
+
config = {
|
69
|
+
storage: storage,
|
70
|
+
lang: lang,
|
71
|
+
host: $asker.ask("Host: ") {|q| q.default = "localhost"},
|
72
|
+
port: ($asker.ask("Port: ") {|q| q.default = db_defaults[:port]}).to_i,
|
73
|
+
database: $asker.ask("Database Name: ") {|q| q.default = "mydb"},
|
74
|
+
user: $asker.ask("User: ") {|q| q.default = db_defaults[:user]},
|
75
|
+
password: $asker.ask("Password: ") {|q| q.default = nil},
|
76
|
+
version_info: $asker.ask("Version info table: ") {|q| q.default = "version_info"},
|
77
|
+
version_number: $asker.ask("Version number table: ") {|q| q.default = "version_number"}
|
78
|
+
}
|
79
|
+
|
80
|
+
@config.init(config)
|
81
|
+
@config.load!
|
82
|
+
Migrator.new(@config).init
|
83
|
+
rescue Exception => e
|
84
|
+
Log.error("Error while initialization.", e)
|
85
|
+
@config.remove
|
86
|
+
exit
|
87
|
+
end
|
88
|
+
|
89
|
+
desc "new [DESCRIPTION]", "generate files for new migration"
|
90
|
+
def new(description="")
|
91
|
+
@migrator.new(description)
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "up", "Upgrade database schema"
|
95
|
+
option :to, :aliases => "-t", :desc => "Upgrade to the version"
|
96
|
+
def up
|
97
|
+
@migrator.up(options[:to])
|
98
|
+
rescue VersionNotFound => e
|
99
|
+
Log.error("Next version not found.")
|
100
|
+
rescue Exception => e
|
101
|
+
Log.error("Error while migrating up.", e)
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "down [TO_VERSION]", "Downgrade database schema"
|
105
|
+
option :to, :aliases => "-t", :desc => "Downgrade back to the version"
|
106
|
+
def down
|
107
|
+
@migrator.down(options[:to])
|
108
|
+
rescue VersionNotFound => e
|
109
|
+
Log.error("Previous version not found.")
|
110
|
+
rescue Exception => e
|
111
|
+
Log.error("Error while migrating down.", e)
|
112
|
+
end
|
113
|
+
|
114
|
+
desc "list", "Show list of all migrations"
|
115
|
+
option :limit, :aliases => "-l", :desc => "Limit results"
|
116
|
+
option :select, :aliases => "-s", :desc => "Columns to select"
|
117
|
+
def list()
|
118
|
+
@migrator.list(options[:select], options[:limit])
|
119
|
+
end
|
120
|
+
|
121
|
+
desc "delete [VERSION]", "Will delete migration data"
|
122
|
+
def delete(version)
|
123
|
+
@migrator.delete(version.to_i)
|
124
|
+
rescue VersionNotFound
|
125
|
+
Log.error("Version not found.")
|
126
|
+
rescue Exception => e
|
127
|
+
Log.error("Error while removing migration.", e)
|
128
|
+
end
|
129
|
+
|
130
|
+
desc "version", "Show current version"
|
131
|
+
def version()
|
132
|
+
Log.version(@migrator.current_version())
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
CLI.start
|
data/lib/migrate.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require "parseconfig"
|
2
|
+
|
3
|
+
module Migrate
|
4
|
+
class Config
|
5
|
+
attr_reader :root
|
6
|
+
|
7
|
+
def initialize(root, file)
|
8
|
+
@root = root
|
9
|
+
@file=file
|
10
|
+
@file_path = "#{root}/#{file}"
|
11
|
+
@loaded = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists?
|
15
|
+
File.exist? @file_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def init(config)
|
19
|
+
if not Dir.exist? @root
|
20
|
+
Dir.mkdir @root
|
21
|
+
end
|
22
|
+
|
23
|
+
File.open(@file_path, "w") do |f|
|
24
|
+
config.map do |key, value|
|
25
|
+
f.puts "#{key}=#{value}\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Log.success("Configuration file created. Location: `#{@file_path}`")
|
30
|
+
end
|
31
|
+
|
32
|
+
def load!
|
33
|
+
Log.info("Loading configuration...")
|
34
|
+
config = ParseConfig.new(@file_path)
|
35
|
+
|
36
|
+
config.get_params.map do |param|
|
37
|
+
self.class.send(:attr_reader, param)
|
38
|
+
instance_variable_set("@#{param}", config[param])
|
39
|
+
end
|
40
|
+
|
41
|
+
@loaded = true
|
42
|
+
Log.success("Configuration loaded.")
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete
|
46
|
+
File.delete @file_path
|
47
|
+
rescue Exception => e
|
48
|
+
Log.error("Error while removing configuration file.", e)
|
49
|
+
exit
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_db
|
53
|
+
case @storage
|
54
|
+
when "pg"
|
55
|
+
if @pg == nil
|
56
|
+
@pg = Storage::Postgres.new(self)
|
57
|
+
end
|
58
|
+
|
59
|
+
@pg
|
60
|
+
when "mysql"
|
61
|
+
if @mysql == nil
|
62
|
+
@mysql = Storage::Mysql.new(self)
|
63
|
+
end
|
64
|
+
|
65
|
+
@mysql
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_lang
|
70
|
+
case @lang
|
71
|
+
when "sql"
|
72
|
+
if @sql == nil
|
73
|
+
@sql = Lang::Sql.new(get_db)
|
74
|
+
end
|
75
|
+
|
76
|
+
@sql
|
77
|
+
when "javascript"
|
78
|
+
if @javascript == nil
|
79
|
+
@javascript = Lang::Javascript.new
|
80
|
+
end
|
81
|
+
|
82
|
+
@javascript
|
83
|
+
when "ruby"
|
84
|
+
if @ruby == nil
|
85
|
+
@ruby = Lang::Ruby.new
|
86
|
+
end
|
87
|
+
|
88
|
+
@ruby
|
89
|
+
when "go"
|
90
|
+
if @go == nil
|
91
|
+
@go = Lang::Go.new
|
92
|
+
end
|
93
|
+
|
94
|
+
@go
|
95
|
+
when "python"
|
96
|
+
if @python == nil
|
97
|
+
@python = Lang::Python.new
|
98
|
+
end
|
99
|
+
|
100
|
+
@python
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/migrate/lang.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Migrate
|
2
|
+
module Lang
|
3
|
+
class Go < Lang
|
4
|
+
def initialize
|
5
|
+
@ext = "go"
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_migration(dir)
|
9
|
+
File.open("#{dir}/up.#{@ext}", "w") do |f|
|
10
|
+
f.puts <<-eot
|
11
|
+
package main
|
12
|
+
|
13
|
+
func main() {
|
14
|
+
// Here goes your Go migration forward
|
15
|
+
}
|
16
|
+
eot
|
17
|
+
end
|
18
|
+
|
19
|
+
File.open("#{dir}/down.#{@ext}", "w") do |f|
|
20
|
+
f.puts <<-eot
|
21
|
+
package main
|
22
|
+
|
23
|
+
func main() {
|
24
|
+
// Here goes your Go migration backward
|
25
|
+
}
|
26
|
+
eot
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def exec_migration(dir, is_up)
|
31
|
+
script = "#{dir}/#{is_up ? "up" : "down"}.#{@ext}"
|
32
|
+
Log.info("Executing #{script}...")
|
33
|
+
`go run #{script}`
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|