whiskey_disk 0.6.0 → 0.6.2

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 CHANGED
@@ -1,3 +1,24 @@
1
+ 0.6.2 / 2010-12-23
2
+ ==================
3
+
4
+ * bumping version to 0.6.2
5
+ * Merge branch 'feature/support-domain-roles' into develop
6
+ * updating README to document new roles functionality
7
+ * even more README tweaks
8
+ * more README tweaks
9
+ * adding lib/tasks/deploy.rake example to README
10
+ * refreshing gemspec
11
+ * update multiple deployment example to use roles
12
+ * new wd_role command for checking membership in a role from shell scripts
13
+ * adding #role? method in whiskey_disk/helpers for role-based rake tasks
14
+ * pass domain roles along as env variables when running ssh commands
15
+ * domain data now includes role information when available
16
+ * internal representation of 'domain' is now a list of hashes
17
+ * refactoring of config domain normalization code
18
+ * adding domain examples for config specs
19
+ * removing unnecessary describe blocks from config spec
20
+ * reordering domain config spec setup data structure for readability
21
+
1
22
 
2
23
  0.6.0 / 2010-12-22
3
24
  ==================
@@ -17,6 +38,10 @@
17
38
  * normalize 'domain' values pulled from config files
18
39
  * refactor config file writing in config spec
19
40
  * WD.remote? now understands arrays of 'domain' entries in the config
41
+
42
+ 0.5.4
43
+ ==================
44
+
20
45
  * Merge branch 'release/0.5.4' into develop
21
46
  * bump gemspec for 0.5.4 release
22
47
  * Version bump to 0.5.4
@@ -37,6 +62,10 @@
37
62
  * And removing unneeded spec helper
38
63
  * removing whiskey_disk config stubbing
39
64
  * introducing use_config() spec helper
65
+
66
+ 0.5.3
67
+ ==================
68
+
40
69
  * Merge branch 'release/0.5.3' into develop
41
70
  * updating gemspec for 0.5.3
42
71
  * updating Contributors section of README
@@ -47,6 +76,10 @@
47
76
  * Reworking the config to append project name overrides to the env, since everything else is dependent thereupon
48
77
  * tidying up the spec
49
78
  * 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
79
+
80
+ 0.5.2
81
+ ==================
82
+
50
83
  * Merge branch 'release/0.5.2' into develop
51
84
  * updating gemspec for version 0.5.2
52
85
  * Bumping version to 0.5.2
@@ -61,6 +94,10 @@
61
94
  * Updating TODO list
62
95
  * Adding lightning talk info to README
63
96
  * Making shallow clones on initial setup
97
+
98
+ 0.5.0
99
+ ==================
100
+
64
101
  * Merge branch 'release/0.5.0' into develop
65
102
  * updating gemspec for 0.5.0
66
103
  * Version bump to 0.5.0
@@ -72,6 +109,10 @@
72
109
  * Reordering specs for post-setup/deployment tasks
73
110
  * Updating README for post_*_script functionality
74
111
  * TODO file updates
112
+
113
+ 0.4.5
114
+ ==================
115
+
75
116
  * Merge branch 'release/0.4.5' into develop
76
117
  * new gemspec for 0.4.5 release
77
118
  * Version bump to 0.4.5
@@ -82,25 +123,45 @@
82
123
  * refactoring update checkout methods
83
124
  * renaming conditional_clone
84
125
  * Refactoring rake task code
126
+
127
+ 0.4.4
128
+ ==================
129
+
85
130
  * Merge branch 'release/0.4.4' into develop
86
131
  * 0.4.4 gemspec
87
132
  * Version bump to 0.4.4
88
133
  * Merge branch 'feature/readme-updates' into develop
89
134
  * TODO list tweakage
90
135
  * README updates
136
+
137
+ 0.4.3
138
+ ==================
139
+
91
140
  * Merge branch 'release/0.4.3' into develop
92
141
  * updating gemspec
93
142
  * Version bump to 0.4.3
94
143
  * Updating TODO
95
144
  * Smarter setups
96
145
  * TODO updates
146
+
147
+ 0.4.2
148
+ ==================
149
+
97
150
  * Version bump to 0.4.2
98
151
  * Taking a different approach to rake task detection
152
+
153
+ 0.4.1
154
+ ==================
155
+
99
156
  * bumping gemspec
100
157
  * Version bump to 0.4.1
101
158
  * Fixing post_* hook edge case
102
159
  * More README updates
103
160
  * updating README
161
+
162
+ 0.4.0
163
+ ==================
164
+
104
165
  * updated gemspec
105
166
  * adding staleness check docs to README
106
167
  * Version bump to 0.4.0
@@ -112,6 +173,10 @@
112
173
  * Adding first pass at conditional staleness checks
113
174
  * updating TODO list
114
175
  * README note about post_* rake task dependencies
176
+
177
+ 0.3.1
178
+ ==================
179
+
115
180
  * updated gemspec
116
181
  * Version bump to 0.3.1
117
182
  * No longer require a Rakefile when --path isn't used
data/README.markdown CHANGED
@@ -20,7 +20,7 @@ everything done.
20
20
  - 1 ssh connection per run -- so everything needed to do a full setup
21
21
  is done in one shot. Everything needed to do a full deployment is done in
22
22
  one shot. (Having 8 minute deploys failing because I was on CDMA wireless on a
23
- train in india where the connection won't stay up for more than 2-3 minutes is
23
+ train in India where the connection won't stay up for more than 2-3 minutes is
24
24
  not where I want to be any more.)
25
25
 
26
26
  - Deployment configuration is specified as YAML data, not as code.
