fpm-cookery 0.32.0 → 0.33.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +5 -2
- data/CHANGELOG.md +19 -0
- data/Rakefile +34 -0
- data/docs/index.rst +1 -0
- data/docs/pages/using-hiera.rst +285 -0
- data/fpm-cookery.gemspec +6 -1
- data/lib/fpm/cookery/book.rb +29 -2
- data/lib/fpm/cookery/book_hook.rb +1 -0
- data/lib/fpm/cookery/chain_packager.rb +4 -2
- data/lib/fpm/cookery/cli.rb +45 -5
- data/lib/fpm/cookery/config.rb +2 -1
- data/lib/fpm/cookery/environment.rb +17 -8
- data/lib/fpm/cookery/exceptions.rb +3 -1
- data/lib/fpm/cookery/facts.rb +50 -35
- data/lib/fpm/cookery/hiera.rb +35 -0
- data/lib/fpm/cookery/hiera/defaults.rb +50 -0
- data/lib/fpm/cookery/hiera/scope.rb +35 -0
- data/lib/fpm/cookery/inheritable_attr.rb +222 -0
- data/lib/fpm/cookery/log/hiera.rb +21 -0
- data/lib/fpm/cookery/omnibus_packager.rb +4 -2
- data/lib/fpm/cookery/package/package.rb +1 -0
- data/lib/fpm/cookery/package/version.rb +11 -4
- data/lib/fpm/cookery/packager.rb +13 -11
- data/lib/fpm/cookery/recipe.rb +167 -105
- data/lib/fpm/cookery/source.rb +6 -8
- data/lib/fpm/cookery/source_handler.rb +18 -3
- data/lib/fpm/cookery/source_handler/curl.rb +2 -2
- data/lib/fpm/cookery/source_handler/directory.rb +10 -11
- data/lib/fpm/cookery/source_handler/noop.rb +1 -2
- data/lib/fpm/cookery/source_handler/svn.rb +1 -1
- data/lib/fpm/cookery/version.rb +1 -1
- data/lib/hiera/fpm_cookery_logger.rb +12 -0
- data/recipes/redis/config/common.yaml +11 -0
- data/recipes/redis/config/git_2.4.2_tag.yaml +4 -0
- data/recipes/redis/config/git_2.4.yaml +4 -0
- data/recipes/redis/config/git_sha_072a905.yaml +4 -0
- data/recipes/redis/config/svn_r2400.yaml +4 -0
- data/recipes/redis/config/svn_trunk.yaml +3 -0
- data/recipes/redis/recipe.rb +2 -27
- data/spec/book_spec.rb +34 -0
- data/spec/config_spec.rb +19 -0
- data/spec/environment_spec.rb +37 -0
- data/spec/facts_spec.rb +54 -31
- data/spec/fixtures/hiera_config/CentOS.yaml +1 -0
- data/spec/fixtures/hiera_config/common.yaml +12 -0
- data/spec/fixtures/hiera_config/custom.yaml +3 -0
- data/spec/fixtures/hiera_config/rpm.yaml +12 -0
- data/spec/hiera_spec.rb +158 -0
- data/spec/inheritable_attr_spec.rb +202 -0
- data/spec/package_dir_spec.rb +37 -0
- data/spec/package_maintainer_spec.rb +4 -1
- data/spec/package_version_spec.rb +50 -0
- data/spec/path_spec.rb +20 -0
- data/spec/recipe_spec.rb +161 -56
- data/spec/source_integrity_check_spec.rb +7 -6
- data/spec/spec_helper.rb +14 -0
- data/spec/support/shared_context.rb +71 -0
- metadata +108 -4
data/spec/path_spec.rb
CHANGED
@@ -67,6 +67,26 @@ describe "Path" do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
describe "#=~" do
|
71
|
+
let(:path) { FPM::Cookery::Path.new('/bar/baz/quux.txt') }
|
72
|
+
|
73
|
+
context "given a Regexp matching the path" do
|
74
|
+
it "returns the index of the beginning of the the match" do
|
75
|
+
expect(path =~ %r[/\w{4}\.\w{3}]).to eq(8)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "given a non-Regexp argument" do
|
80
|
+
it "raises TypeError" do
|
81
|
+
expect { path =~ 'this' }.to raise_error do |error|
|
82
|
+
expect(error).to be_a(TypeError)
|
83
|
+
expect(error.message).to match(/type\s+mismatch/)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
70
90
|
describe "#mkdir" do
|
71
91
|
it "creates the directory" do
|
72
92
|
dir = Dir.mktmpdir
|
data/spec/recipe_spec.rb
CHANGED
@@ -1,23 +1,28 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'json'
|
3
|
+
require 'fpm/cookery/book'
|
4
|
+
require 'fpm/cookery/book_hook'
|
5
|
+
require 'fpm/cookery/exceptions'
|
6
|
+
require 'fpm/cookery/facts'
|
2
7
|
require 'fpm/cookery/recipe'
|
3
8
|
|
4
|
-
describe "
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
let(:config) do
|
15
|
-
double('Config', :tmp_root => nil, :pkg_dir => nil, :cache_dir => nil).as_null_object
|
9
|
+
describe "BaseRecipe" do
|
10
|
+
[:config, :filename].each do |method_name|
|
11
|
+
describe method_name.to_s do
|
12
|
+
it "informs the caller that it must be implemented at runtime" do
|
13
|
+
expect { FPM::Cookery::BaseRecipe.send(method_name) }.to raise_error do |error|
|
14
|
+
expect(error).to be_a(NotImplementedError)
|
15
|
+
expect(error.message).to match(/must be defined when recipe file is loaded/)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
16
19
|
end
|
20
|
+
end
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
22
|
+
describe "Recipe" do
|
23
|
+
config_options = { :tmp_root => nil, :pkg_dir => nil, :cache_dir => nil,
|
24
|
+
:hiera_config => nil }
|
25
|
+
include_context "recipe class", __FILE__, config_options
|
21
26
|
|
22
27
|
it "sets the filename" do
|
23
28
|
expect(recipe.filename.to_s).to eq(__FILE__)
|
@@ -31,15 +36,26 @@ describe "Recipe" do
|
|
31
36
|
describe "with a relative filename path" do
|
32
37
|
it "expands the workdir path" do
|
33
38
|
filename = "spec/#{File.basename(__FILE__)}"
|
34
|
-
r =
|
39
|
+
r = recipe_klass.new
|
35
40
|
expect(r.workdir.to_s).to eq(File.dirname(__FILE__))
|
36
41
|
end
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
45
|
+
describe "#input" do
|
46
|
+
# Avoid Errno::ENOENT for recipe dir that no longer exists
|
47
|
+
before do
|
48
|
+
allow(config).to receive(:fetch).with(:input, nil).and_return([])
|
49
|
+
end
|
50
|
+
|
51
|
+
it "defaults to FPM::Cookery::Package::Dir" do
|
52
|
+
expect(recipe.input(config)).to be_a(FPM::Cookery::Package::Dir)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
40
56
|
describe "#source_handler" do
|
41
57
|
it "returns the recipe's source handler" do
|
42
|
-
|
58
|
+
recipe_klass.class_eval do
|
43
59
|
source 'http://example.com/foo-1.0.tar.gz', :foo => 'bar'
|
44
60
|
end
|
45
61
|
|
@@ -53,12 +69,18 @@ describe "Recipe" do
|
|
53
69
|
def check_attribute(attr, value, expect = nil)
|
54
70
|
expect ||= value
|
55
71
|
|
56
|
-
|
72
|
+
recipe_klass.send(attr, value)
|
57
73
|
|
58
|
-
expect(
|
74
|
+
expect(recipe_klass.send(attr)).to eq(expect)
|
59
75
|
expect(recipe.send(attr)).to eq(expect)
|
60
76
|
end
|
61
77
|
|
78
|
+
describe '#rpm_dist' do
|
79
|
+
it 'can be set' do
|
80
|
+
check_attribute(:rpm_dist, 'el7')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
62
84
|
describe "#arch" do
|
63
85
|
it "can be set" do
|
64
86
|
check_attribute(:arch, 'i386')
|
@@ -205,18 +227,60 @@ describe "Recipe" do
|
|
205
227
|
end
|
206
228
|
end
|
207
229
|
|
230
|
+
describe "#hiera" do
|
231
|
+
before do
|
232
|
+
allow(config).to receive(:hiera_config).and_return("/probably/does/not/exist/pretty/sure/anyway")
|
233
|
+
end
|
234
|
+
|
235
|
+
it "raises an error when Hiera config file does not exist" do
|
236
|
+
expect { recipe_klass.hiera }.to raise_error do |error|
|
237
|
+
expect(error).to be_an(FPM::Cookery::Error::ExecutionFailure)
|
238
|
+
expect(error.message).to match(/Encountered error loading Hiera/)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#applicator" do
|
244
|
+
context "given an attribute not set in the Hiera data file(s)" do
|
245
|
+
before do
|
246
|
+
allow(recipe_klass).to receive(:lookup).with(:source).and_return(nil)
|
247
|
+
allow(recipe_klass).to receive(:source).and_return('http://www.facsimile.co.uk')
|
248
|
+
end
|
249
|
+
|
250
|
+
it "returns `nil'" do
|
251
|
+
expect(recipe_klass.send(:applicator, :source)).to be_nil
|
252
|
+
end
|
253
|
+
|
254
|
+
it "does not call the provided block" do
|
255
|
+
expect { recipe_klass.send(:applicator, :source) { print "whoa" } }.not_to \
|
256
|
+
output("whoa").to_stdout
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context "given an attribute set in the Hiera data file(s)" do
|
261
|
+
before do
|
262
|
+
allow(recipe_klass).to receive(:lookup).with(:name).and_return('J.J. Jingleheimer-Schmidt IV')
|
263
|
+
end
|
264
|
+
|
265
|
+
it "calls the provided block" do
|
266
|
+
expect { recipe_klass.send(:applicator, :name) { print "whoa" } }.to \
|
267
|
+
output("whoa").to_stdout
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
208
272
|
def self.spec_recipe_attribute_list(name, list)
|
209
273
|
class_eval %Q{
|
210
274
|
describe "##{name}" do
|
211
275
|
it "can be set" do
|
212
|
-
|
276
|
+
recipe_klass.class_eval do
|
213
277
|
#{name} "#{list[0]}"
|
214
278
|
#{name} "#{list[1]}"
|
215
279
|
end
|
216
|
-
expect(
|
280
|
+
expect(recipe_klass.#{name}.size).to eq(#{list.size})
|
217
281
|
expect(recipe.#{name}.size).to eq(#{list.size})
|
218
|
-
expect(
|
219
|
-
expect(
|
282
|
+
expect(recipe_klass.#{name}[0]).to eq("#{list[0]}")
|
283
|
+
expect(recipe_klass.#{name}[1]).to eq("#{list[1]}")
|
220
284
|
expect(recipe.#{name}[0]).to eq("#{list[0]}")
|
221
285
|
expect(recipe.#{name}[1]).to eq("#{list[1]}")
|
222
286
|
end
|
@@ -238,44 +302,44 @@ describe "Recipe" do
|
|
238
302
|
|
239
303
|
describe ".source" do
|
240
304
|
it "sets a source url" do
|
241
|
-
|
305
|
+
recipe_klass.class_eval do
|
242
306
|
source 'http://example.com/foo-1.0.tar.gz'
|
243
307
|
end
|
244
308
|
|
245
|
-
expect(
|
246
|
-
expect(
|
309
|
+
expect(recipe_klass.source).to eq('http://example.com/foo-1.0.tar.gz')
|
310
|
+
expect(recipe_klass.new.source).to eq('http://example.com/foo-1.0.tar.gz')
|
247
311
|
end
|
248
312
|
|
249
313
|
describe "with specs" do
|
250
314
|
it "sets specs" do
|
251
|
-
|
315
|
+
recipe_klass.class_eval do
|
252
316
|
source 'http://example.com/foo-1.0.tar.gz', :foo => 'bar'
|
253
317
|
end
|
254
318
|
|
255
|
-
expect(
|
256
|
-
expect(
|
319
|
+
expect(recipe_klass.spec).to eq({:foo => 'bar'})
|
320
|
+
expect(recipe_klass.new.spec).to eq({:foo => 'bar'})
|
257
321
|
end
|
258
322
|
end
|
259
323
|
end
|
260
324
|
|
261
325
|
describe ".url" do
|
262
326
|
it "sets a source type (homebrew compat)" do
|
263
|
-
|
327
|
+
recipe_klass.class_eval do
|
264
328
|
url 'http://example.com/foo-1.0.tar.gz'
|
265
329
|
end
|
266
330
|
|
267
|
-
expect(
|
268
|
-
expect(
|
331
|
+
expect(recipe_klass.source).to eq('http://example.com/foo-1.0.tar.gz')
|
332
|
+
expect(recipe_klass.new.source).to eq('http://example.com/foo-1.0.tar.gz')
|
269
333
|
end
|
270
334
|
|
271
335
|
describe "with specs" do
|
272
336
|
it "sets specs" do
|
273
|
-
|
337
|
+
recipe_klass.class_eval do
|
274
338
|
url 'http://example.com/foo-1.0.tar.gz', :foo => 'bar'
|
275
339
|
end
|
276
340
|
|
277
|
-
expect(
|
278
|
-
expect(
|
341
|
+
expect(recipe_klass.spec).to eq({:foo => 'bar'})
|
342
|
+
expect(recipe_klass.new.spec).to eq({:foo => 'bar'})
|
279
343
|
end
|
280
344
|
end
|
281
345
|
end
|
@@ -293,18 +357,18 @@ describe "Recipe" do
|
|
293
357
|
|
294
358
|
describe "#local_path" do
|
295
359
|
it "returns the path to the local source file" do
|
296
|
-
|
360
|
+
recipe_klass.class_eval do
|
297
361
|
source 'http://example.com/foo-1.0.tar.gz'
|
298
362
|
end
|
299
363
|
|
300
|
-
expect(File.basename(
|
364
|
+
expect(File.basename(recipe_klass.new.local_path.to_s)).to eq('foo-1.0.tar.gz')
|
301
365
|
end
|
302
366
|
end
|
303
367
|
|
304
368
|
describe ".platforms" do
|
305
369
|
describe "with a list of platforms" do
|
306
370
|
it "allows platform specific settings" do
|
307
|
-
|
371
|
+
recipe_klass.class_eval do
|
308
372
|
def self.platform; :ubuntu; end
|
309
373
|
|
310
374
|
vendor 'a'
|
@@ -314,13 +378,13 @@ describe "Recipe" do
|
|
314
378
|
end
|
315
379
|
end
|
316
380
|
|
317
|
-
expect(
|
381
|
+
expect(recipe_klass.new.vendor).to eq('b')
|
318
382
|
end
|
319
383
|
end
|
320
384
|
|
321
385
|
describe "with a single platform" do
|
322
386
|
it "allows platform specific settings" do
|
323
|
-
|
387
|
+
recipe_klass.class_eval do
|
324
388
|
def self.platform; :ubuntu; end
|
325
389
|
|
326
390
|
vendor 'a'
|
@@ -330,13 +394,13 @@ describe "Recipe" do
|
|
330
394
|
end
|
331
395
|
end
|
332
396
|
|
333
|
-
expect(
|
397
|
+
expect(recipe_klass.new.vendor).to eq('b')
|
334
398
|
end
|
335
399
|
end
|
336
400
|
|
337
401
|
describe "without a matching platform" do
|
338
402
|
it "does not set platform specific stuff" do
|
339
|
-
|
403
|
+
recipe_klass.class_eval do
|
340
404
|
def self.platform; :centos; end
|
341
405
|
|
342
406
|
vendor 'a'
|
@@ -346,7 +410,7 @@ describe "Recipe" do
|
|
346
410
|
end
|
347
411
|
end
|
348
412
|
|
349
|
-
expect(
|
413
|
+
expect(recipe_klass.new.vendor).to eq('a')
|
350
414
|
end
|
351
415
|
end
|
352
416
|
end
|
@@ -360,7 +424,7 @@ describe "Recipe" do
|
|
360
424
|
|
361
425
|
describe "with a list of architectures" do
|
362
426
|
it "allows arch specific settings" do
|
363
|
-
|
427
|
+
recipe_klass.class_eval do
|
364
428
|
vendor 'a'
|
365
429
|
|
366
430
|
architectures [:i386, :x86_64] do
|
@@ -368,13 +432,13 @@ describe "Recipe" do
|
|
368
432
|
end
|
369
433
|
end
|
370
434
|
|
371
|
-
expect(
|
435
|
+
expect(recipe_klass.new.vendor).to eq('b')
|
372
436
|
end
|
373
437
|
end
|
374
438
|
|
375
439
|
describe "with a single architecture" do
|
376
440
|
it "allows arch specific settings" do
|
377
|
-
|
441
|
+
recipe_klass.class_eval do
|
378
442
|
vendor 'a'
|
379
443
|
|
380
444
|
architectures :x86_64 do
|
@@ -382,13 +446,13 @@ describe "Recipe" do
|
|
382
446
|
end
|
383
447
|
end
|
384
448
|
|
385
|
-
expect(
|
449
|
+
expect(recipe_klass.new.vendor).to eq('b')
|
386
450
|
end
|
387
451
|
end
|
388
452
|
|
389
453
|
describe "without a matching architecture" do
|
390
454
|
it "does not set arch specific settings" do
|
391
|
-
|
455
|
+
recipe_klass.class_eval do
|
392
456
|
vendor 'a'
|
393
457
|
|
394
458
|
architectures :i386 do
|
@@ -396,11 +460,16 @@ describe "Recipe" do
|
|
396
460
|
end
|
397
461
|
end
|
398
462
|
|
399
|
-
expect(
|
463
|
+
expect(recipe_klass.new.vendor).to eq('a')
|
400
464
|
end
|
401
465
|
end
|
402
466
|
end
|
403
467
|
|
468
|
+
describe ".platform" do
|
469
|
+
it 'matches the current platform from FPM::Cookery::Facts' do
|
470
|
+
expect(recipe_klass.platform).to eq(FPM::Cookery::Facts.platform)
|
471
|
+
end
|
472
|
+
end
|
404
473
|
|
405
474
|
#############################################################################
|
406
475
|
# Directories
|
@@ -531,25 +600,25 @@ describe "Recipe" do
|
|
531
600
|
|
532
601
|
describe "#depends_all" do
|
533
602
|
it "returns build_depends and depends package names" do
|
534
|
-
|
535
|
-
|
603
|
+
recipe_klass.depends [:pkg1, :pkg2]
|
604
|
+
recipe_klass.build_depends [:pkg3, :pkg4]
|
536
605
|
|
537
606
|
expect([:pkg1, :pkg2, :pkg3, :pkg4].all? { |i|
|
538
|
-
|
607
|
+
recipe_klass.depends_all.member?(i) && recipe.depends_all.member?(i)
|
539
608
|
}).to eq(true)
|
540
609
|
end
|
541
610
|
end
|
542
611
|
|
543
612
|
describe ".fpm_attributes" do
|
544
613
|
it "returns hash object as default" do
|
545
|
-
expect(
|
614
|
+
expect(recipe_klass.fpm_attributes).to be_a(Hash)
|
546
615
|
end
|
547
616
|
|
548
617
|
it "returns same value from instance method with hash assignment" do
|
549
618
|
expect(recipe.fpm_attributes).to include({})
|
550
619
|
|
551
|
-
|
552
|
-
|
620
|
+
recipe_klass.fpm_attributes[:rpm_user] = 'httpd'
|
621
|
+
recipe_klass.fpm_attributes[:deb_user] = 'apache'
|
553
622
|
|
554
623
|
expect(recipe.fpm_attributes).to include({:rpm_user=>'httpd', :deb_user=>'apache'})
|
555
624
|
end
|
@@ -557,9 +626,45 @@ describe "Recipe" do
|
|
557
626
|
it "returns same value from instance method with argument assignment" do
|
558
627
|
expect(recipe.fpm_attributes).to include({})
|
559
628
|
|
560
|
-
|
629
|
+
recipe_klass.fpm_attributes :rpm_user => 'httpd', :deb_user => 'apache'
|
561
630
|
|
562
631
|
expect(recipe.fpm_attributes).to include({:rpm_user=>'httpd', :deb_user=>'apache'})
|
563
632
|
end
|
564
633
|
end
|
634
|
+
|
635
|
+
describe "#to_json" do
|
636
|
+
it "returns a terse JSON-formatted string with recipe attributes" do
|
637
|
+
json = recipe.to_json
|
638
|
+
expect { JSON.load(json) }.not_to raise_error
|
639
|
+
expect(json.lines.to_a.length).to be == 1
|
640
|
+
expect(json).to match(/"name"/)
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
describe "#to_pretty_json" do
|
645
|
+
it "returns a multiline JSON-formatted string with recipe attributes" do
|
646
|
+
json = recipe.to_pretty_json
|
647
|
+
expect { JSON.load(json) }.not_to raise_error
|
648
|
+
expect(json.lines.to_a.length).to be > 1
|
649
|
+
expect(json).to match(/"name"/)
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
describe "#template" do
|
654
|
+
context "given an ERB template containing valid recipe attributes" do
|
655
|
+
it "formats the string with recipe attributes" do
|
656
|
+
formatted = recipe.template("<%= name %>")
|
657
|
+
expect(formatted).to be == recipe.name
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
context "given an ERB template containing invalid recipe attributes" do
|
662
|
+
it "raises an error" do
|
663
|
+
expect { recipe.template("<%= notarecipeattr %>") }.to raise_error do |error|
|
664
|
+
expect(error).to be_an(FPM::Cookery::Error::ExecutionFailure)
|
665
|
+
expect(error.message).to match(/no attribute.*notarecipeattr/)
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
end
|
565
670
|
end
|
@@ -3,14 +3,15 @@ require 'fpm/cookery/source_integrity_check'
|
|
3
3
|
require 'fpm/cookery/recipe'
|
4
4
|
|
5
5
|
describe "SourceIntegrityCheck" do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
config_options = { :hiera_config => nil }
|
7
|
+
include_context "recipe class", __FILE__, config_options do
|
8
|
+
let(:klass) do
|
9
|
+
Class.new(FPM::Cookery::Recipe) {
|
10
|
+
source 'http://example.com/foo.tar.gz'
|
11
|
+
}
|
12
|
+
end
|
10
13
|
end
|
11
14
|
|
12
|
-
let(:config) { double('Config').as_null_object }
|
13
|
-
let(:recipe) { recipe_class.new(__FILE__, config) }
|
14
15
|
let(:check) { FPM::Cookery::SourceIntegrityCheck.new(recipe) }
|
15
16
|
|
16
17
|
before do
|