whiskey_disk 0.5.4 → 0.6.0

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.
data/CHANGELOG ADDED
@@ -0,0 +1,129 @@
1
+
2
+ 0.6.0 / 2010-12-22
3
+ ==================
4
+
5
+ * Version bump to 0.6.0
6
+ * Merge branch 'feature/multiple-domain-support' into develop
7
+ * adding a set of multi-domain examples
8
+ * adding a local deployment example
9
+ * updating output summary to be more readable
10
+ * updating README to document multi-domain deployments
11
+ * rake exit statuses reflect overall deployment/setup success
12
+ * adding WhiskeyDisk.success? method
13
+ * We now summarize runs, both local and remote.
14
+ * record results for local runs as well as remote ones
15
+ * now run SSH commands on multiple domains, serially, synchronously
16
+ * propagating changes allowed by normalizing 'domain' in config data
17
+ * normalize 'domain' values pulled from config files
18
+ * refactor config file writing in config spec
19
+ * WD.remote? now understands arrays of 'domain' entries in the config
20
+ * Merge branch 'release/0.5.4' into develop
21
+ * bump gemspec for 0.5.4 release
22
+ * Version bump to 0.5.4
23
+ * Removing Jeweler warning from Rakefile
24
+ * Merge branch 'feature/reduce-mocking-code-in-tests' into develop
25
+ * eliminating more stubbing specs from config_spec
26
+ * Removing more stub! calls from config specs
27
+ * removing YAML.load exception stub
28
+ * replacing some configuration_data stubs in config spec
29
+ * Remove CURRENT_FILE from config specs
30
+ * Removing CURRENT from config specs
31
+ * Removing more File.exists? stubs from config spec.
32
+ * Removing File.exists? stubs in config specs
33
+ * spec refactorings
34
+ * Removing has_config_repo? stubs from rake specs
35
+ * Using non-stubbed configuration in rake specs
36
+ * removing useless stub of :register_configuration
37
+ * And removing unneeded spec helper
38
+ * removing whiskey_disk config stubbing
39
+ * introducing use_config() spec helper
40
+ * Merge branch 'release/0.5.3' into develop
41
+ * updating gemspec for 0.5.3
42
+ * updating Contributors section of README
43
+ * Version bump to 0.5.3
44
+ * Merge branch 'feature/merge-pull-request-2' into develop
45
+ * Cosmetic and naming change in new config method
46
+ * fixing spec example description
47
+ * Reworking the config to append project name overrides to the env, since everything else is dependent thereupon
48
+ * tidying up the spec
49
+ * Allowing a manually specified project name in the bare config hash to be used as the parent project in the absence of one specified from the 'to' env setting
50
+ * Merge branch 'release/0.5.2' into develop
51
+ * updating gemspec for version 0.5.2
52
+ * Bumping version to 0.5.2
53
+ * Merge branch 'feature/ensure_target_needs_no_ruby' into develop
54
+ * Updating TODO list
55
+ * Updating README
56
+ * Merge branch 'feature/make_check_a_wd_option' into develop
57
+ * Updating TODO list
58
+ * Adding --check flag to wd command-line script
59
+ * Updating README with --check changes
60
+ * Merge branch 'feature/use_shallow_clone_on_setup' into develop
61
+ * Updating TODO list
62
+ * Adding lightning talk info to README
63
+ * Making shallow clones on initial setup
64
+ * Merge branch 'release/0.5.0' into develop
65
+ * updating gemspec for 0.5.0
66
+ * Version bump to 0.5.0
67
+ * Merge branch 'feature/alternate-hook-mechanism' into develop
68
+ * TODO list updates
69
+ * Make the rake test task do right by bacon
70
+ * Adding post_setup_script support
71
+ * Adding post_deploy_script support
72
+ * Reordering specs for post-setup/deployment tasks
73
+ * Updating README for post_*_script functionality
74
+ * TODO file updates
75
+ * Merge branch 'release/0.4.5' into develop
76
+ * new gemspec for 0.4.5 release
77
+ * Version bump to 0.4.5
78
+ * ENV settings now available to rake when searching for tasks
79
+ * Merge branch 'feature/refactor-methods' into develop
80
+ * refactoring common code for rake tasks
81
+ * further refactoring of clone_repository
82
+ * refactoring update checkout methods
83
+ * renaming conditional_clone
84
+ * Refactoring rake task code
85
+ * Merge branch 'release/0.4.4' into develop
86
+ * 0.4.4 gemspec
87
+ * Version bump to 0.4.4
88
+ * Merge branch 'feature/readme-updates' into develop
89
+ * TODO list tweakage
90
+ * README updates
91
+ * Merge branch 'release/0.4.3' into develop
92
+ * updating gemspec
93
+ * Version bump to 0.4.3
94
+ * Updating TODO
95
+ * Smarter setups
96
+ * TODO updates
97
+ * Version bump to 0.4.2
98
+ * Taking a different approach to rake task detection
99
+ * bumping gemspec
100
+ * Version bump to 0.4.1
101
+ * Fixing post_* hook edge case
102
+ * More README updates
103
+ * updating README
104
+ * updated gemspec
105
+ * adding staleness check docs to README
106
+ * Version bump to 0.4.0
107
+ * Make the staleness check actually work with bash.
108
+ * Adding "else" block to provide feedback when not stale
109
+ * More complete implementation of staleness checks
110
+ * Removing earlier abortive implementation of staleness checking
111
+ * Support for staleness checks
112
+ * Adding first pass at conditional staleness checks
113
+ * updating TODO list
114
+ * README note about post_* rake task dependencies
115
+ * updated gemspec
116
+ * Version bump to 0.3.1
117
+ * No longer require a Rakefile when --path isn't used
118
+ * We no longer do per-target config file overrides
119
+ * Don't run post_{setup,deploy} rake tasks without a deployed Rakefile
120
+ * use 'target' instead of 'environment' in README
121
+ * encoding < and >
122
+ * more README tweaks
123
+ * readme formatting tweak
124
+ * make sure README.markdown is displayed on install
125
+ * new and improved README
126
+ * adding a simple deploy.yml example to the README
127
+ * add link to live presentation to README
128
+ * adding a check flag for use with staleness checks
129
+ * english spike of staleness check in todo file
data/README.markdown CHANGED
@@ -57,6 +57,12 @@ current local checkout.
57
57
  do hands-free automated deployments whenever code is pushed to your
