crafterm-sprinkle 0.1.5 → 0.1.6

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.
Files changed (45) hide show
  1. data/CREDITS +2 -1
  2. data/Manifest.txt +11 -2
  3. data/{README.rdoc → README.txt} +25 -5
  4. data/bin/sprinkle +7 -0
  5. data/config/hoe.rb +2 -2
  6. data/examples/rails/rails.rb +4 -2
  7. data/lib/sprinkle.rb +8 -2
  8. data/lib/sprinkle/actors/actors.rb +17 -0
  9. data/lib/sprinkle/actors/capistrano.rb +41 -4
  10. data/lib/sprinkle/actors/vlad.rb +39 -4
  11. data/lib/sprinkle/configurable.rb +31 -0
  12. data/lib/sprinkle/deployment.rb +46 -6
  13. data/lib/sprinkle/extensions/arbitrary_options.rb +1 -1
  14. data/lib/sprinkle/extensions/array.rb +1 -3
  15. data/lib/sprinkle/extensions/blank_slate.rb +1 -1
  16. data/lib/sprinkle/extensions/dsl_accessor.rb +1 -1
  17. data/lib/sprinkle/extensions/string.rb +1 -1
  18. data/lib/sprinkle/extensions/symbol.rb +1 -1
  19. data/lib/sprinkle/installers/apt.rb +33 -6
  20. data/lib/sprinkle/installers/gem.rb +34 -6
  21. data/lib/sprinkle/installers/installer.rb +64 -29
  22. data/lib/sprinkle/installers/rake.rb +15 -2
  23. data/lib/sprinkle/installers/rpm.rb +20 -3
  24. data/lib/sprinkle/installers/source.rb +74 -16
  25. data/lib/sprinkle/package.rb +127 -2
  26. data/lib/sprinkle/policy.rb +42 -2
  27. data/lib/sprinkle/script.rb +11 -1
  28. data/lib/sprinkle/verifiers/directory.rb +16 -0
  29. data/lib/sprinkle/verifiers/executable.rb +36 -0
  30. data/lib/sprinkle/verifiers/file.rb +20 -0
  31. data/lib/sprinkle/verifiers/process.rb +21 -0
  32. data/lib/sprinkle/verifiers/ruby.rb +25 -0
  33. data/lib/sprinkle/verifiers/symlink.rb +30 -0
  34. data/lib/sprinkle/verify.rb +114 -0
  35. data/lib/sprinkle/version.rb +1 -1
  36. data/spec/sprinkle/actors/capistrano_spec.rb +21 -1
  37. data/spec/sprinkle/configurable_spec.rb +46 -0
  38. data/spec/sprinkle/installers/apt_spec.rb +1 -5
  39. data/spec/sprinkle/installers/gem_spec.rb +1 -1
  40. data/spec/sprinkle/installers/installer_spec.rb +55 -29
  41. data/spec/sprinkle/package_spec.rb +137 -0
  42. data/spec/sprinkle/verify_spec.rb +160 -0
  43. data/sprinkle.gemspec +6 -6
  44. metadata +17 -4
  45. data/examples/merb/deploy.rb +0 -5
@@ -2,7 +2,7 @@ module Sprinkle #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 5
5
+ TINY = 6
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -99,6 +99,8 @@ describe Sprinkle::Actors::Capistrano do
99
99
 
100
100
  @cap = create_cap do; recipes 'deploy'; end
101
101
  @cap.stub!(:run).and_return
102
+
103
+ @testing_errors = false
102
104
  end
103
105
 
104
106
  it 'should dynamically create a capistrano task containing the commands' do
@@ -108,9 +110,27 @@ describe Sprinkle::Actors::Capistrano do
108
110
  it 'should invoke capistrano task after creation' do
109
111
  @cap.should_receive(:run).with(@name).and_return
110
112
  end
113
+
114
+ it 'should raise capistrano errors when suppressing parameter is not set' do
115
+ @testing_errors = true
116
+
117
+ @cap.should_receive(:run).and_raise(::Capistrano::CommandError)
118
+ lambda { @cap.process @name, @commands, @roles }.should raise_error(::Capistrano::CommandError)
119
+ end
120
+
121
+ it 'should not raise errors and instead return false when suppressing parameter is set' do
122
+ @testing_errors = true
123
+
124
+ @cap.should_receive(:run).and_raise(::Capistrano::CommandError)
125
+
126
+ value = nil
127
+ lambda { value = @cap.process(@name, @commands, @roles, true) }.should_not raise_error(::Capistrano::CommandError)
128
+
129
+ value.should_not be
130
+ end
111
131
 
