monkey_butler 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bundle/config +2 -0
- data/.gitignore +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +28 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +122 -0
- data/Guardfile +8 -0
- data/LICENSE +202 -0
- data/README.md +221 -0
- data/Rakefile +16 -0
- data/bin/mb +6 -0
- data/lib/monkey_butler.rb +1 -0
- data/lib/monkey_butler/actions.rb +38 -0
- data/lib/monkey_butler/cli.rb +354 -0
- data/lib/monkey_butler/databases/abstract_database.rb +49 -0
- data/lib/monkey_butler/databases/cassandra_database.rb +69 -0
- data/lib/monkey_butler/databases/sqlite_database.rb +105 -0
- data/lib/monkey_butler/migrations.rb +52 -0
- data/lib/monkey_butler/project.rb +90 -0
- data/lib/monkey_butler/targets/base.rb +85 -0
- data/lib/monkey_butler/targets/cassandra/cassandra_target.rb +72 -0
- data/lib/monkey_butler/targets/cassandra/create_schema_migrations.cql.erb +16 -0
- data/lib/monkey_butler/targets/cassandra/migration.cql.erb +0 -0
- data/lib/monkey_butler/targets/cocoapods/cocoapods_target.rb +43 -0
- data/lib/monkey_butler/targets/cocoapods/podspec.erb +12 -0
- data/lib/monkey_butler/targets/maven/maven_target.rb +60 -0
- data/lib/monkey_butler/targets/maven/project/.gitignore +6 -0
- data/lib/monkey_butler/targets/maven/project/MonkeyButler.iml +19 -0
- data/lib/monkey_butler/targets/maven/project/build.gradle +54 -0
- data/lib/monkey_butler/targets/sqlite/create_monkey_butler_tables.sql.erb +15 -0
- data/lib/monkey_butler/targets/sqlite/migration.sql.erb +11 -0
- data/lib/monkey_butler/targets/sqlite/sqlite_target.rb +91 -0
- data/lib/monkey_butler/templates/Gemfile.erb +4 -0
- data/lib/monkey_butler/templates/gitignore.erb +1 -0
- data/lib/monkey_butler/util.rb +71 -0
- data/lib/monkey_butler/version.rb +3 -0
- data/logo.jpg +0 -0
- data/monkey_butler.gemspec +33 -0
- data/spec/cli_spec.rb +700 -0
- data/spec/databases/cassandra_database_spec.rb +241 -0
- data/spec/databases/sqlite_database_spec.rb +181 -0
- data/spec/migrations_spec.rb +4 -0
- data/spec/project_spec.rb +128 -0
- data/spec/sandbox/cassandra/.gitignore +2 -0
- data/spec/sandbox/cassandra/.monkey_butler.yml +7 -0
- data/spec/sandbox/cassandra/migrations/20140523123443021_create_sandbox.cql.sql +14 -0
- data/spec/sandbox/cassandra/sandbox.cql +0 -0
- data/spec/sandbox/sqlite/.gitignore +2 -0
- data/spec/sandbox/sqlite/.monkey_butler.yml +7 -0
- data/spec/sandbox/sqlite/migrations/20140523123443021_create_sandbox.sql +14 -0
- data/spec/sandbox/sqlite/sandbox.sql +0 -0
- data/spec/spec_helper.rb +103 -0
- data/spec/targets/cassandra_target_spec.rb +191 -0
- data/spec/targets/cocoapods_target_spec.rb +197 -0
- data/spec/targets/maven_target_spec.rb +156 -0
- data/spec/targets/sqlite_target_spec.rb +103 -0
- data/spec/util_spec.rb +13 -0
- metadata +260 -0
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,700 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'monkey_butler/databases/sqlite_database'
|
3
|
+
|
4
|
+
describe MonkeyButler::CLI, "#init" do
|
5
|
+
describe "#init" do
|
6
|
+
let(:thor_class) { MonkeyButler::CLI }
|
7
|
+
let!(:project_root) { Dir.mktmpdir }
|
8
|
+
|
9
|
+
context 'when no PATH is given' do
|
10
|
+
it "prints an argument error to stderr" do
|
11
|
+
output = invoke!([:init])
|
12
|
+
output[:stderr].should =~ /ERROR: "\w+ init" was called with no arguments/
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when the PATH given already exists' do
|
17
|
+
context "and contains existing content" do
|
18
|
+
it "aborts with an error" do
|
19
|
+
Dir.mktmpdir do |path|
|
20
|
+
File.open(File.join(path, 'sdasdasd'), 'w+')
|
21
|
+
output = invoke!([:init, path])
|
22
|
+
output[:stderr].should =~ /Cannot create repository into non-empty path/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "and is a regular file" do
|
28
|
+
it "aborts with an error" do
|
29
|
+
path = Tempfile.new('monkey_butler').path
|
30
|
+
output = invoke!([:init, path])
|
31
|
+
output[:stderr].should =~ /Cannot create repository: regular file exists at path/
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "and is empty" do
|
36
|
+
it "reports the path already exists" do
|
37
|
+
Dir.mktmpdir do |path|
|
38
|
+
output = invoke!([:init, path])
|
39
|
+
output[:stderr].should be_empty
|
40
|
+
output[:stdout].should =~ /exist\s+$/
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when the PATH given does not exist' do
|
47
|
+
before(:each) do
|
48
|
+
FileUtils.remove_entry project_root
|
49
|
+
end
|
50
|
+
|
51
|
+
it "creates the path" do
|
52
|
+
output = invoke!([:init, project_root])
|
53
|
+
output[:stderr].should be_empty
|
54
|
+
output[:stdout].should =~ /create\s+$/
|
55
|
+
File.exists?(project_root).should be_true
|
56
|
+
File.directory?(project_root).should be_true
|
57
|
+
end
|
58
|
+
|
59
|
+
it "populates .gitignore" do
|
60
|
+
invoke!([:init, project_root, '--name=MonkeyButler'])
|
61
|
+
path = File.join(project_root, '.gitignore')
|
62
|
+
expect(File.exists?(project_root)).to be_true
|
63
|
+
content = File.read(path)
|
64
|
+
content.should include('.DS_Store')
|
65
|
+
content.should =~ /^MonkeyButler.sqlite$/
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '.monkey_butler.yml' do
|
69
|
+
let(:args) { [:init, project_root, '--name=MonkeyButler'] }
|
70
|
+
before(:each) do
|
71
|
+
invoke!(args)
|
72
|
+
@yaml_path = File.join(project_root, '.monkey_butler.yml')
|
73
|
+
end
|
74
|
+
|
75
|
+
it "is created" do
|
76
|
+
expect(File.exists?(@yaml_path)).to be_true
|
77
|
+
end
|
78
|
+
|
79
|
+
it "is valid YAML" do
|
80
|
+
expect { YAML.load(File.read(@yaml_path)) }.not_to raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it "configures the project name" do
|
84
|
+
config = YAML.load(File.read(@yaml_path))
|
85
|
+
config['name'].should == 'MonkeyButler'
|
86
|
+
end
|
87
|
+
|
88
|
+
it "includes a nested config dictionary" do
|
89
|
+
config = YAML.load(File.read(@yaml_path))
|
90
|
+
config['config'].should == {}
|
91
|
+
end
|
92
|
+
|
93
|
+
it "configures default adapters" do
|
94
|
+
config = YAML.load(File.read(@yaml_path))
|
95
|
+
config['config'].should == {}
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when config option is specified" do
|
99
|
+
let(:args) { [:init, project_root, '--name=MonkeyButler', '--config', 'foo:bar'] }
|
100
|
+
|
101
|
+
it "parses the arguments as a hash of config vars" do
|
102
|
+
config = YAML.load(File.read(@yaml_path))
|
103
|
+
config['config'].should == {"foo" => "bar"}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "creates an empty database" do
|
109
|
+
invoke!([:init, project_root, '--name=MonkeyButler'])
|
110
|
+
path = File.join(project_root, 'MonkeyButler.db')
|
111
|
+
expect(File.exists?(project_root)).to be_true
|
112
|
+
end
|
113
|
+
|
114
|
+
it "creates an empty schema" do
|
115
|
+
invoke!([:init, project_root, '--name=MonkeyButler'])
|
116
|
+
path = File.join(project_root, 'MonkeyButler.sql')
|
117
|
+
expect(File.exists?(project_root)).to be_true
|
118
|
+
end
|
119
|
+
|
120
|
+
it "generates an initial migration" do
|
121
|
+
invoke!([:init, project_root, '--name=MonkeyButler'])
|
122
|
+
filename = Dir.entries(File.join(project_root, 'migrations')).detect { |f| f =~ /create_monkey_butler.sql$/ }
|
123
|
+
expect(filename).not_to be_nil
|
124
|
+
path = File.join(project_root, 'migrations', filename)
|
125
|
+
expect(File.exists?(path)).to be_true
|
126
|
+
end
|
127
|
+
|
128
|
+
it "initializes a Git repository at the destination path" do
|
129
|
+
invoke!([:init, project_root, '--name=MonkeyButler'])
|
130
|
+
path = File.join(project_root, '.git')
|
131
|
+
expect(File.exists?(path)).to be_true
|
132
|
+
end
|
133
|
+
|
134
|
+
def stub_bundler
|
135
|
+
MonkeyButler::CLI.any_instance.stub(:bundle) do
|
136
|
+
File.open(File.join(project_root, 'Gemfile.lock'), 'w')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context "when --bundler option is given" do
|
141
|
+
before(:each) do
|
142
|
+
stub_bundler
|
143
|
+
end
|
144
|
+
|
145
|
+
it "creates a Gemfile" do
|
146
|
+
invoke!([:init, project_root, '--bundler'])
|
147
|
+
path = File.join(project_root, 'Gemfile')
|
148
|
+
expect(File.exists?(path)).to be_true
|
149
|
+
end
|
150
|
+
|
151
|
+
it "omits the option from the YAML" do
|
152
|
+
invoke!([:init, project_root, '--bundler'])
|
153
|
+
project = YAML.load File.read(File.join(project_root, '.monkey_butler.yml'))
|
154
|
+
expect(project['bundler']).to be_nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "when --targets option is given" do
|
159
|
+
context "when cocoapods is specified" do
|
160
|
+
it "informs the user that the targets are being initialized" do
|
161
|
+
output = invoke!([:init, project_root, "--config", 'cocoapods.repo:whatever', '--pretend', '--targets', 'cocoapods'])
|
162
|
+
output[:stdout].should =~ /Initializing target 'cocoapods'.../
|
163
|
+
end
|
164
|
+
|
165
|
+
it "writes any changes written to the config back to the file" do
|
166
|
+
expect(Thor::LineEditor).to receive(:readline).with("What is the name of your Cocoapods specs repo? ", {}).and_return("layerhq")
|
167
|
+
invoke!([:init, project_root, '--targets', 'cocoapods'])
|
168
|
+
project = YAML.load File.read(File.join(project_root, '.monkey_butler.yml'))
|
169
|
+
expect(project['config']['cocoapods.repo']).to eql('layerhq')
|
170
|
+
end
|
171
|
+
|
172
|
+
context "when --bundler is given" do
|
173
|
+
it "appends CocoaPods to the Gemfile" do
|
174
|
+
stub_bundler
|
175
|
+
invoke!([:init, project_root, "--config", 'cocoapods.repo:whatever', '--bundler', '--targets', 'cocoapods'])
|
176
|
+
gemfile_content = File.read(File.join(project_root, 'Gemfile'))
|
177
|
+
gemfile_content.should =~ /gem 'cocoapods'/
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe MonkeyButler::CLI do
|
187
|
+
let!(:project_root) { clone_temp_sandbox }
|
188
|
+
let(:project) { MonkeyButler::Project.load(project_root) }
|
189
|
+
let(:schema_path) { File.join(project_root, project.schema_path) }
|
190
|
+
|
191
|
+
def add_migration(sql, ext = '.sql')
|
192
|
+
path = File.join(project_root, 'migrations', random_migration_name + ext)
|
193
|
+
File.open(path, 'w+') do |f|
|
194
|
+
f << sql
|
195
|
+
end
|
196
|
+
File.basename(path)
|
197
|
+
end
|
198
|
+
|
199
|
+
def create_sandbox_migration_path
|
200
|
+
Dir.entries(File.join(project_root, 'migrations')).detect { |f| f =~ /create_sandbox\.sql/ }
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '#load' do
|
204
|
+
context "when the schema is empty" do
|
205
|
+
before(:each) do
|
206
|
+
File.truncate(schema_path, 0)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "fails with an error" do
|
210
|
+
output = invoke!(%w{load})
|
211
|
+
output[:stderr].should =~ /Cannot load database: empty schema found at/
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "when the schema contains invalid SQL" do
|
216
|
+
before(:each) do
|
217
|
+
@timestamp = MonkeyButler::Util.migration_timestamp
|
218
|
+
sql = <<-SQL
|
219
|
+
CREATE TABLE this_is_invalid;
|
220
|
+
SQL
|
221
|
+
File.open(schema_path, 'w+') do |f|
|
222
|
+
f << MonkeyButler::Util.strip_leading_whitespace(sql)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
it "fails with an error" do
|
227
|
+
output = invoke!(%w{load})
|
228
|
+
output[:stderr].should =~ /Failed loading schema: Error: near line 1: near ";": syntax error/
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context "when the schema is populated" do
|
233
|
+
before(:each) do
|
234
|
+
@timestamp = MonkeyButler::Util.migration_timestamp
|
235
|
+
sql = <<-SQL
|
236
|
+
#{MonkeyButler::Databases::SqliteDatabase.create_schema_migrations_sql}
|
237
|
+
INSERT INTO schema_migrations(version) VALUES ('#{@timestamp}');
|
238
|
+
SQL
|
239
|
+
File.open(schema_path, 'w+') do |f|
|
240
|
+
f << MonkeyButler::Util.strip_leading_whitespace(sql)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
it "loads without error" do
|
245
|
+
output = invoke!(%w{load})
|
246
|
+
output[:stdout].should =~ /executing sqlite3 sandbox.sqlite < sandbox.sql/
|
247
|
+
output[:stderr].should be_empty
|
248
|
+
end
|
249
|
+
|
250
|
+
it "reports the current version of the database" do
|
251
|
+
output = invoke!(%w{load})
|
252
|
+
output[:stdout].should =~ /Loaded schema at version #{@timestamp}/
|
253
|
+
end
|
254
|
+
|
255
|
+
context "when a database argument is given" do
|
256
|
+
it "loads into the specified database" do
|
257
|
+
db_path = Tempfile.new('specific.db').path
|
258
|
+
output = invoke!(%W{load -d #{db_path}})
|
259
|
+
output[:stdout].should_not =~ /truncate sandbox.sqlite/
|
260
|
+
output[:stdout].should =~ /executing sqlite3 #{db_path} < sandbox.sql/
|
261
|
+
output[:stdout].should =~ /Loaded schema at version #{@timestamp}/
|
262
|
+
output[:stderr].should be_empty
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def sqlite_url_for_path(path)
|
269
|
+
URI("sqlite://#{path}")
|
270
|
+
end
|
271
|
+
|
272
|
+
describe "#migrate" do
|
273
|
+
before(:each) do
|
274
|
+
@migration_paths = [
|
275
|
+
create_sandbox_migration_path,
|
276
|
+
add_migration('CREATE TABLE table1 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);'),
|
277
|
+
add_migration('CREATE TABLE table2 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);'),
|
278
|
+
add_migration('CREATE TABLE table3 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
279
|
+
]
|
280
|
+
end
|
281
|
+
|
282
|
+
context "when the database is empty" do
|
283
|
+
context "when a database argument is given" do
|
284
|
+
it "applies all migrations to the specified database" do
|
285
|
+
db_path = Tempfile.new('specific.db').path
|
286
|
+
output = invoke!(%W{migrate -d #{db_path}})
|
287
|
+
|
288
|
+
db = MonkeyButler::Databases::SqliteDatabase.new(sqlite_url_for_path(db_path))
|
289
|
+
expected_versions = MonkeyButler::Util.migrations_by_version(@migration_paths).keys.sort
|
290
|
+
target_version = expected_versions.max
|
291
|
+
expect(db.current_version).to eql(target_version)
|
292
|
+
expect(db.all_versions).to eql(expected_versions)
|
293
|
+
end
|
294
|
+
|
295
|
+
context "when the dump option is given" do
|
296
|
+
it "dumps the database after migrations" do
|
297
|
+
db_path = Tempfile.new('specific.db').path
|
298
|
+
File.truncate(schema_path, 0)
|
299
|
+
output = invoke!(%W{migrate -d #{db_path} --dump})
|
300
|
+
output[:stdout].should =~ /Dumping schema from database/
|
301
|
+
File.size(schema_path).should_not == 0
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
it "applies all migrations" do
|
307
|
+
output = invoke!(%w{migrate})
|
308
|
+
|
309
|
+
db = MonkeyButler::Databases::SqliteDatabase.new(sqlite_url_for_path(project_root + '/sandbox.sqlite'))
|
310
|
+
expected_versions = MonkeyButler::Util.migrations_by_version(@migration_paths).keys.sort
|
311
|
+
target_version = expected_versions.max
|
312
|
+
expect(db.current_version).to eql(target_version)
|
313
|
+
expect(db.all_versions).to eql(expected_versions)
|
314
|
+
end
|
315
|
+
|
316
|
+
it "informs the user of target version" do
|
317
|
+
output = invoke!(%w{migrate})
|
318
|
+
expected_versions = MonkeyButler::Util.migrations_by_version(@migration_paths).keys.sort
|
319
|
+
target_version = expected_versions.max
|
320
|
+
output[:stdout].should =~ %r{Migrating new database to #{target_version}}
|
321
|
+
end
|
322
|
+
|
323
|
+
it "informs the user of all migrations applied" do
|
324
|
+
output = invoke!(%w{migrate})
|
325
|
+
output[:stdout].should =~ /Migrating database.../
|
326
|
+
@migration_paths.each do |path|
|
327
|
+
output[:stdout].should =~ %r{applying migration:\s+migrations\/#{path}}
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
it "displays migraiton complete message" do
|
332
|
+
output = invoke!(%w{migrate})
|
333
|
+
expected_versions = MonkeyButler::Util.migrations_by_version(@migration_paths).keys.sort
|
334
|
+
target_version = expected_versions.max
|
335
|
+
output[:stdout].should =~ /Migration to version #{target_version} complete./
|
336
|
+
end
|
337
|
+
|
338
|
+
pending "dumps the schema and schema_migrations rows"
|
339
|
+
pending "adds the schema file to the Git staging area"
|
340
|
+
end
|
341
|
+
|
342
|
+
context "when the database is up to date" do
|
343
|
+
before(:each) do
|
344
|
+
versions = MonkeyButler::Util.migration_versions_from_paths(@migration_paths)
|
345
|
+
database = MonkeyButler::Databases::SqliteDatabase.create(sqlite_url_for_path(project_root + '/sandbox.sqlite'))
|
346
|
+
versions.each { |version| database.insert_version(version) }
|
347
|
+
end
|
348
|
+
|
349
|
+
it "informs the user the database is up to date" do
|
350
|
+
output = invoke!(%w{migrate})
|
351
|
+
output[:stdout].should =~ /Database is up to date./
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
context "when some migrations have been applied" do
|
356
|
+
before(:each) do
|
357
|
+
versions = MonkeyButler::Util.migration_versions_from_paths(@migration_paths)
|
358
|
+
database = MonkeyButler::Databases::SqliteDatabase.create(sqlite_url_for_path(project_root + '/sandbox.sqlite'))
|
359
|
+
@current_version = versions.first
|
360
|
+
database.insert_version(@current_version)
|
361
|
+
end
|
362
|
+
|
363
|
+
it "displays the current version of the database" do
|
364
|
+
output = invoke!(%w{migrate})
|
365
|
+
expected_versions = MonkeyButler::Util.migrations_by_version(@migration_paths).keys.sort
|
366
|
+
target_version = expected_versions.max
|
367
|
+
output[:stdout].should =~ %r{Migrating from #{@current_version} to #{target_version}}
|
368
|
+
end
|
369
|
+
|
370
|
+
it "displays the migrations to be applied" do
|
371
|
+
output = invoke!(%w{migrate})
|
372
|
+
output[:stdout].should =~ /Migrating database/
|
373
|
+
@migration_paths[1,3].each do |path|
|
374
|
+
output[:stdout].should =~ %r{applying migration:\s+migrations\/#{path}}
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
describe '#status' do
|
381
|
+
before(:each) do
|
382
|
+
@migration_paths = [
|
383
|
+
create_sandbox_migration_path,
|
384
|
+
add_migration('CREATE TABLE table1 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);'),
|
385
|
+
add_migration('CREATE TABLE table2 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);'),
|
386
|
+
add_migration('CREATE TABLE table3 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
387
|
+
]
|
388
|
+
end
|
389
|
+
|
390
|
+
context "when the database is up to date" do
|
391
|
+
before(:each) do
|
392
|
+
versions = MonkeyButler::Util.migration_versions_from_paths(@migration_paths)
|
393
|
+
path = project_root + '/sandbox.sqlite'
|
394
|
+
uri = URI("sqlite://#{path}")
|
395
|
+
database = MonkeyButler::Databases::SqliteDatabase.create(uri)
|
396
|
+
versions.each { |version| database.insert_version(version) }
|
397
|
+
end
|
398
|
+
|
399
|
+
it "displays the current version" do
|
400
|
+
output = invoke!(%w{status})
|
401
|
+
output[:stdout].should =~ /Current version\:/
|
402
|
+
end
|
403
|
+
|
404
|
+
it "displays up to date status" do
|
405
|
+
output = invoke!(%w{status})
|
406
|
+
output[:stdout].should =~ /Database is up to date./
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
context "when the database is empty" do
|
411
|
+
it "informs the user the database is missing the schema migrations table" do
|
412
|
+
output = invoke!(%w{status})
|
413
|
+
output[:stdout].should =~ /New database/
|
414
|
+
output[:stdout].should =~ /The database at 'sandbox.sqlite' does not have a 'schema_migrations' table./
|
415
|
+
end
|
416
|
+
|
417
|
+
it "displays the migrations to be applied" do
|
418
|
+
output = invoke!(%w{status})
|
419
|
+
output[:stdout].should =~ /Migrations to be applied/
|
420
|
+
output[:stdout].should =~ /\(use "mb migrate" to apply\)/
|
421
|
+
@migration_paths.each do |path|
|
422
|
+
output[:stdout].should =~ %r{pending migration:\s+migrations\/#{path}}
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
context "when there are unapplied migrations" do
|
428
|
+
before(:each) do
|
429
|
+
versions = MonkeyButler::Util.migration_versions_from_paths(@migration_paths)
|
430
|
+
path = project_root + '/sandbox.sqlite'
|
431
|
+
uri = URI("sqlite://#{path}")
|
432
|
+
database = MonkeyButler::Databases::SqliteDatabase.create(uri)
|
433
|
+
@current_version = versions.first
|
434
|
+
database.insert_version(@current_version)
|
435
|
+
end
|
436
|
+
|
437
|
+
it "displays the current version of the database" do
|
438
|
+
output = invoke!(%w{status})
|
439
|
+
output[:stdout].should =~ %r{Current version: #{@current_version}}
|
440
|
+
end
|
441
|
+
|
442
|
+
it "displays the migrations to be applied" do
|
443
|
+
output = invoke!(%w{status})
|
444
|
+
output[:stdout].should =~ /The database at 'sandbox.sqlite' is 3 versions behind /
|
445
|
+
output[:stdout].should =~ /Migrations to be applied/
|
446
|
+
output[:stdout].should =~ /\(use "mb migrate" to apply\)/
|
447
|
+
@migration_paths[1,3].each do |path|
|
448
|
+
output[:stdout].should =~ %r{pending migration:\s+migrations\/#{path}}
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
describe '#validate' do
|
455
|
+
before(:each) do
|
456
|
+
sql = MonkeyButler::Util.strip_leading_whitespace <<-SQL
|
457
|
+
#{MonkeyButler::Databases::SqliteDatabase.create_schema_migrations_sql}
|
458
|
+
INSERT INTO schema_migrations(version) VALUES ('#{MonkeyButler::Util.migration_timestamp}');
|
459
|
+
SQL
|
460
|
+
File.open(schema_path, 'w+') { |f| f << sql }
|
461
|
+
add_migration('CREATE TABLE table1 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
462
|
+
add_migration('CREATE TABLE table2 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
463
|
+
end
|
464
|
+
|
465
|
+
context "when there is a schema to and migrations to apply" do
|
466
|
+
it "informs the user validation was successful" do
|
467
|
+
output = invoke!(%w{validate})
|
468
|
+
output[:stdout].should =~ /Validation successful./
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
context "when the git url is not configured" do
|
473
|
+
before(:each) do
|
474
|
+
Dir.chdir(project_root) do
|
475
|
+
system("git remote remove origin")
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
it "fails with error" do
|
480
|
+
output = invoke!(['validate'])
|
481
|
+
output[:stderr].should =~ /Invalid configuration: git does not have a remote named 'origin'./
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe '#new' do
|
487
|
+
# TODO: The only test here should be that a dummy database adapter was invoked....
|
488
|
+
context "when using a SQLite database" do
|
489
|
+
it "generates a new migration with the given name" do
|
490
|
+
invoke!(%w{new add_column_to_table})
|
491
|
+
migration = Dir.entries(File.join(project_root, 'migrations')).detect { |f| f =~ /add_column_to_table\.sql/ }
|
492
|
+
migration.should_not be_nil
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
context "when using a Cassandra database" do
|
497
|
+
it "generates a migration"
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
describe '#generate' do
|
502
|
+
before(:each) do
|
503
|
+
sql = MonkeyButler::Util.strip_leading_whitespace <<-SQL
|
504
|
+
#{MonkeyButler::Databases::SqliteDatabase.create_schema_migrations_sql}
|
505
|
+
INSERT INTO schema_migrations(version) VALUES ('#{MonkeyButler::Util.migration_timestamp}');
|
506
|
+
SQL
|
507
|
+
File.open(schema_path, 'w+') { |f| f << sql }
|
508
|
+
add_migration('CREATE TABLE table1 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
509
|
+
add_migration('CREATE TABLE table2 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
510
|
+
end
|
511
|
+
|
512
|
+
context "when no target option is not given" do
|
513
|
+
it "invokes the default targets for the project" do
|
514
|
+
output = invoke!(%w{generate})
|
515
|
+
output[:stdout].should =~ /Invoking target 'cocoapods'/
|
516
|
+
output[:stdout].should_not =~ /Invoking target 'java'/
|
517
|
+
output[:stderr].should == ""
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
context "when target option is given" do
|
522
|
+
it "invokes the specified targets" do
|
523
|
+
output = invoke!(%w{generate -t maven})
|
524
|
+
output[:stdout].should =~ /Invoking target 'maven'/
|
525
|
+
output[:stdout].should_not =~ /Invoking target 'cocoapods'/
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
describe '#package' do
|
531
|
+
before(:each) do
|
532
|
+
sql = MonkeyButler::Util.strip_leading_whitespace <<-SQL
|
533
|
+
#{MonkeyButler::Databases::SqliteDatabase.create_schema_migrations_sql}
|
534
|
+
INSERT INTO schema_migrations(version) VALUES ('#{MonkeyButler::Util.migration_timestamp}');
|
535
|
+
SQL
|
536
|
+
File.open(schema_path, 'w+') { |f| f << sql }
|
537
|
+
add_migration('CREATE TABLE table1 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
538
|
+
add_migration('CREATE TABLE table2 (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);')
|
539
|
+
end
|
540
|
+
|
541
|
+
def stub_questions
|
542
|
+
Thor::LineEditor.stub(:readline).and_return("n")
|
543
|
+
end
|
544
|
+
|
545
|
+
it "invokes validation" do
|
546
|
+
stub_questions
|
547
|
+
output = invoke!(%w{package --pretend})
|
548
|
+
output[:stdout].should =~ /Validation successful/
|
549
|
+
end
|
550
|
+
|
551
|
+
it "invokes generation" do
|
552
|
+
stub_questions
|
553
|
+
output = invoke!(%w{package --pretend})
|
554
|
+
output[:stdout].should =~ /Invoking target 'cocoapods'/
|
555
|
+
end
|
556
|
+
|
557
|
+
it "adds the project to git" do
|
558
|
+
stub_questions
|
559
|
+
output = invoke!(%w{package --pretend})
|
560
|
+
output[:stdout].should =~ /git add . from "."/
|
561
|
+
end
|
562
|
+
|
563
|
+
it "runs git status" do
|
564
|
+
stub_questions
|
565
|
+
output = invoke!(%w{package --pretend})
|
566
|
+
output[:stdout].should =~ /git status from "."/
|
567
|
+
end
|
568
|
+
|
569
|
+
describe "diff" do
|
570
|
+
context "when no diff option is given" do
|
571
|
+
it "asks if you want to see the diff" do
|
572
|
+
expect(Thor::LineEditor).to receive(:readline).with("Review package diff? [y, n] ", {:limited_to=>["y", "n"]}).and_return("n")
|
573
|
+
stub_questions
|
574
|
+
output = invoke!(%w{package --pretend})
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
context "when --diff is specified" do
|
579
|
+
it "shows the diff" do
|
580
|
+
stub_questions
|
581
|
+
output = invoke!(%w{package --pretend --diff})
|
582
|
+
output[:stdout].should =~ /git diff --cached from "."/
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
context "when --no-diff is specified" do
|
587
|
+
it "should not ask to review the diff" do
|
588
|
+
expect(Thor::LineEditor).not_to receive(:readline).with("Review package diff? [y, n] ", {:limited_to=>["y", "n"]})
|
589
|
+
stub_questions
|
590
|
+
output = invoke!(%w{package --pretend --no-diff})
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
describe "commit" do
|
596
|
+
context "when no commit option is given" do
|
597
|
+
it "asks if you want to commit" do
|
598
|
+
expect(Thor::LineEditor).to receive(:readline).with("Commit package artifacts? [y, n] ", {:limited_to=>["y", "n"]}).and_return("n")
|
599
|
+
stub_questions
|
600
|
+
output = invoke!(%w{package --pretend})
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
context "when --commit is specified" do
|
605
|
+
it "commits the changes" do
|
606
|
+
stub_questions
|
607
|
+
output = invoke!(%w{package --pretend --commit})
|
608
|
+
output[:stdout].should =~ /git commit -m 'Packaging release/
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
context "when --no-commit is specified" do
|
613
|
+
it "commits the changes" do
|
614
|
+
expect(Thor::LineEditor).not_to receive(:readline).with("Commit package artifacts? [y, n] ", {:limited_to=>["y", "n"]})
|
615
|
+
stub_questions
|
616
|
+
output = invoke!(%w{package --pretend --no-commit})
|
617
|
+
output[:stdout].should_not =~ /git commit -m 'Packaging release/
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
it "tags a release for the latest version" do
|
622
|
+
db = MonkeyButler::Databases::SqliteDatabase.new(sqlite_url_for_path(project_root + '/sandbox.sqlite'))
|
623
|
+
migrations = MonkeyButler::Migrations.new(project_root + '/migrations', db)
|
624
|
+
|
625
|
+
stub_questions
|
626
|
+
output = invoke!(%w{package --pretend --commit})
|
627
|
+
output[:stdout].should =~ /git tag #{migrations.latest_version}/
|
628
|
+
end
|
629
|
+
|
630
|
+
context "when a tag for the version already exists" do
|
631
|
+
it "tags a point release" do
|
632
|
+
db = MonkeyButler::Databases::SqliteDatabase.new(URI(project_root + '/sandbox.sqlite'))
|
633
|
+
migrations = MonkeyButler::Migrations.new(project_root + '/migrations', db)
|
634
|
+
Dir.chdir(project_root) do
|
635
|
+
`echo '' > foo`
|
636
|
+
`git add foo && git commit -m 'fake commit' .`
|
637
|
+
`git tag #{migrations.latest_version}`
|
638
|
+
end
|
639
|
+
point_release = "#{migrations.latest_version}.1"
|
640
|
+
|
641
|
+
stub_questions
|
642
|
+
output = invoke!(%w{package --commit --quiet})
|
643
|
+
Dir.chdir(project_root) do
|
644
|
+
project.git_latest_tag.should == point_release
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
describe '#push' do
|
652
|
+
it "pushes to git" do
|
653
|
+
output = invoke!(%w{push --pretend})
|
654
|
+
output[:stdout].should =~ /git push origin master --tags/
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
describe "#config" do
|
659
|
+
before(:each) do
|
660
|
+
project = MonkeyButler::Project.load(project_root)
|
661
|
+
project.config['this'] = 'that'
|
662
|
+
project.config['option'] = 'value'
|
663
|
+
end
|
664
|
+
|
665
|
+
context "when called with no arguments" do
|
666
|
+
it "enumerates all config variables" do
|
667
|
+
output = invoke!(%w{config})
|
668
|
+
output[:stdout].should =~ /this=that/
|
669
|
+
output[:stdout].should =~ /option=value/
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
context "when called with one argument" do
|
674
|
+
it "reads the value for that option" do
|
675
|
+
output = invoke!(%w{config this})
|
676
|
+
output[:stdout].should =~ /this=that/
|
677
|
+
output[:stdout].should_not =~ /option=value/
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
context "when called with two arguments" do
|
682
|
+
it "sets the value for the specified option" do
|
683
|
+
invoke!(%w{config this value})
|
684
|
+
yaml = YAML.load(File.read(File.join(project_root, '.monkey_butler.yml')))
|
685
|
+
yaml['config']['this'].should == 'value'
|
686
|
+
end
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
describe MonkeyButler::CLI, "#target integration" do
|
692
|
+
let!(:project_root) { clone_temp_sandbox }
|
693
|
+
|
694
|
+
context "when the current directory has a monkey_butler.yml file" do
|
695
|
+
it "allows the database target to register options" do
|
696
|
+
output = invoke!(%w{help dump})
|
697
|
+
output[:stdout].should =~ /#{Regexp.escape "-d, [--database=DATABASE] # Set target DATABASE"}/
|
698
|
+
end
|
699
|
+
end
|
700
|
+
end
|