58
58
  deployment branch of choice!
59
59
 
60
+ - You can deploy to multiple remote targets at once. Currently this is limited
61
+ to one-after-the-other synchronous deployments, but we're thinking about
62
+ doing them in parallel once we're happy with the stability of this (new)
63
+ feature.
64
+
65
+
60
66
  ### Assumptions ###
61
67
 
62
68
  - your project is managed via git
@@ -100,7 +106,7 @@ As a rails plugin:
100
106
 
101
107
  Known config file settings (if you're familiar with capistrano and vlad these should seem eerily familiar):
102
108
 
103
- domain: host on which to deploy (this is an ssh connect string)
109
+ domain: host or list of hosts on which to deploy (these are ssh connect strings)
104
110
  deploy_to: path to which to deploy main application
105
111
  repository: git repo path for main application
106
112
  branch: git branch to deploy from main application git repo (default: master)
@@ -116,7 +122,7 @@ Known config file settings (if you're familiar with capistrano and vlad these sh
116
122
  A simple config/deploy.yml might look like:
117
123
 
118
124
  qa:
119
- domain: "ogc@www.ogtastic.com"
125
+ domain: "ogc@qa.ogtastic.com"
120
126
  deploy_to: "/var/www/www.ogtastic.com"
121
127
  repository: "git@ogtastic.com:www.ogtastic.com.git"
122
128
  branch: "stable"
@@ -132,6 +138,19 @@ of deploy:setup
132
138
  at the end of deploy:now
133
139
 
134
140
 
141
+ For deploying to multiple hosts, the config/deploy.yml might look like:
142
+
143
+ qa:
144
+ domain:
145
+ - "ogc@qa1.ogtastic.com"
146
+ - "ogc@qa2.ogtastic.com""
147
+ deploy_to: "/var/www/www.ogtastic.com"
148
+ repository: "git@ogtastic.com:www.ogtastic.com.git"
149
+ branch: "stable"
150
+ rake_env:
151
+ RAILS_ENV: 'production'
152
+
153
+
135
154
  ### post\_deploy\_script and post\_setup\_script ###
136
155
 
137
156
  Whiskey\_disk provides rake task hooks (deploy:post\_setup and deploy:post\_deploy) to allow running custom
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.4
1
+ 0.6.0
@@ -0,0 +1,4 @@
1
+ local:
2
+ deploy_to: "/Users/rick/deploy/whiskey_disk/local"
3
+ repository: "/Users/rick/git/whiskey_disk"
4
+ branch: "develop"
@@ -0,0 +1,14 @@
1
+ multi:
2
+ domain:
3
+ - "ogc@hoenir.websages.com"
4
+ - "ogc@nerthus.websages.com"
5
+ deploy_to: "/tmp/test-deployment/"
6
+ repository: "git@git.ogtastic.com:whiskey_disk.git"
7
+ branch: "develop"
8
+ badmulti:
9
+ domain:
10
+ - "ogc@hoenir.websages.com"
11
+ - "ogc@bogus.example.com"
12
+ deploy_to: "/tmp/test-deployment/"
13
+ repository: "git@git.ogtastic.com:whiskey_disk.git"
14
+ branch: "develop"
@@ -103,9 +103,20 @@ class WhiskeyDisk
103
103
  override_project_name!(data)
104
104
  { project_name => data }
105
105
  end
106
+
107
+ def normalize_domain(data)
108
+ data.each_pair do |project, project_data|
109
+ project_data.each_pair do |target, target_data|
110
+ if target_data['domain']
111
+ cleaned = [ target_data['domain'] ].flatten.delete_if { |m| m.nil? or m == '' }
112
+ target_data['domain'] = (cleaned.empty? ? nil : cleaned)
113
+ end
114
+ end
115
+ end
116
+ end
106
117
 
107
118
  def normalize_data(data)
108
- add_project_scoping(add_environment_scoping(data.clone))
119
+ normalize_domain(add_project_scoping(add_environment_scoping(data.clone)))
109
120
  end
110
121
 
111
122
  def load_data
@@ -13,6 +13,9 @@ namespace :deploy do
13
13
  WhiskeyDisk.refresh_configuration if WhiskeyDisk.has_config_repo?
14
14
  WhiskeyDisk.run_post_setup_hooks
15
15
  WhiskeyDisk.flush
16
+ WhiskeyDisk.summarize
17
+
18
+ exit(1) unless WhiskeyDisk.success?
16
19
  end
17
20
 
18
21
  desc "Deploy now."
@@ -23,6 +26,9 @@ namespace :deploy do
23
26
  WhiskeyDisk.refresh_configuration if WhiskeyDisk.has_config_repo?
24
27
  WhiskeyDisk.run_post_deploy_hooks
25
28
  WhiskeyDisk.flush
29
+ WhiskeyDisk.summarize
30
+
31
+ exit(1) unless WhiskeyDisk.success?
26
32
  end
27
33
 
28
34
  task :post_setup do
data/lib/whiskey_disk.rb CHANGED
@@ -3,11 +3,13 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'whiskey_disk', 'conf
3
3
  class WhiskeyDisk
4
4
  class << self
5
5
  attr_writer :configuration
6
+ attr_reader :results
6
7
 
7
8
  def reset
8
9
  @configuration = nil
9
10
  @buffer = nil
10
11
  @staleness_checks = nil
12
+ @results = nil
11
13
  end
12
14
 
13
15
  def buffer
@@ -39,7 +41,7 @@ class WhiskeyDisk
39
41
  end
40
42
 
41
43
  def remote?
42
- ! (self[:domain].nil? or self[:domain] == '')
44
+ !! self[:domain]
43
45
  end
44
46
 
45
47
  def has_config_repo?
@@ -109,11 +111,48 @@ class WhiskeyDisk
109
111
 
110
112
  def run(cmd)
111
113
  needs(:domain)
112
- system('ssh', '-v', self[:domain], "set -x; " + cmd)
114
+ self[:domain].each do |domain|
115
+ status = system('ssh', '-v', domain, "set -x; " + cmd)
116
+ record_result(domain, status)
117
+ end
113
118
  end
114
119
 
115
120
  def flush
116
- remote? ? run(bundle) : system(bundle)
121
+ return run(bundle) if remote?
122
+ record_result('local', system(bundle))
123
+ end
124
+
125
+ def record_result(domain, status)
126
+ @results ||= []
127
+ @results << { :domain => domain, :status => status }
128
+ end
129
+
130
+ def summarize
131
+ puts
132
+ puts "Results:"
133
+ if results and not results.empty?
134
+ successes = failures = total = 0
135
+ results.each do |result|
136
+ total += 1
137
+ if result[:status]
138
+ successes += 1
139
+ else
140
+ failures += 1
141
+ end
142
+
143
+ puts "#{result[:domain]} => #{result[:status] ? 'succeeded' : 'failed'}."
144
+ end
145
+ puts "Total: #{total} deployment#{total == 1 ? '' : 's'}, " +
146
+ "#{successes} success#{successes == 1 ? '' : 'es'}, " +
147
+ "#{failures} failure#{failures == 1 ? '' : 's'}."
148
+ else
149
+ puts "No deployments to report."
150
+ end
151
+ end
152
+
153
+ def success?
154
+ return true if !results or results.empty?
155
+ results.all? {|result| result[:status] }
117
156
  end
118
157
 
119
158
  def if_file_present(path, cmd)
@@ -15,6 +15,10 @@ def build_temp_dir
15
15
  Dir.mktmpdir
16
16
  end
17
17
 
18
+ def write_config_file(data)
19
+ File.open(@config_file, 'w') { |f| f.puts YAML.dump(data) }
20
+ end
21
+
18
22
  describe WhiskeyDisk::Config do
19
23
  describe 'when computing the environment name' do
20
24
  it 'should return false when there is no ENV["to"] setting' do
@@ -106,53 +110,53 @@ describe WhiskeyDisk::Config do
106
110
  end
107
111
 
108
112
  it 'should fail if the configuration file does not define data for this environment' do
109
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'foo' => { 'production' => { 'a' => 'b'}}}) }
113
+ write_config_file('foo' => { 'production' => { 'a' => 'b'} })
110
114
  lambda { WhiskeyDisk::Config.fetch }.should.raise