@@ -46,8 +46,8 @@ current local checkout.
46
46
  specify a config_branch and everyone can have their own local setup that just
47
47
  works.
48
48
 
49
- - There's no before\_after\_before_after hooks. You've got plenty of
50
- flexibility with just a handful of rake hook points to grab onto.
49
+ - There's no before\_after\_before_after hooks. You can use a well-defined rake hook and/or a
50
+ bash script to run additional tasks.
51
51
 
52
52
  - You can enable "staleness checks" so that deployments only happen if
53
53
  either the main repo, or the config repo (if you're using one) has
@@ -62,6 +62,8 @@ current local checkout.
62
62
  doing them in parallel once we're happy with the stability of this (new)
63
63
  feature.
64
64
 
65
+ - Assign hosts to roles (e.g., "web", "db", "app") and vary the shell or rake
66
+ post-setup/post-deploy actions you run based on those roles.
65
67
 
66
68
  ### Assumptions ###
67
69
 
@@ -107,6 +109,7 @@ As a rails plugin:
107
109
  Known config file settings (if you're familiar with capistrano and vlad these should seem eerily familiar):
108
110
 
109
111
  domain: host or list of hosts on which to deploy (these are ssh connect strings)
112
+ can also optionally include role information for each host
110
113
  deploy_to: path to which to deploy main application
111
114
  repository: git repo path for main application
112
115
  branch: git branch to deploy from main application git repo (default: master)
@@ -151,6 +154,85 @@ For deploying to multiple hosts, the config/deploy.yml might look like:
151
154
  RAILS_ENV: 'production'
152
155
 
153
156
 
157
+ ### Specifying domains, with or without roles ###
158
+
159
+ There are a number of ways to specify domains (the ssh connection strings denoting the hosts
160
+ where your code will be deployed). Here are just a few examples:
161
+
162
+ Just a single domain:
163
+
164
+ staging:
165
+ domain: "foo@staging.example.com"
166
+
167
+ Just a single domain, but specified as a one-item list:
168
+
169
+ qa:
170
+ domain:
171
+ - "foo@qa.example.com"
172
+
173
+ A list of multiple domains:
174
+
175
+ production:
176
+ domain:
177
+ - "foo@appserver1.example.com"
178
+ - "foo@appserver2.example.com"
179
+ - "foo@www.example.com"
180
+
181
+ Using the "name" label for the domain names (if using roles, as described below, the "name" label is required,
182
+ otherwise it's optional and superfluous):
183
+
184
+ ci:
185
+ domain:
186
+ - name: "build@ci.example.com"
187
+
188
+
189
+ It's also possible to assign various "roles" to the domains to which you deploy. Some common usages would be
190
+ "www", which might need a post\_deploy task which notifies some web server software (apache, nginx, passenger,
191
+ unicorn, etc.) that it should refresh the contents being served; or perhaps "db", which might need some set of
192
+ post-deployment database migrations run (and which shouldn't be run from multiple servers).
193
+
194
+ The role names are simply strings and you can create whichever roles you wish. See the section below entitled
195
+ "Taking actions based on roles" to see how to use roles to control actions when setting up or deploying to a
196
+ target.
197
+
198
+ Roles are described in the domain: section of the configuration file. There are, of course, a few different
199
+ valid ways to specify roles. Note that the domain name must now be labeled when roles are being specified
200
+ for the domain.
201
+
202
+ A single role for a domain can be specified inline:
203
+
204
+ production:
205
+ domain:
206
+ - name: "foo@appserver1.example.com"
207
+ roles: "web"
208
+
209
+ While multiple roles for a domain must be specified as a list:
210
+
211
+ production:
212
+ domain:
213
+ - name: "foo@appserver1.example.com"
214
+ roles:
215
+ - "web"
216
+ - "app"
217
+ - "db"
218
+
219
+ But domains with roles can be specified alongside simple domains as well:
220
+
221
+ production:
222
+ domain:
223
+ - name: "bar@demo.example.com"
224
+ - "user@otherhost.domain.com"
225
+ - name: "foo@appserver1.example.com"
226
+ roles:
227
+ - "web"
228
+ - "app"
229
+ - "db"
230
+
231
+
232
+ All that said, it's often simpler to refrain from carving up hosts into roles. But who's going to listen to reason?
233
+
234
+
235
+
154
236
  ### post\_deploy\_script and post\_setup\_script ###
155
237
 
156
238
  Whiskey\_disk provides rake task hooks (deploy:post\_setup and deploy:post\_deploy) to allow running custom
@@ -184,7 +266,98 @@ The post\_deploy\_script will be run from /var/www/www.ogtastic.com/bin/post-dep
184
266
  target system.
185
267
 
186
268
 
187
- ### Running from the command-line ###
269
+ ### Taking actions based on roles ###
270
+
271
+ #### When running rake tasks or other ruby scripts ####
272
+
273
+ Whiskey\_disk includes a helper library for use in rake tasks and other ruby scripts. In that library you'll
274
+ find a ruby function 'role?' which returns true if you're currently being deployed to a domain with the given
275
+ role. For example:
276
+
277
+ <code>
278
+
279
+ require 'whiskey_disk/helpers'
280
+
281
+ namespace :deploy do
282
+ task :create_rails_directories do
283
+ if role? :www
284
+ puts "creating log/ and tmp/ directories"
285
+ Dir.chdir(RAILS_ROOT)
286
+ system("mkdir -p log tmp")
287
+ end
288
+ end
289
+
290
+ task :db_migrate_if_necessary do
291
+ Rake::Task['db:migrate'] if role? :db
292
+ end
293
+
294
+ # whytf is this even necessary? Come on. This should be built into ts:restart.
295
+ task :thinking_sphinx_restart => [:environment] do
296
+ if role? :app
297
+ Rake::Task['ts:stop'].invoke rescue nil
298
+ Rake::Task['ts:index'].invoke
299
+ Rake::Task['ts:start'].invoke
300
+ end
301
+ end
302
+
303
+ task :bounce_passenger do
304
+ if role? :www
305
+ puts "restarting Passenger web server"
306
+ Dir.chdir(RAILS_ROOT)
307
+ system("touch tmp/restart.txt")
308
+ end
309
+ end
310
+
311
+ # etc...
312
+
313
+ task :post_setup => [ :create_rails_directories ]
314
+ task :post_deploy => [ :db_migrate_if_necessary, :thinking_sphinx_restart, :bounce_passenger ]
315
+ end
316
+ </code>
317
+
318
+
319
+ #### When working with the shell ####
320
+
321
+ Installing the whiskey\_disk gem also installs another binary, called wd_role. It's job is really simple,
322
+ given a role, determine if we're currently in a deployment that matches that role. If so, exit with a success
323
+ exit status, otherwise, exit with an error exit status. This allows programs running in the shell to conditionally
324
+ execute code based on domain roles. This is particularly applicable to post\_setup\_script and post\_deploy\_script
325
+ code.
326
+
327
+ Here's an off-the-cuff example of how one might use wd\_role. We have the rockhands gem installed (obviously), and
328
+ are in an environment where the 'app' role is active but the 'web' role is not:
329
+
330
+
331
+ $ wd_role web && rock || shocker
332
+ .-.
333
+ .-.U|
334
+ |U| | .-.
335
+ | | |_|U|
336
+ | | | | |
337
+ /| ` |
338
+ | | |
339
+ | |
340
+ \ /
341
+ | |
342
+ | |
343
+
344
+ $ wd_role app && rock || shocker
345
+ .-.
346
+ |U|
347
+ | | .-.
348
+ | |-._|U|
349
+ | | | | |
350
+ /| ` |
351
+ | | |
352
+ | |
353
+ /
354
+ | |
355
+ | |
356
+
357
+
358
+
359
+
360
+ ### Running whiskey\_disk from the command-line ###
188
361
 
189
362
  % wd setup --to=<target>
190
363
  % wd setup --to=<project>:<target>
@@ -307,7 +480,7 @@ sounds if you're using gitosis, btw.)
307
480
  Anyway, a config repo is just a git repo. In it are directories for every
308
481
  project whose configuration information is managed in that repo. For example,
309
482
  there's a "larry" directory in our main config repo, because we're deploying
310
- the [larry project](http://github.com/rick/larry) to manage our high-level
483
+ the [larry project](http://github.com/flogic/larry) to manage our high-level
311
484
  configuration data.
312
485
 
313
486
  Note, if you set the 'project' setting in deploy.yml, that determines the
@@ -361,15 +534,53 @@ overlaid on top of the most recent checkout of the project. Snap.
361
534
 
362
535
 
363
536
 
364
- More Examples:
537
+ ### More Examples: ###
365
538
 
366
- - We are using this to manage larry. See [http://github.com/rick/larry/blob/master/config/deploy.yml](http://github.com/rick/larry/blob/master/config/deploy.yml) and
367
- [http://github.com/rick/larry/blob/master/lib/tasks/deploy.rake](http://github.com/rick/larry/blob/master/lib/tasks/deploy.rake)
539
+ - We are using this to manage larry. See [https://github.com/flogic/larry/blob/master/config/deploy-local.yml.example](https://github.com/flogic/larry/blob/master/config/deploy-local.yml.example) and [http://github.com/flogic/larry/blob/master/lib/tasks/deploy.rake](http://github.com/flogic/larry/blob/master/lib/tasks/deploy.rake)
368
540
 
369
- - We are using whiskey\_disk on a private project with lots of config files, but here's
370
- a gist showing a bit more interesting deploy.rake file for post_setup and
371
- post_deploy work: [https://gist.github.com/47e23f2980943531beeb](https://gist.github.com/47e23f2980943531beeb)
541
+ - Here is a sample of a lib/tasks/deploy.rake from a Rails application we deployed once upon a time:
372
542
 
543
+ <code>
544
+
545
+ RAILS_ENV=ENV['RAILS_ENV'] if ENV['RAILS_ENV'] and '' != ENV['RAILS_ENV']
546
+ Rake::Task['environment'].invoke
547
+
548
+ require 'asset_cache_sweeper'
549
+
550
+ namespace :deploy do
551
+ task :create_rails_directories do
552
+ puts "creating log/ and tmp/ directories"
553
+ Dir.chdir(RAILS_ROOT)
554
+ system("mkdir -p log tmp")
555
+ end
556
+
557
+ # note that the plpgsql language needs to be installed by the db admin at initial database creation :-/
558
+ task :setup_postgres_for_thinking_sphinx => [ :environment ] do
559
+ ThinkingSphinx::PostgreSQLAdapter.new(Product).setup
560
+ end
561
+
562
+ # whytf is this even necessary? Come on. This should be built into ts:restart.
563
+ task :thinking_sphinx_restart => [:environment] do
564
+ Rake::Task['ts:stop'].invoke rescue nil
565
+ Rake::Task['ts:index'].invoke
566
+ Rake::Task['ts:start'].invoke
567
+ end
568
+
569
+ task :bounce_passenger do
570
+ puts "restarting Passenger web server"
571
+ Dir.chdir(RAILS_ROOT)
572
+ system("touch tmp/restart.txt")
573
+ end
574
+
575
+ task :clear_asset_cache => [:environment] do
576
+ STDERR.puts "Expiring cached Assets for domains [#{AssetCacheSweeper.domains.join(", ")}]"
577
+ AssetCacheSweeper.expire
578
+ end
579
+
580
+ task :post_setup => [ :create_rails_directories, :setup_postgres_for_thinking_sphinx ]
581
+ task :post_deploy => [ 'db:migrate', 'ts:config', :thinking_sphinx_restart, :bounce_passenger, :clear_asset_cache ]
582
+ end
583
+ </code>
373
584
 
374
585
  ### Future Directions ###
375
586
 
@@ -387,4 +598,5 @@ to see what we have in mind for the near future.
387
598
 
388
599
  - Rick Bradley (rick@rickbradley.com, github:rick)
389
600
  - Jeremy Holland (jeremy@jeremypholland.com, github:therubyneck): feature/bugfix contributions
390
-
601
+ - Kevin Barnes (@vinbarnes), Yossef Mendellsohn (cardioid) for design help and proofreading
602
+ - Cristi Balan (evilchelu) for feedback and proofreading
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.6.2
data/bin/wd_role ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ require 'whiskey_disk/helpers'
3
+
4
+ # simple command-line script to detect whether this deployment target
5
+ # is in a specified whiskey_disk role. sets exit status appropriately
6
+ #
7
+ # useful for conditionalizing shell scripting based on roles.
8
+
9
+ role = ARGV.shift
10
+ exit(1) unless role?(role)
11
+
12
+ __END__
13
+
14
+ ( this example session presumes you `gem install rockhands` first... )
15
+
16
+ $ export WD_ROLES='app:db'
17
+ $ wd_role web && rock || shocker
18
+ .-.
19
+ .-.U|
20
+ |U| | .-.
21
+ | | |_|U|
22
+ | | | | |
23
+ /| ` |
24
+ | | |
25
+ | |
26
+ \ /
27
+ | |
28
+ | |
29
+
30
+ $ wd_role app && rock || shocker
31
+ .-.
32
+ |U|
33
+ | | .-.
34
+ | |-._|U|
35
+ | | | | |
36
+ /| ` |
37
+ | | |
38
+ | |
39
+ /
40
+ | |
41
+ | |
42
+
@@ -5,6 +5,18 @@ multi:
5
5
  deploy_to: "/tmp/test-deployment/"
6
6
  repository: "git@git.ogtastic.com:whiskey_disk.git"
7
7
  branch: "develop"
8
+ roles:
9
+ domain:
10
+ - name: "ogc@hoenir.websages.com"
11
+ roles:
12
+ - web
13
+ - app
14
+ - name: "ogc@nerthus.websages.com"
15
+ roles: db
16
+ deploy_to: "/tmp/test-deployment/"
17
+ repository: "git@git.ogtastic.com:whiskey_disk.git"
18
+ branch: "feature/support-domain-roles"
19
+ post_deploy_script: "/tmp/role-checker.sh"
8
20
  badmulti:
9
21
  domain:
10
22
  - "ogc@hoenir.websages.com"
data/lib/whiskey_disk.rb CHANGED
@@ -109,11 +109,16 @@ class WhiskeyDisk
109
109
  (staleness_checks_enabled? and check_staleness?) ? apply_staleness_check(join_commands) : join_commands
110
110
  end
111
111
 
112
+ def encode_roles(roles)
113
+ return '' unless roles and !roles.empty?
114
+ "export WD_ROLES='#{roles.join(':')}'; "
115
+ end
116
+
112
117
  def run(cmd)
113
118
  needs(:domain)
114
119
  self[:domain].each do |domain|
115
- status = system('ssh', '-v', domain, "set -x; " + cmd)
116
- record_result(domain, status)
120
+ status = system('ssh', '-v', domain[:name], "set -x; " + encode_roles(domain[:roles]) + cmd)
121
+ record_result(domain[:name], status)
117
122
  end
118
123
  end
119
124
 
@@ -103,20 +103,37 @@ class WhiskeyDisk
103
103
  override_project_name!(data)
104
104
  { project_name => data }
105
105
  end
106
+
107
+ def compact_list(list)
108
+ [ list ].flatten.delete_if { |d| d.nil? or d == '' }
109
+ end
106
110
 
107
111
  def normalize_domain(data)
112
+ compacted = compact_list(data)
113
+ return nil if compacted.empty?
114
+
115
+ compacted.collect do |d|
116
+ if d.respond_to?(:keys)
117
+ row = { :name => (d['name'] || d[:name]) }
118
+ roles = compact_list(d['roles'] || d[:roles])
119
+ row[:roles] = roles unless roles.empty?
120
+ row
121
+ else
122
+ { :name => d }
123
+ end
124
+ end
125
+ end
126
+
127
+ def normalize_domains(data)
108
128
  data.each_pair do |project, project_data|
109
129
  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
130
+ target_data['domain'] = normalize_domain(target_data['domain']) if target_data['domain']
114
131
  end
115
132
  end
116
133
  end
117
134
 
118
135
  def normalize_data(data)
119
- normalize_domain(add_project_scoping(add_environment_scoping(data.clone)))
136
+ normalize_domains(add_project_scoping(add_environment_scoping(data.clone)))
120
137
  end
121
138
 
122
139
  def load_data
@@ -0,0 +1,6 @@
1
+
2
+ # is the current deployment domain in the specified role?
3
+ def role?(role)
4
+ return false unless ENV['WD_ROLES'] and ENV['WD_ROLES'] != ''
5
+ ENV['WD_ROLES'].split(':').include?(role.to_s)
6
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ def run_command
4
+ eval File.read(File.join(File.dirname(__FILE__), *%w[.. bin wd_role]))
5
+ end
6
+
7
+ describe 'wd role command' do
8
+ before do
9
+ ENV['WD_ROLES'] = nil
10
+ end
11
+
12
+ describe 'when no command-line arguments are specified' do
13
+ before do
14
+ Object.send(:remove_const, :ARGV)
15
+ ARGV = []
16
+ end
17
+
18
+ it 'should fail' do
19
+ lambda { run_command }.should.raise(SystemExit)
20
+ end
21
+ end
22
+
23
+ describe "when a role is specified on the command-line" do
24
+ before do
25
+ Object.send(:remove_const, :ARGV)
26
+ ARGV = ['app']
27
+ end
28
+
29
+ it 'should fail when no WD_ROLES environment setting is present' do
30
+ ENV['WD_ROLES'] = nil
31
+ lambda { run_command }.should.raise(SystemExit)
32
+ end
33
+
34
+ it 'should fail when an empty WD_ROLES environment setting is present' do
35
+ ENV['WD_ROLES'] = ''
36
+ lambda { run_command }.should.raise(SystemExit)
37
+ end
38
+
39
+ it 'should fail when the WD_ROLES environment setting does not contain that role' do
40
+ ENV['WD_ROLES'] = 'web:nonapp:db'
41
+ lambda { run_command }.should.raise(SystemExit)
42
+ end
43
+
44
+ it 'should succeed when the WD_ROLES environment setting contains that role' do
45
+ ENV['WD_ROLES'] = 'web:app:db'
46
+ lambda { run_command }.should.not.raise
47
+ end
48
+ end
49
+ end
@@ -210,66 +210,139 @@ describe WhiskeyDisk::Config do
210
210
  before do
211
211
  write_config_file(
212
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
213
  'xyz' => { 'repository' => 'x' },
214
+ 'eee' => { 'repository' => 'x', 'domain' => '' },
216
215
  'abc' => { 'repository' => 'x', 'domain' => 'what@example.com' },
217
- 'eee' => { 'repository' => 'x', 'domain' => '' }
216
+ 'baz' => { 'repository' => 'x', 'domain' => [ 'bar@example.com', 'baz@domain.com' ]},
217
+ 'bar' => { 'repository' => 'x', 'domain' => [ 'user@example.com', nil, 'foo@domain.com', '' ]},
218
+ 'hsh' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com' }, { 'name' => 'baz@domain.com' } ]},
219
+ 'mix' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com' }, 'baz@domain.com' ]},
220
+ 'erl' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com', 'roles' => nil },
221
+ { 'name' => 'baz@domain.com', 'roles' => '' },
222
+ { 'name' => 'aok@domain.com', 'roles' => [] } ]},
223
+ 'rol' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com', 'roles' => [ 'web', 'db' ] },
224
+ { 'name' => 'baz@domain.com', 'roles' => [ 'db' ] },
225
+ { 'name' => 'aok@domain.com', 'roles' => 'app' } ]},
226
+ 'wow' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com', 'roles' => [ 'web', 'db' ] },
227
+ { 'name' => 'baz@domain.com', 'roles' => [ 'db' ] },
228
+ nil, '', [], 'foo@bar.example.com',
229
+ { 'name' => 'aok@domain.com', 'roles' => 'app' } ]},
218
230
  },
231
+
219
232
  '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
233
  'xyz' => { 'repository' => 'x' },
234
+ 'eee' => { 'repository' => 'x', 'domain' => '' },
223
235
  'abc' => { 'repository' => 'x', 'domain' => 'what@example.com' },
224
- 'eee' => { 'repository' => 'x', 'domain' => '' }
236
+ 'hij' => { 'repository' => 'x', 'domain' => [ 'bar@example.com', 'baz@domain.com' ]},
237
+ 'def' => { 'repository' => 'x', 'domain' => [ 'user@example.com', nil, 'foo@domain.com', '' ]},
238
+ 'hsh' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com' }, { 'name' => 'baz@domain.com' } ]},
239
+ 'mix' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com' }, 'baz@domain.com' ]},
240
+ 'erl' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com', 'roles' => nil },
241
+ { 'name' => 'baz@domain.com', 'roles' => '' },
242
+ { 'name' => 'aok@domain.com', 'roles' => [] } ]},
243
+ 'rol' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com', 'roles' => [ 'web', 'db' ] },
244
+ { 'name' => 'baz@domain.com', 'roles' => [ 'db' ] },
245
+ { 'name' => 'aok@domain.com', 'roles' => 'app' } ]},
246
+ 'wow' => { 'repository' => 'x', 'domain' => [ { 'name' => 'bar@example.com', 'roles' => [ 'web', 'db' ] },
247
+ { 'name' => 'baz@domain.com', 'roles' => [ 'db' ] },
248
+ nil, '', [], 'foo@bar.example.com',
249
+ { 'name' => 'aok@domain.com', 'roles' => 'app' } ]},
225
250
  }
