whiskey_disk 0.6.0 → 0.6.2

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