111
115
  end
112
116
 
113
117
  it 'should return the configuration yaml file data for this environment as a hash' do
114
118
  staging = { 'foo' => 'bar', 'repository' => 'xyzzy' }
115
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging }}) }
119
+ write_config_file('foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging })
116
120
  result = WhiskeyDisk::Config.fetch
117
121
  staging.each_pair do |k,v|
118
122
  result[k].should == v
119
123
  end
120
124
  end
121
-
125
+
122
126
  it 'should not include configuration information for other environments in the returned hash' do
123
127
  staging = { 'foo' => 'bar', 'baz' => 'xyzzy' }
124
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({ 'production' => { 'repository' => 'c', 'a' => 'b'}, 'staging' => staging }) }
128
+ write_config_file('production' => { 'repository' => 'c', 'a' => 'b'}, 'staging' => staging)
125
129
  WhiskeyDisk::Config.fetch['a'].should.be.nil
126
130
  end
127
131
 
128
132
  it 'should include the environment in the hash' do
129
133
  staging = { 'foo' => 'bar', 'baz' => 'xyzzy' }
130
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging }}) }
134
+ write_config_file('foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging })
131
135
  WhiskeyDisk::Config.fetch['environment'].should == 'staging'
132
136
  end
133
137
 
134
138
  it 'should not allow overriding the environment in the configuration file' do
135
139
  staging = { 'foo' => 'bar', 'repository' => 'xyzzy', 'environment' => 'production' }
136
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging }}) }
140
+ write_config_file('foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging })
137
141
  WhiskeyDisk::Config.fetch['environment'].should == 'staging'
138
142
  end
139
143
 
140
144
  it 'should include the project handle in the hash' do
141
145
  staging = { 'foo' => 'bar', 'repository' => 'xyzzy' }
142
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging }}) }
146
+ write_config_file('foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging })
143
147
  WhiskeyDisk::Config.fetch['project'].should == 'foo'
144
148
  end
145
149
 
146
150
  it 'should not allow overriding the project handle in the configuration file when a project root is specified' do
147
151
  staging = { 'foo' => 'bar', 'repository' => 'xyzzy', 'project' => 'diskey_whisk' }
148
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging }}) }
152
+ write_config_file('foo' => { 'production' => { 'repository' => 'b'}, 'staging' => staging })
149
153
  WhiskeyDisk::Config.fetch['project'].should == 'foo'