226
251
  )
227
252
  end
228
253
 
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
254
+ it 'should leave the domain as nil when no domain is specified' do
255
+ WhiskeyDisk::Config.load_data['foo']['xyz']['domain'].should.be.nil
256
+ end
257
+
258
+ it 'should handle nil domains across all projects and targets' do
259
+ WhiskeyDisk::Config.load_data['zyx']['xyz']['domain'].should.be.nil
237
260
  end
238
261
 
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
262
+ it 'should return domain as nil if a single empty domain was specified' do
263
+ WhiskeyDisk::Config.load_data['foo']['eee']['domain'].should.be.nil
264
+ end
247
265
 
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
266
+ it 'should handle single empty specified domains across all projects and targets' do
267
+ WhiskeyDisk::Config.load_data['zyx']['eee']['domain'].should.be.nil
268
+ end
269
+
270
+ it 'should return domain as a single element list with a name if a single non-empty domain was specified' do
271
+ WhiskeyDisk::Config.load_data['foo']['abc']['domain'].should == [ { :name => 'what@example.com' } ]
272
+ end
273
+
274
+ it 'should handle single specified domains across all projects and targets' do
275
+ WhiskeyDisk::Config.load_data['zyx']['abc']['domain'].should == [ { :name => 'what@example.com' } ]
276
+ end
251
277
 
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
278
+ it 'should return the list of domain name hashes when a list of domains is specified' do
279
+ WhiskeyDisk::Config.load_data['foo']['baz']['domain'].should == [
280
+ { :name => 'bar@example.com' }, { :name => 'baz@domain.com' }
281
+ ]
255
282
  end
