crafterm-sprinkle 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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