ridgepole 0.4.7 → 0.4.8.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -0
- data/bin/ridgepole +28 -12
- data/lib/ridgepole/client.rb +5 -5
- data/lib/ridgepole/delta.rb +61 -5
- data/lib/ridgepole/diff.rb +5 -3
- data/lib/ridgepole/dsl_parser.rb +19 -10
- data/lib/ridgepole/version.rb +1 -1
- data/spec/cli/ridgepole_spec.rb +6 -9
- data/spec/migrate/migrate_add_column2_spec.rb +6 -3
- data/spec/migrate/migrate_execute_spec.rb +285 -0
- data/spec/migrate/migrate_noop_spec.rb +6 -3
- data/spec/spec_helper.rb +9 -2
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bf1189c330df38c7b922e8d49efbe41345bf5ca
|
4
|
+
data.tar.gz: 7577f13cff3830ee86f19617b593c68a83d225d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1599cba8ef9a7720d32b8da9d5f3403c4dec8a8a92930bd80072df35c6a190934ca61f990d97da47cf7464cfe9031b68f1cc69195dabf826fb5a09e8a5f3f0ff
|
7
|
+
data.tar.gz: 1709a0da42bb15ce7548b38a3b5bcfce395a4608c68201c8d1db16fd93c38172b9023cc5dcb8c47943abb6fb970792458552fabb414ccec36047c6e74effb4f1
|
data/README.md
CHANGED
@@ -128,6 +128,25 @@ create_table "user_comments", force: true, renamed_from: "comments" do |t|
|
|
128
128
|
end
|
129
129
|
```
|
130
130
|
|
131
|
+
## Execute
|
132
|
+
```sh
|
133
|
+
create_table "authors", force: true do |t|
|
134
|
+
t.string "name", null: false
|
135
|
+
end
|
136
|
+
|
137
|
+
create_table "books", force: true do |t|
|
138
|
+
t.string "title", null: false
|
139
|
+
t.integer "author_id", unsigned: true, null: false
|
140
|
+
end
|
141
|
+
|
142
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
143
|
+
|
144
|
+
execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
|
145
|
+
# Execute SQL only if there is no foreign key
|
146
|
+
c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = 'bookshelf' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
131
150
|
## Diff
|
132
151
|
```sh
|
133
152
|
$ ridgepole --diff file1.schema file2.schema
|
data/bin/ridgepole
CHANGED
@@ -34,11 +34,23 @@ set_mode = proc do |m|
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def noop_migrate(delta)
|
37
|
-
|
37
|
+
unless delta.script.empty?
|
38
|
+
puts delta.script + "\n\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
migrated, out = delta.migrate(:noop => true)
|
38
42
|
|
39
|
-
|
40
|
-
|
43
|
+
if migrated
|
44
|
+
out.each_line do |line|
|
45
|
+
if line =~ /\A\s+/
|
46
|
+
puts "# #{line}"
|
47
|
+
else
|
48
|
+
puts line.strip.gsub(/([^\d])([(),])([^\d])/) { "#{$1}#{$2}\n#{$3}" }.each_line.map {|i| "# #{i.gsub(/^\s+/, '')}"}.join + "\n"
|
49
|
+
end
|
50
|
+
end
|
41
51
|
end
|
52
|
+
|
53
|
+
return migrated
|
42
54
|
end
|
43
55
|
|
44
56
|
ARGV.options do |opt|
|
@@ -161,17 +173,18 @@ begin
|
|
161
173
|
|
162
174
|
dsl = File.read(file)
|
163
175
|
delta = client.diff(dsl, :path => file)
|
176
|
+
differ = delta.differ?
|
164
177
|
|
165
178
|
if options[:dry_run]
|
166
|
-
if
|
167
|
-
noop_migrate(delta)
|
179
|
+
if differ
|
180
|
+
differ = noop_migrate(delta)
|
168
181
|
end
|
169
182
|
else
|
170
183
|
logger.verbose_info('# Update schema')
|
171
|
-
delta.migrate
|
184
|
+
differ, out = delta.migrate
|
172
185
|
end
|
173
186
|
|
174
|
-
unless
|
187
|
+
unless differ
|
175
188
|
logger.info('No change')
|
176
189
|
end
|
177
190
|
when :diff
|
@@ -193,15 +206,18 @@ begin
|
|
193
206
|
|
194
207
|
if diff_with_apply
|
195
208
|
logger.verbose_info('# Update schema')
|
209
|
+
differ = delta.differ?
|
196
210
|
|
197
|
-
if
|
198
|
-
delta.migrate
|
199
|
-
|
211
|
+
if differ
|
212
|
+
differ, out = delta.migrate
|
213
|
+
end
|
214
|
+
|
215
|
+
if differ
|
200
216
|
logger.info('No change')
|
201
217
|
end
|
202
218
|
elsif delta.differ?
|
203
|
-
noop_migrate(delta)
|
204
|
-
exit_code = 1
|
219
|
+
differ = noop_migrate(delta)
|
220
|
+
exit_code = 1 if differ
|
205
221
|
end
|
206
222
|
end
|
207
223
|
rescue => e
|
data/lib/ridgepole/client.rb
CHANGED
@@ -22,11 +22,11 @@ class Ridgepole::Client
|
|
22
22
|
logger = Ridgepole::Logger.instance
|
23
23
|
|
24
24
|
logger.verbose_info('# Parse DSL')
|
25
|
-
expected_definition = @parser.parse(dsl, opts)
|
25
|
+
expected_definition, expected_execute = @parser.parse(dsl, opts)
|
26
26
|
logger.verbose_info('# Load tables')
|
27
|
-
current_definition = @parser.parse(@dumper.dump)
|
27
|
+
current_definition, current_execute = @parser.parse(@dumper.dump)
|
28
28
|
logger.verbose_info('# Compare definitions')
|
29
|
-
@diff.diff(current_definition, expected_definition)
|
29
|
+
@diff.diff(current_definition, expected_definition, :execute => expected_execute)
|
30
30
|
end
|
31
31
|
|
32
32
|
class << self
|
@@ -34,9 +34,9 @@ class Ridgepole::Client
|
|
34
34
|
logger = Ridgepole::Logger.instance
|
35
35
|
|
36
36
|
logger.verbose_info('# Parse DSL1')
|
37
|
-
definition1 = load_definition(dsl_or_config1)
|
37
|
+
definition1, execute1 = load_definition(dsl_or_config1)
|
38
38
|
logger.verbose_info('# Parse DSL2')
|
39
|
-
definition2 = load_definition(dsl_or_config2)
|
39
|
+
definition2, execute2 = load_definition(dsl_or_config2)
|
40
40
|
|
41
41
|
logger.verbose_info('# Compare definitions')
|
42
42
|
diff = Ridgepole::Diff.new(options)
|
data/lib/ridgepole/delta.rb
CHANGED
@@ -4,6 +4,7 @@ class Ridgepole::Delta
|
|
4
4
|
def initialize(delta, options = {})
|
5
5
|
@delta = delta
|
6
6
|
@options = options
|
7
|
+
@logger = Ridgepole::Logger.instance
|
7
8
|
end
|
8
9
|
|
9
10
|
def migrate(options = {})
|
@@ -41,12 +42,15 @@ class Ridgepole::Delta
|
|
41
42
|
end
|
42
43
|
|
43
44
|
def differ?
|
44
|
-
not script.empty?
|
45
|
+
not script.empty? or not delta_execute.empty?
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
48
49
|
|
49
50
|
def migrate0(options = {})
|
51
|
+
migrated = false
|
52
|
+
out = nil
|
53
|
+
|
50
54
|
if options[:noop]
|
51
55
|
disable_logging_orig = ActiveRecord::Migration.disable_logging
|
52
56
|
|
@@ -59,26 +63,74 @@ class Ridgepole::Delta
|
|
59
63
|
end
|
60
64
|
|
61
65
|
Ridgepole::ExecuteExpander.without_operation(callback) do
|
62
|
-
eval_script(script, options.merge(:out => buf))
|
66
|
+
migrated = eval_script(script, options.merge(:out => buf))
|
63
67
|
end
|
64
68
|
|
65
|
-
buf.string.strip
|
69
|
+
out = buf.string.strip
|
66
70
|
ensure
|
67
71
|
ActiveRecord::Migration.disable_logging = disable_logging_orig
|
68
72
|
end
|
69
73
|
else
|
70
|
-
eval_script(script, options)
|
74
|
+
migrated = eval_script(script, options)
|
71
75
|
end
|
76
|
+
|
77
|
+
[migrated, out]
|
72
78
|
end
|
73
79
|
|
74
80
|
def eval_script(script, options = {})
|
81
|
+
execute_count = 0
|
82
|
+
|
75
83
|
begin
|
76
84
|
with_pre_post_query(options) do
|
77
|
-
|
85
|
+
unless script.empty?
|
86
|
+
ActiveRecord::Schema.new.instance_eval(script, SCRIPT_NAME, 1)
|
87
|
+
end
|
88
|
+
|
89
|
+
execute_count = execute_sqls(options)
|
78
90
|
end
|
79
91
|
rescue => e
|
80
92
|
raise_exception(script, e)
|
81
93
|
end
|
94
|
+
|
95
|
+
not script.empty? or execute_count.nonzero?
|
96
|
+
end
|
97
|
+
|
98
|
+
def execute_sqls(options = {})
|
99
|
+
es = @delta[:execute] || []
|
100
|
+
out = options[:out] || $stdout
|
101
|
+
execute_count = 0
|
102
|
+
|
103
|
+
es.each do |exec|
|
104
|
+
sql, cond = exec.values_at(:sql, :condition)
|
105
|
+
executable = false
|
106
|
+
|
107
|
+
begin
|
108
|
+
executable = cond.nil? || cond.call(ActiveRecord::Base.connection)
|
109
|
+
rescue => e
|
110
|
+
errmsg = "[WARN] `#{sql}` is not executed: #{e.message}"
|
111
|
+
|
112
|
+
if @options[:debug]
|
113
|
+
errmsg = ([errmsg] + e.backtrace).join("\n\tfrom ")
|
114
|
+
end
|
115
|
+
|
116
|
+
Ridgepole::Logger.instance.warn(errmsg)
|
117
|
+
|
118
|
+
executable = false
|
119
|
+
end
|
120
|
+
|
121
|
+
next unless executable
|
122
|
+
|
123
|
+
if options[:noop]
|
124
|
+
out.puts(sql.strip_heredoc)
|
125
|
+
else
|
126
|
+
@logger.info(sql.strip_heredoc)
|
127
|
+
ActiveRecord::Base.connection.execute(sql)
|
128
|
+
end
|
129
|
+
|
130
|
+
execute_count += 1
|
131
|
+
end
|
132
|
+
|
133
|
+
return execute_count
|
82
134
|
end
|
83
135
|
|
84
136
|
def with_pre_post_query(options = {})
|
@@ -324,4 +376,8 @@ remove_index(#{table_name.inspect}, #{target.inspect})
|
|
324
376
|
EOS
|
325
377
|
end
|
326
378
|
end
|
379
|
+
|
380
|
+
def delta_execute
|
381
|
+
@delta[:execute] || []
|
382
|
+
end
|
327
383
|
end
|
data/lib/ridgepole/diff.rb
CHANGED
@@ -3,9 +3,9 @@ class Ridgepole::Diff
|
|
3
3
|
@options = options
|
4
4
|
end
|
5
5
|
|
6
|
-
def diff(from, to)
|
7
|
-
from = (from || {}).
|
8
|
-
to = (to || {}).
|
6
|
+
def diff(from, to, options = {})
|
7
|
+
from = (from || {}).deep_dup
|
8
|
+
to = (to || {}).deep_dup
|
9
9
|
|
10
10
|
if @options[:reverse]
|
11
11
|
from, to = to, from
|
@@ -36,6 +36,8 @@ class Ridgepole::Diff
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
delta[:execute] = options[:execute]
|
40
|
+
|
39
41
|
Ridgepole::Delta.new(delta, @options)
|
40
42
|
end
|
41
43
|
|
data/lib/ridgepole/dsl_parser.rb
CHANGED
@@ -40,26 +40,28 @@ class Ridgepole::DSLParser
|
|
40
40
|
|
41
41
|
def timestamps(*args)
|
42
42
|
options = {:null => false}.merge(args.extract_options!)
|
43
|
-
column(:created_at, :datetime, options
|
44
|
-
column(:updated_at, :datetime, options
|
43
|
+
column(:created_at, :datetime, options)
|
44
|
+
column(:updated_at, :datetime, options)
|
45
45
|
end
|
46
46
|
|
47
47
|
def references(*args)
|
48
48
|
options = args.extract_options!
|
49
49
|
polymorphic = options.delete(:polymorphic)
|
50
50
|
args.each do |col|
|
51
|
-
column("#{col}_id", :integer, options
|
52
|
-
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options
|
51
|
+
column("#{col}_id", :integer, options)
|
52
|
+
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
|
53
53
|
end
|
54
54
|
end
|
55
55
|
alias :belongs_to :references
|
56
56
|
end
|
57
57
|
|
58
58
|
attr_reader :__definition
|
59
|
+
attr_reader :__execute
|
59
60
|
|
60
61
|
def initialize(opts = {})
|
61
62
|
@__working_dir = File.expand_path(opts[:path] ? File.dirname(opts[:path]) : Dir.pwd)
|
62
63
|
@__definition = {}
|
64
|
+
@__execute = []
|
63
65
|
end
|
64
66
|
|
65
67
|
def self.eval(dsl, opts = {})
|
@@ -71,7 +73,7 @@ class Ridgepole::DSLParser
|
|
71
73
|
ctx.instance_eval(dsl)
|
72
74
|
end
|
73
75
|
|
74
|
-
ctx.__definition
|
76
|
+
[ctx.__definition, ctx.__execute]
|
75
77
|
end
|
76
78
|
|
77
79
|
def create_table(table_name, options = {})
|
@@ -123,6 +125,13 @@ class Ridgepole::DSLParser
|
|
123
125
|
Kernel.require(file)
|
124
126
|
end
|
125
127
|
end
|
128
|
+
|
129
|
+
def execute(sql, name = nil, &cond)
|
130
|
+
@__execute << {
|
131
|
+
:sql => sql,
|
132
|
+
:condition => cond,
|
133
|
+
}
|
134
|
+
end
|
126
135
|
end
|
127
136
|
|
128
137
|
def initialize(options = {})
|
@@ -130,15 +139,15 @@ class Ridgepole::DSLParser
|
|
130
139
|
end
|
131
140
|
|
132
141
|
def parse(dsl, opts = {})
|
133
|
-
|
134
|
-
check_orphan_index(
|
135
|
-
|
142
|
+
definition, execute = Context.eval(dsl, opts)
|
143
|
+
check_orphan_index(definition)
|
144
|
+
[definition, execute]
|
136
145
|
end
|
137
146
|
|
138
147
|
private
|
139
148
|
|
140
|
-
def check_orphan_index(
|
141
|
-
|
149
|
+
def check_orphan_index(definition)
|
150
|
+
definition.each do |table_name, attrs|
|
142
151
|
if attrs.length == 1 and attrs[:indices]
|
143
152
|
raise "Table `#{table_name}` to create the index is not defined: #{attrs[:indices].keys.join(',')}"
|
144
153
|
end
|
data/lib/ridgepole/version.rb
CHANGED
data/spec/cli/ridgepole_spec.rb
CHANGED
@@ -110,8 +110,8 @@ describe 'ridgepole' do
|
|
110
110
|
Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {:dry_run=>false, :debug=>false}])
|
111
111
|
Apply `Schemafile`
|
112
112
|
Ridgepole::Client#diff
|
113
|
-
Ridgepole::Delta#migrate
|
114
113
|
Ridgepole::Delta#differ?
|
114
|
+
Ridgepole::Delta#migrate
|
115
115
|
No change
|
116
116
|
EOS
|
117
117
|
end
|
@@ -131,8 +131,8 @@ describe 'ridgepole' do
|
|
131
131
|
Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_test_for_conf_file"}, {:dry_run=>false, :debug=>true}])
|
132
132
|
Apply `Schemafile`
|
133
133
|
Ridgepole::Client#diff
|
134
|
-
Ridgepole::Delta#migrate
|
135
134
|
Ridgepole::Delta#differ?
|
135
|
+
Ridgepole::Delta#migrate
|
136
136
|
No change
|
137
137
|
EOS
|
138
138
|
end
|
@@ -157,8 +157,8 @@ describe 'ridgepole' do
|
|
157
157
|
Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_development"}, {:dry_run=>false, :debug=>true}])
|
158
158
|
Apply `Schemafile`
|
159
159
|
Ridgepole::Client#diff
|
160
|
-
Ridgepole::Delta#migrate
|
161
160
|
Ridgepole::Delta#differ?
|
161
|
+
Ridgepole::Delta#migrate
|
162
162
|
No change
|
163
163
|
EOS
|
164
164
|
end
|
@@ -173,7 +173,6 @@ describe 'ridgepole' do
|
|
173
173
|
Apply `Schemafile` (dry-run)
|
174
174
|
Ridgepole::Client#diff
|
175
175
|
Ridgepole::Delta#differ?
|
176
|
-
Ridgepole::Delta#differ?
|
177
176
|
No change
|
178
177
|
EOS
|
179
178
|
end
|
@@ -189,8 +188,8 @@ describe 'ridgepole' do
|
|
189
188
|
Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {:dry_run=>false, :debug=>false}])
|
190
189
|
Apply `Schemafile`
|
191
190
|
Ridgepole::Client#diff
|
192
|
-
Ridgepole::Delta#migrate
|
193
191
|
Ridgepole::Delta#differ?
|
192
|
+
Ridgepole::Delta#migrate
|
194
193
|
EOS
|
195
194
|
end
|
196
195
|
|
@@ -204,15 +203,13 @@ describe 'ridgepole' do
|
|
204
203
|
Ridgepole::Client#diff
|
205
204
|
Ridgepole::Delta#differ?
|
206
205
|
Ridgepole::Delta#script
|
206
|
+
Ridgepole::Delta#script
|
207
207
|
create_table :table do
|
208
208
|
end
|
209
209
|
|
210
210
|
Ridgepole::Delta#migrate
|
211
211
|
# create_table :table do
|
212
|
-
|
213
212
|
# end
|
214
|
-
|
215
|
-
Ridgepole::Delta#differ?
|
216
213
|
EOS
|
217
214
|
end
|
218
215
|
end
|
@@ -244,12 +241,12 @@ describe 'ridgepole' do
|
|
244
241
|
Ridgepole::Client.diff([{"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {:dry_run=>false, :debug=>false}])
|
245
242
|
Ridgepole::Delta#differ?
|
246
243
|
Ridgepole::Delta#script
|
244
|
+
Ridgepole::Delta#script
|
247
245
|
create_table :table do
|
248
246
|
end
|
249
247
|
|
250
248
|
Ridgepole::Delta#migrate
|
251
249
|
# create_table :table do
|
252
|
-
|
253
250
|
# end
|
254
251
|
EOS
|
255
252
|
end
|
@@ -30,7 +30,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
|
|
30
30
|
delta = subject.diff(expected_dsl)
|
31
31
|
expect(delta.differ?).to be_truthy
|
32
32
|
expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
|
33
|
-
sql = delta.migrate(:noop => true)
|
33
|
+
migrated, sql = delta.migrate(:noop => true)
|
34
|
+
expect(migrated).to be_truthy
|
34
35
|
expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
|
35
36
|
|
36
37
|
sql = sql.each_line.map {|i| i.strip }.join("\n")
|
@@ -69,7 +70,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
|
|
69
70
|
delta = subject.diff(expected_dsl)
|
70
71
|
expect(delta.differ?).to be_truthy
|
71
72
|
expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
|
72
|
-
sql = delta.migrate(:noop => true)
|
73
|
+
migrated, sql = delta.migrate(:noop => true)
|
74
|
+
expect(migrated).to be_truthy
|
73
75
|
expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
|
74
76
|
|
75
77
|
sql = sql.each_line.map {|i| i.strip }.join("\n")
|
@@ -108,7 +110,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
|
|
108
110
|
delta = subject.diff(expected_dsl)
|
109
111
|
expect(delta.differ?).to be_truthy
|
110
112
|
expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
|
111
|
-
sql = delta.migrate(:noop => true)
|
113
|
+
migrated, sql = delta.migrate(:noop => true)
|
114
|
+
expect(migrated).to be_truthy
|
112
115
|
expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
|
113
116
|
|
114
117
|
sql = sql.each_line.map {|i| i.strip }.join("\n")
|
@@ -0,0 +1,285 @@
|
|
1
|
+
describe 'Ridgepole::Client#diff -> migrate' do
|
2
|
+
context 'when execute' do
|
3
|
+
let(:dsl) {
|
4
|
+
<<-RUBY
|
5
|
+
create_table "authors", force: true do |t|
|
6
|
+
t.string "name", null: false
|
7
|
+
end
|
8
|
+
|
9
|
+
create_table "books", force: true do |t|
|
10
|
+
t.string "title", null: false
|
11
|
+
t.integer "author_id", unsigned: true, null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
15
|
+
RUBY
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:dsl_with_execute) {
|
19
|
+
<<-RUBY
|
20
|
+
create_table "authors", force: true do |t|
|
21
|
+
t.string "name", null: false
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table "books", force: true do |t|
|
25
|
+
t.string "title", null: false
|
26
|
+
t.integer "author_id", unsigned: true, null: false
|
27
|
+
end
|
28
|
+
|
29
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
30
|
+
|
31
|
+
execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
|
32
|
+
c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
|
33
|
+
end
|
34
|
+
RUBY
|
35
|
+
}
|
36
|
+
|
37
|
+
before { subject.diff(dsl).migrate }
|
38
|
+
subject { client }
|
39
|
+
|
40
|
+
it {
|
41
|
+
delta = subject.diff(dsl_with_execute)
|
42
|
+
expect(delta.differ?).to be_truthy
|
43
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
44
|
+
|
45
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
46
|
+
CREATE TABLE `books` (
|
47
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
48
|
+
`title` varchar(255) NOT NULL,
|
49
|
+
`author_id` int(10) unsigned NOT NULL,
|
50
|
+
PRIMARY KEY (`id`),
|
51
|
+
KEY `idx_author_id` (`author_id`) USING BTREE
|
52
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
53
|
+
SQL
|
54
|
+
|
55
|
+
delta.migrate
|
56
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
57
|
+
|
58
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
59
|
+
CREATE TABLE `books` (
|
60
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
61
|
+
`title` varchar(255) NOT NULL,
|
62
|
+
`author_id` int(10) unsigned NOT NULL,
|
63
|
+
PRIMARY KEY (`id`),
|
64
|
+
KEY `idx_author_id` (`author_id`) USING BTREE,
|
65
|
+
CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
|
66
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
67
|
+
SQL
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when not execute' do
|
72
|
+
let(:dsl) {
|
73
|
+
<<-RUBY
|
74
|
+
create_table "authors", force: true do |t|
|
75
|
+
t.string "name", null: false
|
76
|
+
end
|
77
|
+
|
78
|
+
create_table "books", force: true do |t|
|
79
|
+
t.string "title", null: false
|
80
|
+
t.integer "author_id", unsigned: true, null: false
|
81
|
+
end
|
82
|
+
|
83
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
84
|
+
RUBY
|
85
|
+
}
|
86
|
+
|
87
|
+
let(:dsl_with_execute) {
|
88
|
+
<<-RUBY
|
89
|
+
create_table "authors", force: true do |t|
|
90
|
+
t.string "name", null: false
|
91
|
+
end
|
92
|
+
|
93
|
+
create_table "books", force: true do |t|
|
94
|
+
t.string "title", null: false
|
95
|
+
t.integer "author_id", unsigned: true, null: false
|
96
|
+
end
|
97
|
+
|
98
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
99
|
+
|
100
|
+
execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
|
101
|
+
c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
|
102
|
+
end
|
103
|
+
RUBY
|
104
|
+
}
|
105
|
+
|
106
|
+
before { subject.diff(dsl_with_execute).migrate }
|
107
|
+
subject { client }
|
108
|
+
|
109
|
+
it {
|
110
|
+
delta = subject.diff(dsl_with_execute)
|
111
|
+
expect(delta.differ?).to be_truthy
|
112
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
113
|
+
|
114
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
115
|
+
CREATE TABLE `books` (
|
116
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
117
|
+
`title` varchar(255) NOT NULL,
|
118
|
+
`author_id` int(10) unsigned NOT NULL,
|
119
|
+
PRIMARY KEY (`id`),
|
120
|
+
KEY `idx_author_id` (`author_id`) USING BTREE,
|
121
|
+
CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
|
122
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
123
|
+
SQL
|
124
|
+
|
125
|
+
migrated, out = delta.migrate
|
126
|
+
expect(migrated).to be_falsey
|
127
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
128
|
+
|
129
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
130
|
+
CREATE TABLE `books` (
|
131
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
132
|
+
`title` varchar(255) NOT NULL,
|
133
|
+
`author_id` int(10) unsigned NOT NULL,
|
134
|
+
PRIMARY KEY (`id`),
|
135
|
+
KEY `idx_author_id` (`author_id`) USING BTREE,
|
136
|
+
CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
|
137
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
138
|
+
SQL
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when execute (noop)' do
|
143
|
+
let(:dsl) {
|
144
|
+
<<-RUBY
|
145
|
+
create_table "authors", force: true do |t|
|
146
|
+
t.string "name", null: false
|
147
|
+
end
|
148
|
+
|
149
|
+
create_table "books", force: true do |t|
|
150
|
+
t.string "title", null: false
|
151
|
+
t.integer "author_id", unsigned: true, null: false
|
152
|
+
end
|
153
|
+
|
154
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
155
|
+
RUBY
|
156
|
+
}
|
157
|
+
|
158
|
+
let(:dsl_with_execute) {
|
159
|
+
<<-RUBY
|
160
|
+
create_table "authors", force: true do |t|
|
161
|
+
t.string "name", null: false
|
162
|
+
end
|
163
|
+
|
164
|
+
create_table "books", force: true do |t|
|
165
|
+
t.string "title", null: false
|
166
|
+
t.integer "author_id", unsigned: true, null: false
|
167
|
+
end
|
168
|
+
|
169
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
170
|
+
|
171
|
+
execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
|
172
|
+
c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
|
173
|
+
end
|
174
|
+
RUBY
|
175
|
+
}
|
176
|
+
|
177
|
+
before { subject.diff(dsl).migrate }
|
178
|
+
subject { client }
|
179
|
+
|
180
|
+
it {
|
181
|
+
delta = subject.diff(dsl_with_execute)
|
182
|
+
expect(delta.differ?).to be_truthy
|
183
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
184
|
+
|
185
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
186
|
+
CREATE TABLE `books` (
|
187
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
188
|
+
`title` varchar(255) NOT NULL,
|
189
|
+
`author_id` int(10) unsigned NOT NULL,
|
190
|
+
PRIMARY KEY (`id`),
|
191
|
+
KEY `idx_author_id` (`author_id`) USING BTREE
|
192
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
193
|
+
SQL
|
194
|
+
|
195
|
+
migrated, sql = delta.migrate(:noop => true)
|
196
|
+
expect(migrated).to be_truthy
|
197
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
198
|
+
|
199
|
+
expect(sql.strip).to eq "ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)"
|
200
|
+
|
201
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
202
|
+
CREATE TABLE `books` (
|
203
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
204
|
+
`title` varchar(255) NOT NULL,
|
205
|
+
`author_id` int(10) unsigned NOT NULL,
|
206
|
+
PRIMARY KEY (`id`),
|
207
|
+
KEY `idx_author_id` (`author_id`) USING BTREE
|
208
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
209
|
+
SQL
|
210
|
+
}
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'when not execute (noop)' do
|
214
|
+
let(:dsl) {
|
215
|
+
<<-RUBY
|
216
|
+
create_table "authors", force: true do |t|
|
217
|
+
t.string "name", null: false
|
218
|
+
end
|
219
|
+
|
220
|
+
create_table "books", force: true do |t|
|
221
|
+
t.string "title", null: false
|
222
|
+
t.integer "author_id", unsigned: true, null: false
|
223
|
+
end
|
224
|
+
|
225
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
226
|
+
RUBY
|
227
|
+
}
|
228
|
+
|
229
|
+
let(:dsl_with_execute) {
|
230
|
+
<<-RUBY
|
231
|
+
create_table "authors", force: true do |t|
|
232
|
+
t.string "name", null: false
|
233
|
+
end
|
234
|
+
|
235
|
+
create_table "books", force: true do |t|
|
236
|
+
t.string "title", null: false
|
237
|
+
t.integer "author_id", unsigned: true, null: false
|
238
|
+
end
|
239
|
+
|
240
|
+
add_index "books", ["author_id"], name: "idx_author_id", using: :btree
|
241
|
+
|
242
|
+
execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
|
243
|
+
c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
|
244
|
+
end
|
245
|
+
RUBY
|
246
|
+
}
|
247
|
+
|
248
|
+
before { subject.diff(dsl_with_execute).migrate }
|
249
|
+
subject { client }
|
250
|
+
|
251
|
+
it {
|
252
|
+
delta = subject.diff(dsl_with_execute)
|
253
|
+
expect(delta.differ?).to be_truthy
|
254
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
255
|
+
|
256
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
257
|
+
CREATE TABLE `books` (
|
258
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
259
|
+
`title` varchar(255) NOT NULL,
|
260
|
+
`author_id` int(10) unsigned NOT NULL,
|
261
|
+
PRIMARY KEY (`id`),
|
262
|
+
KEY `idx_author_id` (`author_id`) USING BTREE,
|
263
|
+
CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
|
264
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
265
|
+
SQL
|
266
|
+
|
267
|
+
migrated, sql = delta.migrate(:noop => true)
|
268
|
+
expect(migrated).to be_falsey
|
269
|
+
expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
|
270
|
+
|
271
|
+
expect(sql.strip).to eq ""
|
272
|
+
|
273
|
+
expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
|
274
|
+
CREATE TABLE `books` (
|
275
|
+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
276
|
+
`title` varchar(255) NOT NULL,
|
277
|
+
`author_id` int(10) unsigned NOT NULL,
|
278
|
+
PRIMARY KEY (`id`),
|
279
|
+
KEY `idx_author_id` (`author_id`) USING BTREE,
|
280
|
+
CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
|
281
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
282
|
+
SQL
|
283
|
+
}
|
284
|
+
end
|
285
|
+
end
|
@@ -75,7 +75,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
|
|
75
75
|
it {
|
76
76
|
delta = subject.diff(expected_dsl)
|
77
77
|
expect(delta.differ?).to be_truthy
|
78
|
-
sql = delta.migrate(:noop => true)
|
78
|
+
migrated, sql = delta.migrate(:noop => true)
|
79
|
+
expect(migrated).to be_truthy
|
79
80
|
expect(subject.dump).to eq actual_dsl
|
80
81
|
|
81
82
|
sql = sql.each_line.map {|i| i.strip }.join("\n")
|
@@ -104,7 +105,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
|
|
104
105
|
it {
|
105
106
|
delta = client(:bulk_change => true).diff(expected_dsl)
|
106
107
|
expect(delta.differ?).to be_truthy
|
107
|
-
sql = delta.migrate(:noop => true)
|
108
|
+
migrated, sql = delta.migrate(:noop => true)
|
109
|
+
expect(migrated).to be_truthy
|
108
110
|
expect(subject.dump).to eq actual_dsl
|
109
111
|
|
110
112
|
sql = sql.each_line.map {|i| i.strip }.join("\n")
|
@@ -205,7 +207,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
|
|
205
207
|
it {
|
206
208
|
delta = subject.diff(expected_dsl)
|
207
209
|
expect(delta.differ?).to be_truthy
|
208
|
-
sql = delta.migrate(:noop => true)
|
210
|
+
migrated, sql = delta.migrate(:noop => true)
|
211
|
+
expect(migrated).to be_truthy
|
209
212
|
expect(subject.dump).to eq actual_dsl
|
210
213
|
|
211
214
|
sql = sql.each_line.map {|i| i.strip }.join("\n")
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,8 @@ require 'open3'
|
|
7
7
|
require 'tempfile'
|
8
8
|
require 'json'
|
9
9
|
|
10
|
+
TEST_SCHEMA = 'ridgepole_test'
|
11
|
+
|
10
12
|
ActiveRecord::Migration.verbose = false
|
11
13
|
Ridgepole::Logger.instance.level = ::Logger::ERROR
|
12
14
|
|
@@ -38,10 +40,15 @@ end
|
|
38
40
|
def conn_spec(config = {})
|
39
41
|
{
|
40
42
|
adapter: 'mysql2',
|
41
|
-
database:
|
43
|
+
database: TEST_SCHEMA,
|
42
44
|
}.merge(config)
|
43
45
|
end
|
44
46
|
|
47
|
+
def show_create_table(table_name)
|
48
|
+
raw_conn = ActiveRecord::Base.connection.raw_connection
|
49
|
+
raw_conn.query("SHOW CREATE TABLE `#{table_name}`").first[1]
|
50
|
+
end
|
51
|
+
|
45
52
|
def default_cli_hook
|
46
53
|
<<-RUBY.strip_heredoc
|
47
54
|
require 'ridgepole'
|
@@ -51,7 +58,7 @@ def default_cli_hook
|
|
51
58
|
end
|
52
59
|
def migrate(*args)
|
53
60
|
puts "Ridgepole::Delta#migrate"
|
54
|
-
"create_table :table do\\nend"
|
61
|
+
[#{differ}, "create_table :table do\\nend"]
|
55
62
|
end
|
56
63
|
def script
|
57
64
|
puts "Ridgepole::Delta#script"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ridgepole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Genki Sugawara
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -153,6 +153,7 @@ files:
|
|
153
153
|
- spec/migrate/migrate_duplicate_index_spec.rb
|
154
154
|
- spec/migrate/migrate_duplicate_table_spec.rb
|
155
155
|
- spec/migrate/migrate_empty_spec.rb
|
156
|
+
- spec/migrate/migrate_execute_spec.rb
|
156
157
|
- spec/migrate/migrate_merge_mode_spec.rb
|
157
158
|
- spec/migrate/migrate_noop_spec.rb
|
158
159
|
- spec/migrate/migrate_rename_column_spec.rb
|
@@ -185,12 +186,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
185
186
|
version: '0'
|
186
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
188
|
requirements:
|
188
|
-
- - '
|
189
|
+
- - '>'
|
189
190
|
- !ruby/object:Gem::Version
|
190
|
-
version:
|
191
|
+
version: 1.3.1
|
191
192
|
requirements: []
|
192
193
|
rubyforge_project:
|
193
|
-
rubygems_version: 2.
|
194
|
+
rubygems_version: 2.0.14
|
194
195
|
signing_key:
|
195
196
|
specification_version: 4
|
196
197
|
summary: Ridgepole is a tool to manage DB schema.
|
@@ -224,6 +225,7 @@ test_files:
|
|
224
225
|
- spec/migrate/migrate_duplicate_index_spec.rb
|
225
226
|
- spec/migrate/migrate_duplicate_table_spec.rb
|
226
227
|
- spec/migrate/migrate_empty_spec.rb
|
228
|
+
- spec/migrate/migrate_execute_spec.rb
|
227
229
|
- spec/migrate/migrate_merge_mode_spec.rb
|
228
230
|
- spec/migrate/migrate_noop_spec.rb
|
229
231
|
- spec/migrate/migrate_rename_column_spec.rb
|