256
283
 
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
284
+ it 'should handle lists of domains across all projects and targets' do
285
+ WhiskeyDisk::Config.load_data['zyx']['hij']['domain'].should == [
286
+ { :name => 'bar@example.com' }, { :name => 'baz@domain.com' }
287
+ ]
288
+ end
261
289
 
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
290
+ it 'should remove any blank or nil domains from a simple list of domains' do
291
+ WhiskeyDisk::Config.load_data['foo']['bar']['domain'].should == [
292
+ { :name => 'user@example.com' }, { :name => 'foo@domain.com' }
293
+ ]
294
+ end
295
+
296
+ it 'should handle cleaning up blanks and nils across all projects and targets' do
297
+ WhiskeyDisk::Config.load_data['zyx']['def']['domain'].should == [
298
+ { :name => 'user@example.com' }, { :name => 'foo@domain.com' }
299
+ ]
300
+ end
265
301
 
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
302
+ it 'should not include roles when only nil, blank or empty roles lists are specified' do
303
+ WhiskeyDisk::Config.load_data['foo']['erl']['domain'].should == [
304
+ { :name => 'bar@example.com' }, { :name => 'baz@domain.com' }, { :name => 'aok@domain.com' }
305
+ ]
306
+ end
307
+
308
+ it 'should handle filtering empty roles across all projects and targets ' do
309
+ WhiskeyDisk::Config.load_data['zyx']['erl']['domain'].should == [
310
+ { :name => 'bar@example.com' }, { :name => 'baz@domain.com' }, { :name => 'aok@domain.com' }
311
+ ]
312
+ end
313
+
314
+ it 'should include and normalize roles when specified as strings or lists' do
315
+ WhiskeyDisk::Config.load_data['foo']['rol']['domain'].should == [
316
+ { :name => 'bar@example.com', :roles => [ 'web', 'db' ] },
317
+ { :name => 'baz@domain.com', :roles => [ 'db' ] },
318
+ { :name => 'aok@domain.com', :roles => [ 'app' ] }
319
+ ]
320
+ end
321
+
322
+ it 'should handle normalizing roles across all projects and targets ' do
323
+ WhiskeyDisk::Config.load_data['zyx']['rol']['domain'].should == [
324
+ { :name => 'bar@example.com', :roles => [ 'web', 'db' ] },
325
+ { :name => 'baz@domain.com', :roles => [ 'db' ] },
326
+ { :name => 'aok@domain.com', :roles => [ 'app' ] }
327
+ ]
328
+ end
329
+
330
+ it 'should respect empty domains among role data' do
331
+ WhiskeyDisk::Config.load_data['foo']['wow']['domain'].should == [
332
+ { :name => 'bar@example.com', :roles => [ 'web', 'db' ] },
333
+ { :name => 'baz@domain.com', :roles => [ 'db' ] },
334
+ { :name => 'foo@bar.example.com' },
335
+ { :name => 'aok@domain.com', :roles => [ 'app' ] }
336
+ ]
337
+ end
338
+
339
+ it 'should handle empty domain filtering among roles across all projects and targets' do
340
+ WhiskeyDisk::Config.load_data['zyx']['wow']['domain'].should == [
341
+ { :name => 'bar@example.com', :roles => [ 'web', 'db' ] },
342
+ { :name => 'baz@domain.com', :roles => [ 'db' ] },
343
+ { :name => 'foo@bar.example.com' },
344
+ { :name => 'aok@domain.com', :roles => [ 'app' ] }
345
+ ]
273
346
  end