150
154
  end
151
155
 
152
156
  it 'should allow overriding the project handle in the configuration file when a project root is not specified' do
153
157
  ENV['to'] = @env = 'staging'
154
158
  staging = { 'foo' => 'bar', 'repository' => 'xyzzy', 'project' => 'diskey_whisk' }
155
- File.open(@config_file, 'w') {|f| f.puts YAML.dump({'production' => { 'repository' => 'b'}, 'staging' => staging }) }
159
+ write_config_file('production' => { 'repository' => 'b'}, 'staging' => staging)
156
160
  WhiskeyDisk::Config.fetch['project'].should == 'diskey_whisk'
157
161
  end
158
162
  end
@@ -198,16 +202,83 @@ describe WhiskeyDisk::Config do
198
202
  end
199
203
 
200
204
  it 'should return a normalized version of the un-YAMLized configuration data' do
201
- File.open(@config_file, 'w') { |f| f.puts YAML.dump({ 'repository' => 'x'}) }
205
+ write_config_file('repository' => 'x')
202
206
  WhiskeyDisk::Config.load_data.should == { 'foo' => { 'bar' => { 'repository' => 'x' } } }
203
207
  end
208
+
209
+ describe 'normalizing domains' do
210
+ before do
211
+ write_config_file(
212
+ 'foo' => {
213
+ 'bar' => { 'repository' => 'x', 'domain' => [ 'user@example.com', nil, 'foo@domain.com', '' ]},
214
+ 'baz' => { 'repository' => 'x', 'domain' => [ 'bar@example.com', 'baz@domain.com' ]},
215
+ 'xyz' => { 'repository' => 'x' },
216
+ 'abc' => { 'repository' => 'x', 'domain' => 'what@example.com' },
217
+ 'eee' => { 'repository' => 'x', 'domain' => '' }
218
+ },
219
+ 'zyx' => {
220
+ 'def' => { 'repository' => 'x', 'domain' => [ 'user@example.com', nil, 'foo@domain.com', '' ]},
221
+ 'hij' => { 'repository' => 'x', 'domain' => [ 'bar@example.com', 'baz@domain.com' ]},
222
+ 'xyz' => { 'repository' => 'x' },
223
+ 'abc' => { 'repository' => 'x', 'domain' => 'what@example.com' },
224
+ 'eee' => { 'repository' => 'x', 'domain' => '' }
225
+ }
226
+ )
227
+ end
228
+
229
+ describe 'and no domain has been specified' do
230
+ it 'should leave the domain as nil' do
231
+ WhiskeyDisk::Config.load_data['foo']['xyz']['domain'].should.be.nil
232
+ end
233
+
234
+ it 'should handle nil domains across all projects and targets' do
235
+ WhiskeyDisk::Config.load_data['zyx']['xyz']['domain'].should.be.nil
236
+ end
237
+ end
238
+
239
+ describe 'and a single domain has been specified' do
240
+ it 'should return domain as nil if the specified domain was empty' do
241
+ WhiskeyDisk::Config.load_data['foo']['eee']['domain'].should.be.nil
242
+ end
243
+
244
+ it 'should handle empty specified domains across all projects and targets' do
245
+ WhiskeyDisk::Config.load_data['zyx']['eee']['domain'].should.be.nil
246
+ end
247
+
248
+ it 'should return domain as a single list of the specified domain if the specified domain was not empty' do
249
+ WhiskeyDisk::Config.load_data['foo']['abc']['domain'].should == ['what@example.com']
250
+ end
251
+
252
+ it 'should handle single specified domains across all projects and targets' do
253
+ WhiskeyDisk::Config.load_data['zyx']['abc']['domain'].should == ['what@example.com']
254
+ end
255
+ end
256
+
257
+ describe 'and a list of domains was specified' do
258
+ it 'should return the list of domains' do
259
+ WhiskeyDisk::Config.load_data['foo']['baz']['domain'].should == [ 'bar@example.com', 'baz@domain.com' ]
260
+ end
261
+
262
+ it 'should handle lists of domains across all projects and targets' do
263
+ WhiskeyDisk::Config.load_data['zyx']['hij']['domain'].should == [ 'bar@example.com', 'baz@domain.com' ]
264
+ end
265
+
266
+ it 'should remove any blank or nil domains from the list' do
267
+ WhiskeyDisk::Config.load_data['foo']['bar']['domain'].should == ['user@example.com', 'foo@domain.com' ]
268
+ end
269
+
270
+ it 'should handle cleaning up blanks and nils across all projects and targets' do
271
+ WhiskeyDisk::Config.load_data['zyx']['def']['domain'].should == ['user@example.com', 'foo@domain.com' ]
272
+ end
273
+ end
274
+ end
204
275
  end