112
132
  after do
113
- @cap.process @name, @commands, @roles
133
+ @cap.process @name, @commands, @roles unless @testing_errors
114
134
  end
115
135
 
116
136
  end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sprinkle::Configurable do
4
+ module MyPrefix
5
+ class Configurable
6
+ include Sprinkle::Configurable
7
+ end
8
+ end
9
+
10
+ before do
11
+ @configurable = MyPrefix::Configurable.new
12
+ @default = Proc.new { }
13
+ @defaults = { :configurable => @default }
14
+ @deployment.stub!(:defaults).and_return(@defaults)
15
+ @deployment.stub!(:style)
16
+ end
17
+
18
+ it 'should be configurable via external defaults' do
19
+ @configurable.should respond_to(:defaults)
20
+ end
21
+
22
+ it 'should select the defaults for the particular concrete installer class' do
23
+ @deployment.should_receive(:defaults).and_return(@defaults)
24
+ @defaults.should_receive(:[]).with(:configurable).and_return(@default)
25
+ end
26
+
27
+ it 'should configure the installer delivery mechansim' do
28
+ @configurable.should_receive(:instance_eval)
29
+ end
30
+
31
+ it 'should maintain an options hash set arbitrarily via method missing' do
32
+ @configurable.instance_eval do
33
+ hsv 'gts'
34
+ end
35
+ @configurable.hsv.should == 'gts'
36
+ end
37
+
38
+ it 'should allow the delivery instance variable to be accessed' do
39
+ @configurable.delivery = "string"
40
+ @configurable.instance_variable_get(:@delivery).should eql("string")
41
+ end
42
+
43
+ after do
44
+ @configurable.defaults(@deployment)
45
+ end
46
+ end
@@ -22,10 +22,6 @@ describe Sprinkle::Installers::Apt do
22
22
  @installer.packages.should == ['gcc', 'gdb', 'g++']
23
23
  end
24
24
 
25
- end
26
-
27
- describe 'when created for dependencies only install' do
28
-
29
25
  it 'should remove options from packages list' do
30
26
  @installer = create_apt 'ruby', :dependencies_only => true
31
27
  @installer.packages.should == [ 'ruby' ]
@@ -62,7 +58,7 @@ describe Sprinkle::Installers::Apt do
62
58
  describe 'during dependencies only installation' do
63
59
 
64
60
  before do
65
- @installer = create_apt 'ruby', :dependencies_only => true
61
+ @installer = create_apt('ruby') { dependencies_only true }
66
62
  @install_commands = @installer.send :install_commands
67
63
  end
68
64
 
@@ -69,7 +69,7 @@ describe Sprinkle::Installers::Gem do
69
69
  end
70
70
 
71
71
  end
72
-
72
+
73
73
  end
74
74
 
75
75
  end
@@ -53,37 +53,10 @@ describe Sprinkle::Installers::Installer do
53
53
  end
54
54
 
55
55
  describe 'during configuration' do
56
-
57
- before do
58
- @default = Proc.new { }
59
- @defaults = { :installer => @default }
60
- @deployment.stub!(:defaults).and_return(@defaults)
61
- end
62
-
63
- it 'should be configurable via external defaults' do
56
+ # We just check to make sure it has the Sprinkle::Configurable method
57
+ it 'should be configurable' do
64
58
  @installer.should respond_to(:defaults)
65
59
  end
66
-
67
- it 'should select the defaults for the particular concrete installer class' do
68
- @deployment.should_receive(:defaults).and_return(@defaults)
69
- @defaults.should_receive(:[]).with(:installer).and_return(@default)
70
- end
71
-
72
- it 'should configure the installer delivery mechansim' do
73
- @installer.should_receive(:instance_eval)
74
- end
75
-
76
- it 'should maintain an options hash set arbitrarily via method missing' do
77
- @installer.instance_eval do
78
- hsv 'gts'
79
- end
80
- @installer.hsv.should == 'gts'
81
- end
82
-
83
- after do
84
- @installer.defaults(@deployment)
85
- end
86
-
87
60
  end
88
61
 
89
62
  describe 'during installation' do
@@ -114,6 +87,59 @@ describe Sprinkle::Installers::Installer do
114
87
  @delivery.should_receive(:process).with(@package.name, @sequence, @roles)