274
347
  end
275
348
  end
@@ -278,7 +351,7 @@ describe WhiskeyDisk::Config do
278
351
  before do
279
352
  ENV['to'] = @env = 'foo:staging'
280
353
 
281
- @bare_data = { 'repository' => 'git://foo/bar.git', 'domain' => ['ogc@ogtastic.com'] }
354
+ @bare_data = { 'repository' => 'git://foo/bar.git', 'domain' => [ { :name => 'ogc@ogtastic.com' } ] }
282
355
  @env_data = { 'staging' => @bare_data }
283
356
  @proj_data = { 'foo' => @env_data }
284
357
  end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk', 'helpers'))
3
+
4
+ describe '#role?' do
5
+ it 'should accept a role string' do
6
+ lambda { role?('web') }.should.not.raise(ArgumentError)
7
+ end
8
+
9
+ it 'should require a role string' do
10
+ lambda { role? }.should.raise(ArgumentError)
11
+ end
12
+
13
+ it 'should return false if the WD_ROLES environment variable is unset' do
14
+ ENV['WD_ROLES'] = nil
15
+ role?(:web).should.be.false
16
+ end
17
+
18
+ it 'should return false if the WD_ROLES environment variable is empty' do
19
+ ENV['WD_ROLES'] = ''
20
+ role?(:web).should.be.false
21
+ end
22
+
23
+ it 'should return true if the role, as a symbol is among the roles in the WD_ROLES env variable' do
24
+ ENV['WD_ROLES'] = 'db:web'
25
+ role?(:db).should.be.true
26
+ end
27
+
28
+ it 'should return true if the role, as a string is among the roles in the WD_ROLES env variable' do
29
+ ENV['WD_ROLES'] = 'db:web'
30
+ role?('db').should.be.true
31
+ end
32
+
33
+ it 'should return false if the role, as a symbol is not among the roles in the WD_ROLES env variable' do
34
+ ENV['WD_ROLES'] = 'db:web'
35
+ role?(:app).should.be.false
36
+ end
37
+
38
+ it 'should return false if the role, as a string is not among the roles in the WD_ROLES env variable' do
39
+ ENV['WD_ROLES'] = 'db:web'
40
+ role?('app').should.be.false
41
+ end
42
+ end
43
+
@@ -7,7 +7,9 @@ require 'rake'
7
7
  class TestOrderedExecution < WhiskeyDisk
