ridgepole 0.4.7 → 0.4.8.rc1
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 +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
|