115
88
  end
116
89
  end
90
+
91
+ describe "with a pre command" do
92
+
93
+ def create_installer_with_pre_command(cmd="")
94
+ installer = Sprinkle::Installers::Installer.new @package do
95
+ pre :install, cmd
96
+
97
+ def install_commands
98
+ ["installer"]
99
+ end
100
+ end
101
+
102
+ installer.stub!(:puts).and_return
103
+ installer.delivery = @delivery
104
+ installer
105
+ end
106
+ before do
107
+ @installer = create_installer_with_pre_command('run')
108
+ end
109
+ describe "string commands" do
110
+ it "should insert the pre command for the specific package in the installation process" do
111
+ @installer.send(:install_sequence).should == [ 'run', 'installer' ]
112
+ end
113
+ end
114
+ describe "blocks as commands" do
115
+ before(:each) do
116
+ @installer = Sprinkle::Installers::Installer.new @package do
117
+ pre :install do
118
+ %w(a b c)
119
+ end
120
+
121
+ def install_commands
122
+ ["installer"]
123
+ end
124
+ end
125
+
126
+ @installer.stub!(:puts).and_return
127
+ @installer.delivery = @delivery
128
+ end
129
+ it "should be able to store a block if it's the pre command" do
130
+ @installer.send(:install_sequence).should == [ "a", "b", "c", 'installer' ]
131
+ end
132
+ end
133
+ describe "blocks as commands" do
134
+ before(:each) do
135
+ @array = ["a", "b"]
136
+ @installer = create_installer_with_pre_command(@array)
137
+ end
138
+ it "should be able to store a block if it's the pre command" do
139
+ @installer.send(:install_sequence).should == [ @array, 'installer' ].flatten
140
+ end
141
+ end
142
+ end
117
143
 
118
144
  after do
119
145
  @installer.process(@roles)
@@ -26,6 +26,16 @@ describe Sprinkle::Package do
26
26
  }.should change { pre_count }.by(1)
27
27
  CODE
28
28
  end
29
+
30
+ # More of Mitchell's meta-programming to dry up specs.
31
+ def create_package_with_blank_verify(n = 1)
32
+ eval(<<CODE)
33
+ @pkg = package @name do
34
+ gem 'gem'
35
+ #{"verify 'stuff happens' do; end\n" * n}
36
+ end
37
+ CODE
38
+ end
29
39
 
30
40
  describe 'when created' do
31
41
 
@@ -221,8 +231,105 @@ CODE
221
231
  end
222
232
 
223
233
  end
234
+
235
+ describe 'with verifications' do
236
+ before do
237
+ @pkg = create_package_with_blank_verify(3)
238
+ @pkg.installer = @installer
239
+ @installer.stub!(:defaults)
240
+ @installer.stub!(:process)
241
+ end
242
+
243
+ describe 'with forcing' do
244
+ before do
245
+ # Being explicit
246
+ Sprinkle::OPTIONS[:force] = true
247
+ end
248
+
249
+ it 'should process verifications only once' do
250
+ @pkg.should_receive(:process_verifications).once
251
+ @pkg.process(@deployment, @roles)
252
+ end
253
+
254
+ after do
255
+ # Being explicit
256
+ Sprinkle::OPTIONS[:force] = false
257
+ end
258
+ end
259
+
260
+ describe 'without forcing' do
261
+ before do
262
+ # Being explicit
263
+ Sprinkle::OPTIONS[:force] = false
264
+ end
265
+
266
+ it 'should process verifications twice' do
267
+ @pkg.should_receive(:process_verifications).once.with(@deployment, @roles, true).and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
268
+ @pkg.should_receive(:process_verifications).once.with(@deployment, @roles).and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
269
+ end
270
+
271
+ it 'should continue with installation if pre-verification fails' do
272
+ @pkg.should_receive(:process_verifications).twice.and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
273
+ @installer.should_receive(:defaults)
274
+ @installer.should_receive(:process)
275
+ end
276
+
277
+ it 'should only process verifications once and should not process installer if verifications succeed' do
278
+ @pkg.should_receive(:process_verifications).once.and_return(nil)
279
+ @installer.should_not_receive(:defaults)
280
+ @installer.should_not_receive(:process)
281
+ end
282
+
283
+ after do
284
+ begin
285
+ @pkg.process(@deployment, @roles)
286
+ rescue Sprinkle::VerificationFailed => e; end
287
+ end
288
+ end
289
+ end
224
290
 