205
276
 
206
277
  describe 'normalizing YAML data from the configuration file' do
207
278
  before do
208
279
  ENV['to'] = @env = 'foo:staging'
209
280
 
210
- @bare_data = { 'repository' => 'git://foo/bar.git', 'domain' => 'ogc@ogtastic.com' }
281
+ @bare_data = { 'repository' => 'git://foo/bar.git', 'domain' => ['ogc@ogtastic.com'] }
211
282
  @env_data = { 'staging' => @bare_data }
212
283
  @proj_data = { 'foo' => @env_data }
213
284
  end
@@ -25,20 +25,23 @@ describe 'rake tasks' do
25
25
  :update_configuration_repository_checkout,
26
26
  :refresh_configuration,
27
27
  :run_post_setup_hooks,
28
- :flush
28
+ :flush,
29
+ :summarize
29
30
  ].each do |meth|
30
- WhiskeyDisk.stub!(meth)
31
+ WhiskeyDisk.stub!(meth)
31
32
  end
33
+
34
+ WhiskeyDisk.stub!(:success?).and_return(true)
32
35
  end
33
36
 
34
37
  it 'should make changes on the specified domain when a domain is specified' do
35
- WhiskeyDisk.configuration = { 'domain' => 'some domain' }
38
+ WhiskeyDisk.configuration = { 'domain' => [ 'some domain' ] }
36
39
  @rake["deploy:setup"].invoke
37
40
  WhiskeyDisk.should.be.remote
38
41
  end
39
42
 
40
43
  it 'should make changes on the local system when no domain is specified' do
41
- WhiskeyDisk.configuration = { 'domain' => '' }
44
+ WhiskeyDisk.configuration = { 'domain' => nil }
42
45
  WhiskeyDisk.should.not.be.remote
43
46
  end
44
47
 
@@ -126,6 +129,20 @@ describe 'rake tasks' do
126
129
  WhiskeyDisk.should.receive(:flush)
127
130
  @rake["deploy:setup"].invoke
128
131
  end
132
+
133
+ it 'should summarize the results of the setup run' do
134
+ WhiskeyDisk.should.receive(:summarize)
135
+ @rake["deploy:setup"].invoke
136
+ end
137
+
138
+ it 'should not exit in error if all setup runs were successful' do
139
+ lambda { @rake["deploy:setup"].invoke }.should.not.raise(SystemExit)
140
+ end
141
+
142
+ it 'should exit in error if some setup run was unsuccessful' do
143
+ WhiskeyDisk.stub!(:success?).and_return(false)
144
+ lambda { @rake["deploy:setup"].invoke }.should.raise(SystemExit)
145
+ end
129
146
  end
130
147
 
131
148
  describe 'deploy:now' do
@@ -137,14 +154,17 @@ describe 'rake tasks' do
137
154
  :update_configuration_repository_checkout,
138
155
  :refresh_configuration,
139
156
  :run_post_deploy_hooks,
140
- :flush
157
+ :flush,
158
+ :summarize
141
159
  ].each do |meth|
142
160
  WhiskeyDisk.stub!(meth)
143
161
  end
162
+
163
+ WhiskeyDisk.stub!(:success?).and_return(true)
144
164
  end
145
165
 
146
166
  it 'should make changes on the specified domain when a domain is specified' do
147
- WhiskeyDisk.configuration = { 'domain' => 'some domain'}
167
+ WhiskeyDisk.configuration = { 'domain' => [ 'some domain' ]}
148
168
  @rake["deploy:now"].invoke
149
169
  WhiskeyDisk.should.be.remote
150
170
  end
@@ -202,6 +222,20 @@ describe 'rake tasks' do
202
222
  WhiskeyDisk.should.receive(:flush)
203
223
  @rake["deploy:now"].invoke
204
224
  end