8
8
  class << self
9
9
  def commands
10
- @commands
10
+ result = @commands
11
+ @commands = []
12
+ result
11
13
  end
12
14
 
13
15
  def system(*args)
@@ -57,12 +59,12 @@ describe 'WhiskeyDisk' do
57
59
  end
58
60
 
59
61
  it 'should return true if the configuration includes a non-empty domain setting' do
60
- @parameters['domain'] = ['smeghost']
62
+ @parameters['domain'] = [ { :name => 'smeghost' } ]
61
63
  WhiskeyDisk.remote?.should == true
62
64
  end
63
65
 
64
66
  it 'should return true if the configuration includes a multiple domain settings' do
65
- @parameters['domain'] = ['smeghost', 'faphost']
67
+ @parameters['domain'] = [ { :name => 'smeghost' }, { :name => 'faphost' } ]
66
68
  WhiskeyDisk.remote?.should == true
67
69
  end
68
70
  end
@@ -527,7 +529,7 @@ describe 'WhiskeyDisk' do
527
529
  describe 'flushing changes' do
528
530
  describe 'when running remotely' do
529
531
  before do
530
- WhiskeyDisk.configuration = { 'domain' => 'www.domain.com', 'deploy_to' => '/path/to/main/repo' }
532
+ WhiskeyDisk.configuration = { 'domain' => [ { :name => 'www.domain.com' } ], 'deploy_to' => '/path/to/main/repo' }
531
533
  WhiskeyDisk.stub!(:bundle).and_return('command string')