225
291
  end
292
+
293
+ describe 'when processing verifications' do
294
+ before do
295
+ @deployment = mock(Sprinkle::Deployment)
296
+ @roles = [ :app, :db ]
297
+ @installer = mock(Sprinkle::Installers::Installer, :defaults => true, :process => true)
298
+ @pkg = create_package_with_blank_verify(3)
299
+ @pkg.installer = @installer
300
+ @installer.stub!(:defaults)
301
+ @installer.stub!(:process)
302
+ @logger = mock(ActiveSupport::BufferedLogger, :debug => true, :debug? => true)
303
+ @logger.stub!(:info)
304
+ end
305
+
306
+ it 'should request _each_ verification to configure itself against the deployment context' do
307
+ @pkg.verifications.each do |v|
308
+ v.should_receive(:defaults).with(@deployment).once
309
+ v.stub!(:process)
310
+ end
311
+ end
312
+
313
+ it 'should request _each_ verification to process' do
314
+ @pkg.verifications.each do |v|
315
+ v.stub!(:defaults)
316
+ v.should_receive(:process).with(@roles).once
317
+ end
318
+ end
319
+
320
+ it 'should enter a log info event to notify user whats happening' do
321
+ @pkg.verifications.each do |v|
322
+ v.stub!(:defaults)
323
+ v.stub!(:process)
324
+ end
325
+
326
+ @pkg.should_receive(:logger).once.and_return(@logger)
327
+ end
328
+
329
+ after do
330
+ @pkg.process_verifications(@deployment, @roles)
331
+ end
332
+ end
226
333
 
227
334
  describe 'hierarchies' do
228
335
 
@@ -281,5 +388,35 @@ CODE
281
388
  end
282
389
 
283
390
  end
391
+
392
+ describe 'with verifications' do
393
+ it 'should create a Sprinkle::Verification object for the verify block' do
394
+ Sprinkle::Verify.should_receive(:new).once
395
+
396
+ create_package_with_blank_verify
397
+ end
398
+
399
+ it 'should create multiple Sprinkle::Verification objects for multiple verify blocks' do
400
+ Sprinkle::Verify.should_receive(:new).twice
401
+
402
+ create_package_with_blank_verify(2)
403
+ end
404
+
405
+ it 'should add each Sprinkle::Verificaton object to the @verifications array' do
406
+ @pkg = create_package_with_blank_verify(3)
407
+ @pkg.verifications.length.should eql(3)
408
+ end
409
+
410
+ it 'should initialize Sprinkle::Verification with the package name, description, and block' do
411
+ Sprinkle::Verify.should_receive(:new) do |pkg, desc|
412
+ pkg.name.should eql(@name)
413
+ desc.should eql('stuff happens')
414
+ end
415
+
416
+ # We do a should_not raise_error because if a block was NOT passed, an error
417
+ # is raised. This is specced in verification_spec.rb
418
+ lambda { create_package_with_blank_verify }.should_not raise_error
419
+ end
420
+ end
284
421
 
285
422
  end