225
+
226
+ it 'should summarize the results of the deployment run' do
227
+ WhiskeyDisk.should.receive(:summarize)
228
+ @rake["deploy:now"].invoke
229
+ end
230
+
231
+ it 'should not exit in error if all deployment runs were successful' do
232
+ lambda { @rake["deploy:now"].invoke }.should.not.raise(SystemExit)
233
+ end
234
+
235
+ it 'should exit in error if some deployment run was unsuccessful' do
236
+ WhiskeyDisk.stub!(:success?).and_return(false)
237
+ lambda { @rake["deploy:now"].invoke }.should.raise(SystemExit)
238
+ end
205
239
  end
206
240
 
207
241
  describe 'deploy:post_setup' do
@@ -2,6 +2,21 @@ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper.rb'))
2
2
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'whiskey_disk'))
3
3
  require 'rake'
4
4
 
5
+ # WhiskeyDisk subclass that allows us to test in what order ssh commands are
6
+ # issued by WhiskeyDisk.run
7
+ class TestOrderedExecution < WhiskeyDisk
8
+ class << self
9
+ def commands
10
+ @commands
11
+ end
12
+
13
+ def system(*args)
14
+ @commands ||= []
15
+ @commands << args.join(' ')
16
+ end
17
+ end
18
+ end
19
+
5
20
  describe 'requiring the main library' do
6
21
  before do
7
22
  Rake.application = @rake = Rake::Application.new
@@ -36,19 +51,19 @@ describe 'WhiskeyDisk' do
36
51
  lambda { WhiskeyDisk.remote?(:foo) }.should.raise(ArgumentError)
37
52
  end
38
53
 
39
- it 'should return true if the configuration includes a non-empty domain setting' do
40
- @parameters['domain'] = 'smeghost'
41
- WhiskeyDisk.remote?.should == true
42
- end
43
-
44
54
  it 'should return false if the configuration includes a nil domain setting' do
45
55
  @parameters['domain'] = nil
46
56
  WhiskeyDisk.remote?.should == false
47
57
  end
58
+
59
+ it 'should return true if the configuration includes a non-empty domain setting' do
60
+ @parameters['domain'] = ['smeghost']
61
+ WhiskeyDisk.remote?.should == true
62
+ end
48
63
 
49
- it 'should return false if the configuration includes a blank domain setting' do
50
- @parameters['domain'] = ''
51
- WhiskeyDisk.remote?.should == false
64
+ it 'should return true if the configuration includes a multiple domain settings' do
65
+ @parameters['domain'] = ['smeghost', 'faphost']
66
+ WhiskeyDisk.remote?.should == true
52
67
  end
53
68
  end
54
69
 
@@ -532,6 +547,7 @@ describe 'WhiskeyDisk' do
532
547
 
533
548
  describe 'when running locally' do
534
549
  before do
550
+ WhiskeyDisk.reset
535
551
  WhiskeyDisk.configuration = { 'deploy_to' => '/path/to/main/repo' }
536
552
  WhiskeyDisk.stub!(:bundle).and_return('command string')
537
553
  WhiskeyDisk.stub!(:system)
@@ -548,6 +564,18 @@ describe 'WhiskeyDisk' do
548
564
  WhiskeyDisk.should.receive(:system).with('command string')
549
565
  WhiskeyDisk.flush
550
566
  end
567
+
568
+ it 'should record a failure result when the system command fails' do
569
+ WhiskeyDisk.stub!(:system).and_return(false)
570
+ WhiskeyDisk.flush
571
+ WhiskeyDisk.results.should == [ { :domain => 'local', :status => false } ]
572
+ end
573
+
574
+ it 'should record a success result when the system command succeeds' do
575
+ WhiskeyDisk.stub!(:system).and_return(true)
576
+ WhiskeyDisk.flush
577
+ WhiskeyDisk.results.should == [ { :domain => 'local', :status => true } ]
578
+ end
551
579
  end
552
580
  end
553
581
 
@@ -753,6 +781,7 @@ describe 'WhiskeyDisk' do
753
781
 
754
782
  describe 'when running a command string remotely' do
755
783
  before do
784
+ WhiskeyDisk.reset
756
785
  @domain = 'ogc@ogtastic.com'
757
786
  WhiskeyDisk.configuration = { 'domain' => @domain }
758
787
  WhiskeyDisk.stub!(:system)
@@ -770,11 +799,119 @@ describe 'WhiskeyDisk' do
770
799
  WhiskeyDisk.configuration = {}
771
800
  lambda { WhiskeyDisk.run('ls') }.should.raise
772
801
  end
773
-
802
+
774
803
  it 'should pass the string to ssh with verbosity enabled' do
775
804
  WhiskeyDisk.should.receive(:system).with('ssh', '-v', @domain, "set -x; ls")
776
805
  WhiskeyDisk.run('ls')
777
806
  end