532
534
  WhiskeyDisk.stub!(:run)
533
535
  end
@@ -783,7 +785,7 @@ describe 'WhiskeyDisk' do
783
785
  before do
784
786
  WhiskeyDisk.reset
785
787
  @domain = 'ogc@ogtastic.com'
786
- WhiskeyDisk.configuration = { 'domain' => @domain }
788
+ WhiskeyDisk.configuration = { 'domain' => [ { :name => @domain } ] }
787
789
  WhiskeyDisk.stub!(:system)
788
790
  end
789
791
 
@@ -800,14 +802,27 @@ describe 'WhiskeyDisk' do
800
802
  lambda { WhiskeyDisk.run('ls') }.should.raise
801
803
  end
802
804
 
803
- it 'should pass the string to ssh with verbosity enabled' do
804
- WhiskeyDisk.should.receive(:system).with('ssh', '-v', @domain, "set -x; ls")
805
- WhiskeyDisk.run('ls')
805
+ describe 'and a single domain is specified' do
806
+ before do
807
+ @domain = 'ogc@ogtastic.com'
808
+ WhiskeyDisk.configuration = { 'domain' => [ { :name => @domain } ] }
809
+ end
810
+
811
+ it 'should pass the string to ssh with verbosity enabled' do
812
+ WhiskeyDisk.should.receive(:system).with('ssh', '-v', @domain, "set -x; ls")
813
+ WhiskeyDisk.run('ls')
814
+ end
815
+
816
+ it 'should include domain role settings when the domain has roles' do
817
+ WhiskeyDisk.configuration = { 'domain' => [ { :name => @domain, :roles => [ 'web', 'db' ] } ] }
818
+ WhiskeyDisk.should.receive(:system).with('ssh', '-v', @domain, "set -x; export WD_ROLES='web:db'; ls")
819
+ WhiskeyDisk.run('ls')
820
+ end
806
821
  end
807
822
 
808
823
  describe 'and multiple domains are specified' do
809
824
  before do
810
- @domains = [ 'ogc@ogtastic.com', 'foo@example.com' ]
825
+ @domains = [ { :name => 'ogc@ogtastic.com' }, { :name => 'foo@example.com' } ]
811
826
  end
812
827
 
813
828
  it 'should run the command via ssh on each domain in the order specified in the configuration file' do
@@ -819,6 +834,19 @@ describe 'WhiskeyDisk' do
819
834
  ]
820
835
  end
821
836
 