@@ -0,0 +1,160 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sprinkle::Verify do
4
+ before do
5
+ @name = :package
6
+ @package = package @name do
7
+ gem 'nonexistent'
8
+ verify 'moo' do
9
+ # Check a file exists
10
+ has_file 'my_file.txt'
11
+
12
+ # Check a directory exists
13
+ has_directory 'mydir'
14
+
15
+ # Check a symlink exists
16
+ has_symlink 'mypointer'
17
+
18
+ # Check a symlink points to a certain file
19
+ has_symlink 'mypointer', 'myfile'
20
+
21
+ # Check if an executable exists
22
+ has_executable '/usr/bin/ruby'
23
+
24
+ # Check if a global executable exists (in PATH)
25
+ has_executable 'rails'
26
+
27
+ # Check for a process
28
+ has_process 'httpd'
29
+
30
+ # Check that ruby can include files
31
+ ruby_can_load 'a', 'b', 'c'
32
+
33
+ # Check that a gem exists
34
+ has_gem 'rails'
35
+ has_gem 'rails', '2.1.0'
36
+ end
37
+ end
38
+ @verification = @package.verifications[0]
39
+ @delivery = mock(Sprinkle::Deployment, :process => true)
40
+ @verification.delivery = @delivery
41
+ end
42
+
43
+ describe 'when created' do
44
+ it 'should raise error without a block' do
45
+ lambda { Verify.new(nil, '') }.should raise_error
46
+ end
47
+ end
48
+
49
+ describe 'with checks' do
50
+ it 'should do a "test -f" on the has_file check' do
51
+ @verification.commands.should include('test -f my_file.txt')
52
+ end
53
+
54
+ it 'should do a "test -d" on the has_directory check' do
55
+ @verification.commands.should include('test -d mydir')
56
+ end
57
+
58
+ it 'should do a "test -L" to check something is a symbolic link' do
59
+ @verification.commands.should include('test -L mypointer')
60
+ end
61
+
62
+ it 'should do a test equality to check a symlink points to a specific file' do
63
+ @verification.commands.should include("test 'myfile' = `readlink mypointer`")
64
+ end
65
+
66
+ it 'should do a "test -x" to check for an executable' do
67
+ @verification.commands.should include("test -x /usr/bin/ruby")
68
+ end
69
+
70
+ it 'should test the "which" command to look for a global executable' do
71
+ @verification.commands.should include('[ -n "`echo \`which rails\``" ]')
72
+ end
73
+
74
+ it 'should test the process list to find a process' do
75
+ @verification.commands.should include("ps aux | grep 'httpd' | grep -v grep")
76
+ end
77
+
78
+ it 'should check if ruby can include a, b, c' do
79
+ @verification.commands.should include("ruby -e \"require 'rubygems';require 'a';require 'b';require 'c'\"")
80
+ end
81
+
82
+ it 'should check that a ruby gem is installed' do
83
+ @verification.commands.should include("sudo gem list | grep -e '^rails (.*.*)$'")
84
+ @verification.commands.should include("sudo gem list | grep -e '^rails (.*2\\.1\\.0.*)$'")
85
+ end
86
+ end
87
+
88
+ describe 'with configurations' do
89
+ # Make sure it includes Sprinkle::Configurable
90
+ it 'should respond to configurable methods' do
91
+ @verification.should respond_to(:defaults)
92
+ end
93
+
94
+ it 'should default padding option to 4' do
95
+ @verification.padding.should eql(4)
96
+ end
97
+ end
98
+
99
+ describe 'with process' do
100
+ it 'should raise an error when no delivery mechanism is set' do
101
+ @verification.instance_variable_set(:@delivery, nil)
102
+ lambda { @verification.process([]) }.should raise_error
103
+ end
104
+
105
+ describe 'when not testing' do
106
+ before do
107
+ # To be explicit
108
+ Sprinkle::OPTIONS[:testing] = false
109
+ end
110
+
111
+ it 'should call process on the delivery with the correct parameters' do
112
+ @delivery.should_receive(:process).with(@name, @verification.commands, [:app], true).once.and_return(true)
113
+ @verification.process([:app])
114
+ end
115
+
116
+ it 'should raise Sprinkle::VerificationFailed exception when commands fail' do
117
+ @delivery.should_receive(:process).once.and_return(false)
118
+ lambda { @verification.process([:app]) }.should raise_error(Sprinkle::VerificationFailed) do |error|
119
+ error.package.should eql(@package)
120
+ error.description.should eql('moo')
121
+ end
122
+ end
123
+ end
124
+
125
+ describe 'when testing' do
126
+ before do
127
+ Sprinkle::OPTIONS[:testing] = true
128
+ @logger = mock(ActiveSupport::BufferedLogger, :debug => true, :debug? => true)
129
+ end
130
+
131
+ it 'should not call process on the delivery' do
132
+ @delivery.should_not_receive(:process)
133
+ end
134
+
135
+ it 'should print the install sequence to the console' do
136
+ @verification.should_receive(:logger).twice.and_return(@logger)
137
+ end
138
+
139
+ after do
140
+ @verification.process([:app])
141
+ Sprinkle::OPTIONS[:testing] = false
142
+ end
143
+ end
144
+ end
145
+
146
+ describe 'with registering new verification modules' do
147
+ module MyModule
148
+ def rawr; end
149
+ end
150
+
151
+ it 'should not respond to rawr initially' do
152
+ @verification.should_not respond_to(:rawr)
153
+ end
154
+
155
+ it 'should respond to rawr after registering the module' do
156
+ Sprinkle::Verify.register(MyModule)
157
+ @verification.should respond_to(:rawr)
158
+ end
159
+ end
160
+ end