807
+
808
+ describe 'and multiple domains are specified' do
809
+ before do
810
+ @domains = [ 'ogc@ogtastic.com', 'foo@example.com' ]
811
+ end
812
+
813
+ it 'should run the command via ssh on each domain in the order specified in the configuration file' do
814
+ TestOrderedExecution.configuration = { 'domain' => @domains }
815
+ TestOrderedExecution.run('ls')
816
+ TestOrderedExecution.commands.should == [
817
+ "ssh -v ogc@ogtastic.com set -x; ls",
818
+ "ssh -v foo@example.com set -x; ls"
819
+ ]
820
+ end
821
+
822
+ it 'should not fail if an ssh command fails' do
823
+ WhiskeyDisk.configuration = { 'domain' => @domains }
824
+ WhiskeyDisk.stub!(:system).with('ssh', '-v', 'ogc@ogtastic.com', 'set -x; ls').and_return(false)
825
+ lambda { WhiskeyDisk.run('ls') }.should.not.raise(RuntimeError)
826
+ end
827
+
828
+ it 'should continue to run the remaining ssh commands when an ssh fails' do
829
+ WhiskeyDisk.configuration = { 'domain' => @domains }
830
+ WhiskeyDisk.stub!(:system).with('ssh', '-v', 'ogc@ogtastic.com', 'set -x; ls').and_return(false)
831
+ WhiskeyDisk.should.receive(:system).with('ssh', '-v', 'foo@example.com', 'set -x; ls')
832
+ WhiskeyDisk.run('ls')
833
+ end
834
+
835
+ it 'should record failure and success status for issued ssh commands' do
836
+ WhiskeyDisk.configuration = { 'domain' => @domains }
837
+ WhiskeyDisk.stub!(:system).with('ssh', '-v', 'ogc@ogtastic.com', 'set -x; ls').and_return(false)
838
+ WhiskeyDisk.stub!(:system).with('ssh', '-v', 'foo@example.com', 'set -x; ls').and_return(true)
839
+ WhiskeyDisk.run('ls')
840
+ WhiskeyDisk.results.should == [ { :domain => 'ogc@ogtastic.com', :status => false },
841
+ { :domain => 'foo@example.com', :status => true} ]
842
+ end
843
+ end
844
+ end
845
+
846
+ describe 'determining if all the deployments succeeded' do
847
+ before do
848
+ WhiskeyDisk.reset
849
+ end
850
+
851
+ it 'should work without arguments' do
852
+ lambda { WhiskeyDisk.success? }.should.not.raise(ArgumentError)
853
+ end
854
+
855
+ it 'should not allow arguments' do
856
+ lambda { WhiskeyDisk.success?(:foo) }.should.raise(ArgumentError)
857
+ end
858
+
859
+ it 'should return true if there are no results recorded' do
860
+ WhiskeyDisk.success?.should.be.true
861
+ end
862
+
863
+ it 'should return true if all recorded results have true statuses' do
864
+ WhiskeyDisk.record_result('1', true)
865
+ WhiskeyDisk.record_result('2', true)
866
+ WhiskeyDisk.record_result('3', true)
867
+ WhiskeyDisk.success?.should.be.true
868
+ end
869
+
870
+ it 'should return false if any recorded result has a false status' do
871
+ WhiskeyDisk.record_result('1', true)
872
+ WhiskeyDisk.record_result('2', false)
873
+ WhiskeyDisk.record_result('3', true)
874
+ WhiskeyDisk.success?.should.be.false
875
+ end
876
+ end
877
+
878
+ describe 'summarizing the results of a run' do
879
+ before do
880
+ WhiskeyDisk.reset
881
+ WhiskeyDisk.stub!(:puts)
882
+ end
883
+
884
+ it 'should work without arguments' do
885
+ lambda { WhiskeyDisk.summarize }.should.not.raise(ArgumentError)
886
+ end
887
+
888
+ it 'should not allow arguments' do
889
+ lambda { WhiskeyDisk.summarize(:foo) }.should.raise(ArgumentError)
890
+ end
891
+
892
+ it 'should output a no runs message when no results are recorded' do
893
+ WhiskeyDisk.should.receive(:puts).with('No deployments to report.')
894
+ WhiskeyDisk.summarize
895
+ end
896
+
897
+ describe 'and there are results recorded' do
898
+ before do
899
+ WhiskeyDisk.record_result('foo@bar.com', false)
900
+ WhiskeyDisk.record_result('ogc@ogtastic.com', true)
901
+ WhiskeyDisk.record_result('user@example.com', true)
902
+ end
903
+
904
+ it 'should output a status line for each recorded deployment run' do
905
+ WhiskeyDisk.should.receive(:puts).with('foo@bar.com => failed.')
906
+ WhiskeyDisk.should.receive(:puts).with('ogc@ogtastic.com => succeeded.')
907
+ WhiskeyDisk.should.receive(:puts).with('user@example.com => succeeded.')
908
+ WhiskeyDisk.summarize
909
+ end
910
+
911
+ it 'should output a summary line including the total runs, count of failures and count of successes.' do
912
+ WhiskeyDisk.should.receive(:puts).with('Total: 3 deployments, 2 successes, 1 failure.')
913
+ WhiskeyDisk.summarize
914
+ end
915
+ end
778
916
  end
779
917
  end