837
+ it 'should include role settings for each domain when available' do
838
+ @domains = [
839
+ { :name => 'ogc@ogtastic.com', :roles => [ 'db', 'web' ] },
840
+ { :name => 'foo@example.com', :roles => [ 'app' ] }
841
+ ]
842
+ TestOrderedExecution.configuration = { 'domain' => @domains }
843
+ TestOrderedExecution.run('ls')
844
+ TestOrderedExecution.commands.should == [
845
+ "ssh -v ogc@ogtastic.com set -x; export WD_ROLES='db:web'; ls",
846
+ "ssh -v foo@example.com set -x; export WD_ROLES='app'; ls"
847
+ ]
848
+ end
849
+
822
850
  it 'should not fail if an ssh command fails' do
823
851
  WhiskeyDisk.configuration = { 'domain' => @domains }
824
852
  WhiskeyDisk.stub!(:system).with('ssh', '-v', 'ogc@ogtastic.com', 'set -x; ls').and_return(false)
data/whiskey_disk.gemspec CHANGED
@@ -5,15 +5,14 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{whiskey_disk}
8
- s.version = "0.6.0"
8
+ s.version = "0.6.2"
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-12-22}
13
- s.default_executable = %q{wd}
12
+ s.date = %q{2010-12-23}
14
13
  s.description = %q{Opinionated gem for doing fast git-based server deployments.}
15
14
  s.email = %q{rick@rickbradley.com}
16
- s.executables = ["wd"]
15
+ s.executables = ["wd_role", "wd"]
17
16
  s.extra_rdoc_files = [
18
17
  "README.markdown"
19
18
  ]
@@ -26,6 +25,7 @@ Gem::Specification.new do |s|
26
25
  "VERSION",
27
26
  "WHY.txt",
28
27
  "bin/wd",
28
+ "bin/wd_role",
29
29
  "examples/deploy-local.yml",
30
30
  "examples/deploy-multiple-remotes.yml",
31
31
  "examples/deploy-staging.yml",
@@ -35,13 +35,16 @@ Gem::Specification.new do |s|
35
35
  "install.rb",
36
36
  "lib/whiskey_disk.rb",
37
37
  "lib/whiskey_disk/config.rb",
38
+ "lib/whiskey_disk/helpers.rb",
38
39
  "lib/whiskey_disk/rake.rb",
39
40
  "spec/.bacon",
40
41
  "spec/init_spec.rb",
41
42
  "spec/install_spec.rb",
42
43
  "spec/spec_helper.rb",
43
44
  "spec/wd_command_spec.rb",
45
+ "spec/wd_role_command_spec.rb",
44
46
  "spec/whiskey_disk/config_spec.rb",
47
+ "spec/whiskey_disk/helpers_spec.rb",
45
48
  "spec/whiskey_disk/rake_spec.rb",
46
49
  "spec/whiskey_disk_spec.rb",
47
50
  "tasks/deploy.rake",
@@ -56,7 +59,9 @@ Gem::Specification.new do |s|
56
59
  "spec/install_spec.rb",
57
60
  "spec/spec_helper.rb",
58
61
  "spec/wd_command_spec.rb",
62
+ "spec/wd_role_command_spec.rb",
59
63
  "spec/whiskey_disk/config_spec.rb",
64
+ "spec/whiskey_disk/helpers_spec.rb",
60
65
  "spec/whiskey_disk/rake_spec.rb",
61
66
  "spec/whiskey_disk_spec.rb"
62
67
  ]
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: 7
4
+ hash: 3
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 0
10
- version: 0.6.0
9
+ - 2
10
+ version: 0.6.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Rick Bradley
@@ -15,8 +15,8 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-22 00:00:00 -05:00
19
- default_executable: wd
18
+ date: 2010-12-23 00:00:00 -05:00
19
+ default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: rake
@@ -35,6 +35,7 @@ dependencies:
35
35
  description: Opinionated gem for doing fast git-based server deployments.
36
36
  email: rick@rickbradley.com
37
37
  executables:
38
+ - wd_role
38
39
  - wd
39
40
  extensions: []
40
41
 
@@ -49,6 +50,7 @@ files:
49
50
  - VERSION
50
51
  - WHY.txt
51
52
  - bin/wd
53
+ - bin/wd_role
52
54
  - examples/deploy-local.yml
53
55
  - examples/deploy-multiple-remotes.yml
54
56
  - examples/deploy-staging.yml
@@ -58,13 +60,16 @@ files:
58
60
  - install.rb
59
61
  - lib/whiskey_disk.rb
60
62
  - lib/whiskey_disk/config.rb
63
+ - lib/whiskey_disk/helpers.rb
61
64
  - lib/whiskey_disk/rake.rb
62
65
  - spec/.bacon
63
66
  - spec/init_spec.rb
64
67
  - spec/install_spec.rb
65
68
  - spec/spec_helper.rb
66
69
  - spec/wd_command_spec.rb
70
+ - spec/wd_role_command_spec.rb
67
71
  - spec/whiskey_disk/config_spec.rb
72
+ - spec/whiskey_disk/helpers_spec.rb
68
73
  - spec/whiskey_disk/rake_spec.rb
69
74
  - spec/whiskey_disk_spec.rb
70
75
  - tasks/deploy.rake
@@ -108,6 +113,8 @@ test_files:
108
113
  - spec/install_spec.rb
109
114
  - spec/spec_helper.rb
110
115
  - spec/wd_command_spec.rb
116
+ - spec/wd_role_command_spec.rb
111
117
  - spec/whiskey_disk/config_spec.rb
118
+ - spec/whiskey_disk/helpers_spec.rb
112
119
  - spec/whiskey_disk/rake_spec.rb
113
120
  - spec/whiskey_disk_spec.rb