whiskey_disk 0.5.4 → 0.6.0

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