780
-
data/whiskey_disk.gemspec CHANGED
@@ -1,15 +1,15 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{whiskey_disk}
8
- s.version = "0.5.4"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rick Bradley"]
12
- s.date = %q{2010-10-26}
12
+ s.date = %q{2010-12-22}
13
13
  s.default_executable = %q{wd}
14
14
  s.description = %q{Opinionated gem for doing fast git-based server deployments.}
15
15
  s.email = %q{rick@rickbradley.com}
@@ -18,46 +18,47 @@ Gem::Specification.new do |s|
18
18
  "README.markdown"
19
19
  ]
20
20
  s.files = [
21
- ".gitignore",
22
- "MIT-LICENSE",
23
- "README.markdown",
24
- "Rakefile",
25
- "TODO.txt",
26
- "VERSION",
27
- "WHY.txt",
28
- "bin/wd",
29
- "examples/deploy-staging.yml",
30
- "examples/deploy.rake",
31
- "examples/deploy.yml",
32
- "init.rb",
33
- "install.rb",
34
- "lib/whiskey_disk.rb",
35
- "lib/whiskey_disk/config.rb",
36
- "lib/whiskey_disk/rake.rb",
37
- "spec/.bacon",
38
- "spec/init_spec.rb",
39
- "spec/install_spec.rb",
40
- "spec/spec_helper.rb",
41
- "spec/wd_command_spec.rb",
42
- "spec/whiskey_disk/config_spec.rb",
43
- "spec/whiskey_disk/rake_spec.rb",
44
- "spec/whiskey_disk_spec.rb",
45
- "tasks/deploy.rake",
46
- "whiskey_disk.gemspec"
21
+ "CHANGELOG",
22
+ "MIT-LICENSE",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "TODO.txt",
26
+ "VERSION",
27
+ "WHY.txt",
28
+ "bin/wd",
29
+ "examples/deploy-local.yml",
30
+ "examples/deploy-multiple-remotes.yml",
31
+ "examples/deploy-staging.yml",
32
+ "examples/deploy.rake",
33
+ "examples/deploy.yml",
34
+ "init.rb",
35
+ "install.rb",
36
+ "lib/whiskey_disk.rb",
37
+ "lib/whiskey_disk/config.rb",
38
+ "lib/whiskey_disk/rake.rb",
39
+ "spec/.bacon",
40
+ "spec/init_spec.rb",
41
+ "spec/install_spec.rb",
42
+ "spec/spec_helper.rb",
43
+ "spec/wd_command_spec.rb",
44
+ "spec/whiskey_disk/config_spec.rb",
45
+ "spec/whiskey_disk/rake_spec.rb",
46
+ "spec/whiskey_disk_spec.rb",
47
+ "tasks/deploy.rake",
48
+ "whiskey_disk.gemspec"
47
49
  ]
48
50
  s.homepage = %q{http://github.com/flogic/whiskey_disk}
49
- s.rdoc_options = ["--charset=UTF-8"]
50
51
  s.require_paths = ["lib"]
51
52
  s.rubygems_version = %q{1.3.7}
52
53
  s.summary = %q{embarrassingly fast deployments.}
53
54
  s.test_files = [
54
55
  "spec/init_spec.rb",
55
- "spec/install_spec.rb",
56
- "spec/spec_helper.rb",
57
- "spec/wd_command_spec.rb",
58
- "spec/whiskey_disk/config_spec.rb",
59
- "spec/whiskey_disk/rake_spec.rb",
60
- "spec/whiskey_disk_spec.rb"
56
+ "spec/install_spec.rb",
57
+ "spec/spec_helper.rb",
58
+ "spec/wd_command_spec.rb",
59
+ "spec/whiskey_disk/config_spec.rb",
60
+ "spec/whiskey_disk/rake_spec.rb",
61
+ "spec/whiskey_disk_spec.rb"
61
62
  ]
62
63
 
63
64
  if s.respond_to? :specification_version then
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whiskey_disk
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
9
- - 4
10
- version: 0.5.4
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Rick Bradley
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-26 00:00:00 -05:00
18
+ date: 2010-12-22 00:00:00 -05:00
19
19
  default_executable: wd
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -41,7 +41,7 @@ extensions: []
41
41
  extra_rdoc_files:
42
42
  - README.markdown
43
43
  files:
44
- - .gitignore
44
+ - CHANGELOG
45
45
  - MIT-LICENSE
46
46
  - README.markdown
47
47
  - Rakefile
@@ -49,6 +49,8 @@ files:
49
49
  - VERSION
50
50
  - WHY.txt
51
51
  - bin/wd
52
+ - examples/deploy-local.yml
53
+ - examples/deploy-multiple-remotes.yml
52
54
  - examples/deploy-staging.yml
53
55
  - examples/deploy.rake
54
56
  - examples/deploy.yml
@@ -72,8 +74,8 @@ homepage: http://github.com/flogic/whiskey_disk
72
74
  licenses: []
73
75
 
74
76
  post_install_message:
75
- rdoc_options:
76
- - --charset=UTF-8
77
+ rdoc_options: []
78
+
77
79
  require_paths:
78
80
  - lib
79
81
  required_ruby_version: !ruby/object:Gem::Requirement
data/.gitignore DELETED
@@ -1 +0,0 @@
1
- pkg/