whiskey_disk 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,281 @@
1
+ ## Whiskey Disk -- embarrassingly fast deployments. ##
2
+
3
+
4
+ A very opinionated deployment tool, designed to be as fast as technologically possible. (For more background, read the [WHY.txt](http://github.com/flogic/whiskey_disk/raw/master/WHY.txt) file) Should work with any project which is git hosted, not just Ruby / Ruby on Rails projects. Allows for local deploys as well as remote.
5
+
6
+ Right-arrow through a short whiskey_disk presentation at [http://wd2010.rickbradley.com/](http://wd2010.rickbradley.com) (slide source available [here](http://github.com/rick/whiskey_disk_presentation).)
7
+
8
+ ### Selling points ###
9
+
10
+ - If you share the same opinions as we do there's almost no code involved, almost no
11
+ dependencies, and it uses stock *nix tools (ssh, bash, rsync) to get
12
+ everything done.
13
+
14
+ - Written completely spec-first for 100% coverage. We even did that for the
15
+ rake tasks, the init.rb and the plugin install.rb (if you swing that way).
16
+
17
+ - 1 ssh connection per run -- so everything needed to do a full setup
18
+ is done in one shot. Everything needed to do a full deployment is done in
19
+ one shot. (Having 8 minute deploys failing because I was on CDMA wireless on a
20
+ train in india where the connection won't stay up for more than 2-3 minutes is
21
+ not where I want to be any more.)
22
+
23
+ - Deployment configuration is specified as YAML data, not as code.
24
+ Operations to perform after setup or deployment are specified as rake
25
+ tasks.
26
+
27
+ - You can do *local* deployments, by this I mean you can use whiskey\_disk to
28
+ deploy fully running instances of your application to the same machine
29
+ you're developing on. This turns out to be surprisingly handy (well, I was
30
+ surprised). *NOTE*: be sure to set your deploy_to to a place other than the
31
+ current local checkout.
32
+
33
+ - You can do multi-project deployments, specifying deployment data in a single
34
+ deploy.yml config file, or keep an entire directory of project deployment config files.
35
+
36
+ - You can have per-developer configurations for targets (especially
37
+ useful for "local" or "development" targets). Use .gitignore, or
38
+ specify a config_branch and everyone can have their own local setup that just
39
+ works.
40
+
41
+ - There's no before\_after\_before_after hooks. You've got plenty of
42
+ flexibility with just a handful of rake hook points to grab onto.
43
+
44
+
45
+ #### Dependencies ####
46
+
47
+ rake, ssh, git, rsync on the deployment target server (affectionately referred to as the "g-node" by vinbarnes), bash-ish shell on deployment server.
48
+
49
+ #### Assumptions ####
50
+
51
+ - you have a Rakefile in the top directory of your project's checkout
52
+ - you are deploying over ssh
53
+ - your project is managed via git
54
+ - you are comfortable defining post-setup and post-deployment actions with rake
55
+ - you have an optional second git repository for per-application/per-target configuration files
56
+
57
+ ### Installation ###
58
+
59
+ As a gem:
60
+
61
+ % gem install whiskey_disk
62
+
63
+ As a rails plugin:
64
+
65
+ % script/plugin install git://github.com/flogic/whiskey_disk.git
66
+
67
+ ### Configuration ###
68
+
69
+ - look in the examples/ directory for sample configuration files
70
+ - main configuration is in %lt;app_root>/config/deploy.yml
71
+ - config files are YAML, with a section for each target.
72
+
73
+ Known config file settings (if you're familiar with capistrano and vlad these should seem eerily familiar):
74
+
75
+ domain: host on which to deploy (this is an ssh connect string)
76
+ deploy_to: path to which to deploy main application
77
+ repository: git repo path for main application
78
+ branch: git branch to deploy from main application git repo (default: master)
79
+ deploy_config_to: where to deploy the configuration repository
80
+ config_repository: git repository for configuration files
81
+ config_branch: git branch to deploy from configuration git repo (default: master)
82
+ project: project name (used to compute path in configuration checkout)
83
+ rake_env: hash of environment variables to set when running post_setup and post_deploy rake tasks
84
+
85
+
86
+ A simple config/deploy.yml might look like:
87
+
88
+ qa:
89
+ domain: "ogc@www.ogtastic.com"
90
+ deploy_to: "/var/www/www.ogtastic.com"
91
+ repository: "git@ogtastic.com:www.ogtastic.com.git"
92
+ branch: "stable"
93
+ rake_env:
94
+ RAILS_ENV: 'production'
95
+
96
+ - defining a deploy:<target>:post_setup rake task (e.g., in lib/tasks/
97
+ or in your project's Rakefile) will cause that task to be run at the end
98
+ of deploy:setup
99
+
100
+ - defining a deploy:<target>:post_deploy rake task (e.g., in
101
+ lib/tasks/ or in your project's Rakefile) will cause that task to be run
102
+ at the end of deploy:now
103
+
104
+
105
+
106
+ ### Running via rake ###
107
+
108
+ In your Rakefile:
109
+
110
+ require 'whiskey_disk/rake'
111
+
112
+ Then, from the command-line:
113
+
114
+ % rake deploy:setup to=<target> (e.g., "qa", "staging", "production", etc.)
115
+ % rake deploy:now to=<target>
116
+
117
+ or, specifying the project name:
118
+
119
+ % rake deploy:setup to=<project>:<target> (e.g., "foo:qa", "bar:production", etc.)
120
+ % rake deploy:now to=<project>:<target>
121
+
122
+
123
+ ### Running from the command-line ###
124
+
125
+ % wd setup --to=<target>
126
+ % wd setup --to=<project>:<target>
127
+ % wd setup --to=foo:qa --path=/etc/whiskey_disk/deploy.yml
128
+
129
+ % wd deploy --to=<target>
130
+ % wd deploy --to=<project>:<target>
131
+ % wd deploy --to=foo:qa --path=/etc/whiskey_disk/deploy.yml
132
+
133
+
134
+ Note that the wd command (unlike rake, which requires a Rakefile in the current directory) can be run from anywhere, so you can deploy any project, working from any path, and can even specify where to find the deployment YAML configuration file.
135
+
136
+ The --path argument can take either a file or a directory. When given a file it will use that file as the configuration file. When given a directory it will look in that directory for deploy/&lt;project&gt;/&lt;target&gt;.yml, then deploy/&lt;project&gt;.yml, then deploy/&lt;target&gt;.yml, then &lt;target&gt;.yml, and finally, deploy.yml.
137
+
138
+ All this means you can manage a large number of project deployments (local or remote) and have a single scripted deployment manager that keeps them up to date. Configurations can live in a centralized location, and developers don't have to be actively involved in ensuring code gets shipped up to a server. Win.
139
+
140
+
141
+ ### Configuration Repository ###
142
+
143
+ #### What's all this about a second repository for configuration stuff? ####
144
+
145
+ This is completely optional, but we really are digging this, so maybe
146
+ you should try it. Basically it goes like this...
147
+
148
+ We have a number of web applications that we manage. Usually there's a
149
+ customer, there might be third-party developers, or the customer might have
150
+ access to the git repo, or their designer might, etc. We also tend to run a
151
+ few instances of any given app, for any given customer. So, we'll run a
152
+ "production" site, which is the public- facing, world-accessible main site.
153
+ We'll usually also run a "staging" site, which is roughly the same code, maybe
154
+ the same data, running on a different URL, which the customer can look at to
155
+ see if the functionality there is suitable for deploying out to production. We
156
+ sometimes run a "development" site which is even less likely to be the same
157
+ code as production, etc., but gives visibility into what might end up in
158
+ production one day soon.
159
+
160
+ So we'll store the code for all of these versions of a site in the same git
161
+ repo, typically using a different remote branch for each target
162
+ ("qa", "production", "staging", "development").
163
+
164
+ One thing that comes up pretty quickly is that there are various files
165
+ associated with the application which have more to do with configuration of a
166
+ running instance than they have to do with the application in general. In the
167
+ rails world these files are probably in config, or config/initializers/. Think
168
+ database connection information, search engine settings, exception notification
169
+ plugin data, email configuration, Amazon S3 credentials, e-commerce back-end
170
+ configuration, etc.
171
+
172
+ We don't want the production site using the same database as the
173
+ development site. We don't want staging using (and re-indexing, re-starting,
174
+ etc.) production's search engine server. We don't want any site other than
175
+ production to send account reset emails, or to push orders out to fulfillment,
176
+ etc.
177
+
178
+ For some reason, the answer to this with cap and/or vlad has been to have
179
+ recipes which reference various files up in a shared area on the server, do
180
+ copying or symlinking, etc. Where did those files come from? How did they get
181
+ there? How are they managed over time? If they got there via a configuration
182
+ tool, why (a) are they not in the right place, or (b) do we have to do work to
183
+ get them into the right place?
184
+
185
+ So, we decided that we'd change how we deal with the issue. Instead of
186
+ moving files around or symlinking every time we deploy, we will manage the
187
+ configuration data just like we manage other files required by our projects --
188
+ with git.
189
+
190
+ So, each project we deploy is associated with a config repo in our git
191
+ repository. Usually many projects are in the same repo, because we're the only
192
+ people to see the data and there's no confidentiality issue. But, if a
193
+ customer has access to their git information then we'll make a separate config
194
+ repo for all that customers' projects. (This is easier to manage than it
195
+ sounds if you're using gitosis, btw.)
196
+
197
+ Anyway, a config repo is just a git repo. In it are directories for every
198
+ project whose configuration information is managed in that repo. For example,
199
+ there's a "larry" directory in our main config repo, because we're deploying
200
+ the [larry project](http://github.com/rick/larry) to manage our high-level
201
+ configuration data.
202
+
203
+ Note, if you set the 'project' setting in deploy.yml, that determines the
204
+ name of the top-level project directory whiskey\_disk will hunt for in your
205
+ config repo. If you don't it uses the 'repository' setting (i.e., the git URL)
206
+ to try to guess what the project name might be. So if the URL ends in
207
+ foo/bar.git, or foo:bar.git, or /bar, or :bar, whiskey\_disk is going to guess
208
+ "bar". If it's all bitched up, just set 'project' manually in deploy.yml.
209
+
210
+ Inside the project directory is a directory named for each target we
211
+ might deploy to. Frankly, we've been using "production", "staging",
212
+ "development", and "local" on just about everything.
213
+
214
+ Inside the target directory is a tree of files. So, e.g., there's
215
+ config/, which has initializers/ and database.yml in it.
216
+
217
+ Long story short, load up whatever configuration files you're using into
218
+ the repo as described, and come deployment time exactly those files will be
219
+ overlaid on top of the most recent checkout of the project. Snap.
220
+
221
+ project-config/
222
+ |
223
+ +---larry/
224
+ |
225
+ +---production/
226
+ | |
227
+ | +---config/
228
+ | |
229
+ | +---initializers/
230
+ | |
231
+ | +---database.yml
232
+ |
233
+ +---staging/
234
+ | |
235
+ | |
236
+ | +---config/
237
+ | |
238
+ | ....
239
+ |
240
+ +---development/
241
+ | |
242
+ | +---config/
243
+ | |
244
+ | ....
245
+ |
246
+ +---local/
247
+ |
248
+ +---config/
249
+ |
250
+ ....
251
+
252
+
253
+
254
+ More Examples:
255
+
256
+ - 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
257
+ [http://github.com/rick/larry/blob/master/lib/tasks/deploy.rake](http://github.com/rick/larry/blob/master/lib/tasks/deploy.rake)
258
+
259
+ - We are using whiskey\_disk on a private project with lots of config files, but here's
260
+ a gist showing a bit more interesting deploy.rake file for post_setup and
261
+ post_deploy work: [https://gist.github.com/47e23f2980943531beeb](https://gist.github.com/47e23f2980943531beeb)
262
+
263
+ On the radar for an upcoming release are:
264
+
265
+ - common post_* recipes being specifiable by symbol names in deploy.yml ?
266
+ - bringing in a very simplified version of mislav/git-deploy post-{receive,reset} hooks, and a little sugar so you can say:
267
+
268
+ task :post_deploy do
269
+ if has_changes?('db/migrate') or has_changes?('config/database.yml')
270
+ Rake::Task['db:migrate'].invoke
271
+ end
272
+ end
273
+
274
+
275
+ ### Resources ###
276
+
277
+ - [http://github.com/blog/470-deployment-script-spring-cleaning](http://github.com/blog/470-deployment-script-spring-cleaning)
278
+ - [http://github.com/mislav/git-deploy](http://github.com/mislav/git-deploy)
279
+ - [http://toroid.org/ams/git-website-howto](http://toroid.org/ams/git-website-howto)
280
+
281
+
data/TODO.txt CHANGED
@@ -1,5 +1,14 @@
1
1
  - would be nice to have the ability to say if a project is out of date (meaning that, based upon this config file, either the checked out project repo or the checked out config repo is older than the upstream) so we can do some sort of automated / conditional deployments. We could implement this as a config file option (check for out of date before deploying), but questions about how to "force" if necessary. Could also be done as a flag.
2
-
2
+ by default, the behavior should be *not* to check if in-sync, make it so that ENV['check'] =~ /^(?:t(?:rue)?|1|y(?:es))/i will trigger the check
3
+ similarly wd --check will set the variable
4
+
5
+ - the thinking is that a metadata file for multiple projects would specify values for this, with a meta-app using check=true by default
6
+
7
+ ml=`cat .git/refs/heads/master`; mr=`git ls-remote git@ogtastic.com:whiskey_disk.git refs/heads/master`; if [[ $ml != ${mr%% *} ]]; then { echo "out-of-date"; } else { echo "up-to-date"; } fi
8
+
9
+ - note that we actually want to check both the main repository and the configuration repository for changes
10
+ - this is only relevant for deploy:now, obviously
11
+
3
12
  - do git-deploy style change detection: get the current branch ref, then do the fetch/reset, get the current branch ref; find the differences, make them available to the rake task(s)
4
13
  - some sort of simple API to access the detected changes
5
14
  require 'whiskey_disk/rake'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
data/install.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  def readme_contents
2
- IO.read(File.expand_path(File.join(File.dirname(__FILE__), 'README')))
2
+ IO.read(File.expand_path(File.join(File.dirname(__FILE__), 'README.markdown')))
3
3
  end
4
4
 
5
5
  puts readme_contents
@@ -18,16 +18,23 @@ class WhiskeyDisk
18
18
  (ENV['path'] && ENV['path'] != '') ? ENV['path'] : false
19
19
  end
20
20
 
21
+ def check_staleness?
22
+ !!(ENV['check'] && ENV['check'] =~ /^(?:t(?:rue)?|y(?:es)?|1)$/)
23
+ end
24
+
21
25
  def contains_rakefile?(path)
22
26
  File.exists?(File.expand_path(File.join(path, 'Rakefile')))
23
27
  end
24
28
 
25
29
  def find_rakefile_from_current_path
30
+ original_path = Dir.pwd
26
31
  while (!contains_rakefile?(Dir.pwd))
27
- raise "Could not find Rakefile in the current directory tree!" if Dir.pwd == '/'
32
+ return File.join(original_path, 'config') if Dir.pwd == '/'
28
33
  Dir.chdir('..')
29
34
  end
30
35
  File.join(Dir.pwd, 'config')
36
+ ensure
37
+ Dir.chdir(original_path)
31
38
  end
32
39
 
33
40
  def base_path
data/lib/whiskey_disk.rb CHANGED
@@ -75,6 +75,10 @@ class WhiskeyDisk
75
75
  remote? ? run(bundle) : system(bundle)
76
76
  end
77
77
 
78
+ def if_file_present(path, cmd)
79
+ "if [ -e #{path} ]; then #{cmd}; fi"
80
+ end
81
+
78
82
  def ensure_main_parent_path_is_present
79
83
  needs(:deploy_to)
80
84
  enqueue "mkdir -p #{parent_path(self[:deploy_to])}"
@@ -120,13 +124,15 @@ class WhiskeyDisk
120
124
  def run_post_setup_hooks
121
125
  needs(:deploy_to)
122
126
  enqueue "cd #{self[:deploy_to]}"
123
- enqueue "#{env_vars} rake --trace deploy:post_setup to=#{self[:environment]}"
127
+ enqueue(if_file_present("#{self[:deploy_to]}/Rakefile",
128
+ "#{env_vars} rake --trace deploy:post_setup to=#{self[:environment]}"))
124
129
  end
125
130
 
126
131
  def run_post_deploy_hooks
127
132
  needs(:deploy_to)
128
133
  enqueue "cd #{self[:deploy_to]}"
129
- enqueue "#{env_vars} rake --trace deploy:post_deploy to=#{self[:environment]}"
134
+ enqueue(if_file_present("#{self[:deploy_to]}/Rakefile",
135
+ "#{env_vars} rake --trace deploy:post_deploy to=#{self[:environment]}"))
130
136
  end
131
137
  end
132
138
  end
@@ -28,6 +28,43 @@ describe WhiskeyDisk::Config do
28
28
  end
29
29
  end
30
30
 
31
+ describe 'when determining whether to do a staleness check before updating' do
32
+ it 'should return false when there is no ENV["check"] setting' do
33
+ ENV['check'] = nil
34
+ WhiskeyDisk::Config.check_staleness?.should == false
35
+ end
36
+
37
+ it 'should return false when the ENV["check"] setting is blank' do
38
+ ENV['check'] = ''
39
+ WhiskeyDisk::Config.check_staleness?.should == false
40
+ end
41
+
42
+ it 'should return true if the ENV["check"] setting is "t"' do
43
+ ENV['check'] = 't'
44
+ WhiskeyDisk::Config.check_staleness?.should == true
45
+ end
46
+
47
+ it 'should return true if the ENV["check"] setting is "true"' do
48
+ ENV['check'] = 'true'
49
+ WhiskeyDisk::Config.check_staleness?.should == true
50
+ end
51
+
52
+ it 'should return true if the ENV["check"] setting is "y"' do
53
+ ENV['check'] = 'y'
54
+ WhiskeyDisk::Config.check_staleness?.should == true
55
+ end
56
+
57
+ it 'should return true if the ENV["check"] setting is "yes"' do
58
+ ENV['check'] = 'yes'
59
+ WhiskeyDisk::Config.check_staleness?.should == true
60
+ end
61
+
62
+ it 'should return true if the ENV["check"] setting is "1"' do
63
+ ENV['check'] = '1'
64
+ WhiskeyDisk::Config.check_staleness?.should == true
65
+ end
66
+ end
67
+
31
68
  describe 'when fetching configuration' do
32
69
  before do
33
70
  ENV['to'] = @env = 'foo:staging'
@@ -398,22 +435,54 @@ describe WhiskeyDisk::Config do
398
435
  ENV['path'] = @path = nil
399
436
  end
400
437
 
401
- it 'should return the path set in the "path" environment variable when one is set' do
402
- ENV['path'] = @path = CURRENT
403
- WhiskeyDisk::Config.base_path.should == @path
438
+ describe 'and a "path" environment variable is set' do
439
+ before do
440
+ ENV['path'] = @path = CURRENT
441
+ Dir.chdir(CURRENT)
442
+ end
443
+
444
+ it 'should return the path set in the "path" environment variable' do
445
+ WhiskeyDisk::Config.base_path.should == @path
446
+ end
447
+
448
+ it 'should leave the current working path the same as when the base path lookup started' do
449
+ WhiskeyDisk::Config.base_path
450
+ Dir.pwd.should == CURRENT
451
+ end
404
452
  end
405
453
 
406
- it 'should fail if there is no Rakefile along the root path to the current directory' do
407
- WhiskeyDisk::Config.stub!(:contains_rakefile?).and_return(false)
408
- lambda { WhiskeyDisk::Config.base_path }.should.raise
409
- end
454
+ describe 'and there is no Rakefile in the root path to the current directory' do
455
+ before do
456
+ Dir.chdir(CURRENT)
457
+ WhiskeyDisk::Config.stub!(:contains_rakefile?).and_return(false)
458
+ end
459
+
460
+ it 'should return the config directory under the current directory if there is no Rakefile along the root path to the current directory' do
461
+ WhiskeyDisk::Config.base_path.should == File.join(CURRENT, 'config')
462
+ end
463
+
464
+ it 'should leave the current working path the same as when the base path lookup started' do
465
+ WhiskeyDisk::Config.base_path
466
+ Dir.pwd.should == CURRENT
467
+ end
468
+ end
410
469
 
411
- it 'return the config directory in the nearest enclosing path with a Rakefile along the root path to the current directory' do
412
- top = ::File.expand_path(File.join(CURRENT, '..', '..'))
413
- WhiskeyDisk::Config.stub!(:contains_rakefile?).and_return(false)
414
- WhiskeyDisk::Config.stub!(:contains_rakefile?).with(top).and_return(true)
415
- Dir.chdir(CURRENT)
416
- WhiskeyDisk::Config.base_path.should == File.join(top, 'config')
470
+ describe 'and there is a Rakefile in the root path to the current directory' do
471
+ before do
472
+ @top = ::File.expand_path(File.join(CURRENT, '..', '..'))
473
+ WhiskeyDisk::Config.stub!(:contains_rakefile?).and_return(false)
474
+ WhiskeyDisk::Config.stub!(:contains_rakefile?).with(@top).and_return(true)
475
+ Dir.chdir(CURRENT)
476
+ end
477
+
478
+ it 'return the config directory in the nearest enclosing path with a Rakefile along the root path to the current directory' do
479
+ WhiskeyDisk::Config.base_path.should == File.join(@top, 'config')
480
+ end
481
+
482
+ it 'should leave the current working path the same as when the base path lookup started' do
483
+ WhiskeyDisk::Config.base_path
484
+ Dir.pwd.should == CURRENT
485
+ end
417
486
  end
418
487
  end
419
488
  end
@@ -334,6 +334,11 @@ describe 'WhiskeyDisk' do
334
334
  WhiskeyDisk.buffer.join(' ').should.match(%r{cd /path/to/main/repo})
335
335
  end
336
336
 
337
+ it 'should make the post setup rake tasks conditional on the presence of a Rakefile in the deployment path' do
338
+ WhiskeyDisk.run_post_setup_hooks
339
+ WhiskeyDisk.buffer.join(' ').should.match(%r{if \[ -e /path/to/main/repo/Rakefile \]; then .*; fi})
340
+ end
341
+
337
342
  it 'should attempt to run the post setup rake tasks' do
338
343
  WhiskeyDisk.run_post_setup_hooks
339
344
  WhiskeyDisk.buffer.join(' ').should.match(%r{rake.*deploy:post_setup})
@@ -373,6 +378,11 @@ describe 'WhiskeyDisk' do
373
378
  WhiskeyDisk.buffer.join(' ').should.match(%r{cd /path/to/main/repo})
374
379
  end
375
380
 
381
+ it 'should make the post deployment rake tasks conditional on the presence of a Rakefile in the deployment path' do
382
+ WhiskeyDisk.run_post_deploy_hooks
383
+ WhiskeyDisk.buffer.join(' ').should.match(%r{if \[ -e /path/to/main/repo/Rakefile \]; then .*; fi})
384
+ end
385
+
376
386
  it 'should attempt to run the post deployment rake tasks' do
377
387
  WhiskeyDisk.run_post_deploy_hooks
378
388
  WhiskeyDisk.buffer.join(' ').should.match(%r{rake.*deploy:post_deploy})
data/whiskey_disk.gemspec CHANGED
@@ -5,22 +5,22 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{whiskey_disk}
8
- s.version = "0.3.0"
8
+ s.version = "0.3.1"
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-06-17}
12
+ s.date = %q{2010-07-08}
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}
16
16
  s.executables = ["wd"]
17
17
  s.extra_rdoc_files = [
18
- "README"
18
+ "README.markdown"
19
19
  ]
20
20
  s.files = [
21
21
  ".gitignore",
22
22
  "MIT-LICENSE",
23
- "README",
23
+ "README.markdown",
24
24
  "Rakefile",
25
25
  "TODO.txt",
26
26
  "VERSION",
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: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 0
10
- version: 0.3.0
9
+ - 1
10
+ version: 0.3.1
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-06-17 00:00:00 -05:00
18
+ date: 2010-07-08 00:00:00 -05:00
19
19
  default_executable: wd
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -39,11 +39,11 @@ executables:
39
39
  extensions: []
40
40
 
41
41
  extra_rdoc_files:
42
- - README
42
+ - README.markdown
43
43
  files:
44
44
  - .gitignore
45
45
  - MIT-LICENSE
46
- - README
46
+ - README.markdown
47
47
  - Rakefile
48
48
  - TODO.txt
49
49
  - VERSION
data/README DELETED
@@ -1,283 +0,0 @@
1
- Whiskey Disk -- embarrassingly fast deployments.
2
-
3
- A very opinionated deployment tool, designed to be as fast as technologically possible. (For more background, read the WHY.txt file)
4
-
5
- Should work with any project which is git hosted, not just Ruby / Ruby on
6
- Rails projects. Allows for local deploys as well as remote.
7
-
8
- Selling points:
9
-
10
- - If you share the same opinions there's almost no code involved, almost no
11
- dependencies, and it uses stock *nix tools (ssh, bash, rsync) to get
12
- everything done.
13
-
14
- - Written completely spec-first for 100% coverage. We even did that for the
15
- rake tasks, the init.rb and the plugin install.rb if you swing that way.
16
-
17
- - 1 ssh connection per rake task -- so everything needed to do a full setup
18
- is done in one shot. Everything needed to do a full deployment is done in
19
- one shot. Having 8 minute deploys failing because I was on cdma wireless on a
20
- train in india where the connection won't stay up for more than 2-3 minutes is
21
- not where I want to be.
22
-
23
- - You can do *local* deployments, by this I mean you can use whiskey_disk to
24
- deploy fully running instances of your application to the same machine
25
- you're developing on. This turns out to be surprisingly handy (well, I was
26
- surprised). *NOTE*: be sure to set your deploy_to to a place other than the
27
- current local checkout.
28
-
29
- - You can have per-developer configurations for environments (especially
30
- useful for "local" or "development" enviroments). Use .gitignore, or
31
- specify a config_branch and everyone can have their own local setup that just
32
- works.
33
-
34
- - Deployment configuration is specified as YAML data, not as code.
35
- Operations to perform after setup or deployment are specified as rake
36
- tasks.
37
-
38
- - There's no before_after_before_after hooks. You've got plenty of
39
- flexibility with just a handful of rake hook points to grab onto.
40
-
41
- - rake deploy:setup and rake deploy:now are really all that are needed, best
42
- I can tell.
43
-
44
-
45
-
46
- Dependencies: rake, ssh, git, rsync on the deployment target server (affectionately
47
- referred to as the "g-node" by vinbarnes), bash-ish shell on deployment
48
- server.
49
-
50
- Assumptions:
51
-
52
- - you have a Rakefile in the top directory of your project's checkout
53
- - you are deploying over ssh
54
- - your project is managed via git
55
- - you have a second git repository for per-application/per-environment configuration files
56
- - you are comfortable defining post-setup and post-deployment actions with rake
57
-
58
- Installation:
59
-
60
- As a gem:
61
-
62
- % gem install whiskey_disk
63
-
64
- As a rails plugin:
65
-
66
- % script/plugin install git://github.com/flogic/whiskey_disk.git
67
-
68
- Configuration:
69
-
70
- - look in the examples/ directory for sample configuration files
71
- - main configuration is in <app_root>/config/deploy.yml
72
- - config files are YAML, with a section for each environment.
73
-
74
- Known config file settings (if you're familiar with capistrano and vlad these
75
- should seem eerily familiar)::
76
-
77
- - domain: host on which to deploy (this is an ssh connect string)
78
- - deploy_to: path to which to deploy main application
79
- - repository: git repo path for main application
80
- - branch: git branch to deploy from main application git repo (default: master)
81
- - deploy_config_to: where to deploy the configuration repository
82
- - config_repository: git repository for configuration files
83
- - config_branch: git branch to deploy from configuration git repo (default: master)
84
- - project: project name (used to compute path in configuration checkout)
85
- - rake_env: hash of environment variables to set when running post_setup and post_deploy rake tasks
86
-
87
- - defining a deploy:<environment>:post_setup rake task (e.g., in lib/tasks/
88
- or in your project's Rakefile) will cause that task to be run at the end
89
- of deploy:setup
90
-
91
- - defining a deploy:<environment>:post_deploy rake task (e.g., in
92
- lib/tasks/ or in your project's Rakefile) will cause that task to be run
93
- at the end of deploy:now
94
-
95
-
96
- Running via rake:
97
-
98
- ... in your Rakefile:
99
-
100
- require 'whiskey_disk/rake'
101
-
102
- Then, from the command-line:
103
-
104
- % rake deploy:setup to=<target> (e.g., "staging", "production", etc.)
105
- % rake deploy:now to=<target>
106
-
107
- or, specifying the project name:
108
-
109
- % rake deploy:setup to=<project>:<target> (e.g., "foo:staging", "bar:production", etc.)
110
- % rake deploy:now to=<project>:<target>
111
-
112
-
113
- Running from the command-line:
114
-
115
- % wd setup --to=<target>
116
- % wd setup --to=<project>:<target>
117
- % wd setup --to=foo:staging --path=/etc/whiskey_disk/deploy.yml
118
-
119
- % wd deploy --to=<target>
120
- % wd deploy --to=<project>:<target>
121
- % wd deploy --to=foo:staging --path=/etc/whiskey_disk/deploy.yml
122
-
123
-
124
- Note that the wd command (unlike rake, which requires a Rakefile in the current directory) can be run from anywhere, so you can deploy any project, working from any path, and can even specify where to find the deployment YAML configuration file.
125
-
126
- The --path argument can take either a file or a directory. When given a file it will use that file as the configuration file. When given a directory it will look in that directory for deploy/<project>/<target>.yml, then deploy/<project>.yml, then deploy/<target>.yml, then <target>.yml, and finally, deploy.yml.
127
-
128
- All this means you can manage a large number of project deployments (local or remote) and have a single scripted deployment manager that keeps them up to date. Configurations can live in a centralized location, and developers don't have to be actively involved in ensuring code gets shipped up to a server. Win.
129
-
130
-
131
- Configuration Repository
132
-
133
- What's all this about a second repository for configuration stuff?
134
-
135
- This is completely optional, but we really are digging this, so maybe
136
- you should try it. Basically it goes like this...
137
-
138
- We have a number of web applications that we manage. Usually there's a
139
- customer, there might be third-party developers, or the customer might have
140
- access to the git repo, or their designer might, etc. We also tend to run a
141
- few instances of any given app, for any given customer. So, we'll run a
142
- "production" site, which is the public- facing, world-accessible main site.
143
- We'll usually also run a "staging" site, which is roughly the same code, maybe
144
- the same data, running on a different URL, which the customer can look at to
145
- see if the functionality there is suitable for deploying out to production. We
146
- sometimes run a "development" site which is even less likely to be the same
147
- code as production, etc., but gives visibility into what might end up in
148
- production one day soon.
149
-
150
- So we'll store the code for all of these versions of a site in the same git
151
- repo, typically using a different remote branch for each environment
152
- ("production", "staging", "development").
153
-
154
- One thing that comes up pretty quickly is that there are various files
155
- associated with the application which have more to do with configuration of a
156
- running instance than they have to do with the application in general. In the
157
- rails world these files are probably in config, or config/initializers/. Think
158
- database connection information, search engine settings, exception notification
159
- plugin data, email configuration, Amazon S3 credentials, e-commerce back-end
160
- configuration, etc.
161
-
162
- We don't want the production site using the same database as the
163
- development site. We don't want staging using (and re-indexing, re-starting,
164
- etc.) production's search engine server. We don't want any site other than
165
- production to send account reset emails, or to push orders out to fulfillment,
166
- etc.
167
-
168
- For some reason, the answer to this with cap and/or vlad has been to have
169
- recipes which reference various files up in a shared area on the server, do
170
- copying or symlinking, etc. Where did those files come from? How did they get
171
- there? How are they managed over time? If they got there via a configuration
172
- tool, why (a) are they not in the right place, or (b) do we have to do work to
173
- get them into the right place?
174
-
175
- So, we decided that we'd change how we deal with the issue. Instead of
176
- moving files around or symlinking every time we deploy, we will manage the
177
- configuration data just like we manage other files required by our projects --
178
- with git.
179
-
180
- So, each project we deploy is associated with a config repo in our git
181
- repository. Usually many projects are in the same repo, because we're the only
182
- people to see the data and there's no confidentiality issue. But, if a
183
- customer has access to their git information then we'll make a separate config
184
- repo for all that customers' projects. (This is easier to manage than it
185
- sounds if you're using gitosis, btw.)
186
-
187
- Anyway, a config repo is just a git repo. In it are directories for every
188
- project whose configuration information is managed in that repo. For example,
189
- there's a "larry" directory in our main config repo, because we're deploying
190
- the larry project (http://github.com/rick/larry) to manage our high-level
191
- configuration data.
192
-
193
- Note, if you set the 'project' setting in deploy.yml, that determines the
194
- name of the top-level project directory whiskey_disk will hunt for in your
195
- config repo. If you don't it uses the 'repository' setting (i.e., the git URL)
196
- to try to guess what the project name might be. So if the URL ends in
197
- foo/bar.git, or foo:bar.git, or /bar, or :bar, whiskey_disk is going to guess
198
- "bar". If it's all bitched up, just set 'project' manually in deploy.yml.
199
-
200
- Inside the project directory is a directory named for each environment we
201
- might deploy to. Frankly, we've been using "production", "staging",
202
- "development", and "local" on just about everything.
203
-
204
- Inside the environment directory is a tree of files. So, e.g., there's
205
- config/, which has initializers/ and database.yml in it.
206
-
207
- Long story short, load up whatever configuration files you're using into
208
- the repo as described, and come deployment time exactly those files will be
209
- overlaid on top of the most recent checkout of the project. Snap.
210
-
211
- project-config/
212
- |
213
- +---larry/
214
- |
215
- +---production/
216
- | |
217
- | +---config/
218
- | |
219
- | +---initializers/
220
- | |
221
- | +---database.yml
222
- |
223
- +---staging/
224
- | |
225
- | |
226
- | +---config/
227
- | |
228
- | ....
229
- |
230
- +---development/
231
- | |
232
- | +---config/
233
- | |
234
- | ....
235
- |
236
- +---local/
237
- |
238
- +---config/
239
- |
240
- ....
241
-
242
-
243
-
244
- More Examples:
245
-
246
- - We are using this to manage larry. See:
247
-
248
- http://github.com/rick/larry/blob/master/config/deploy.yml
249
- http://github.com/rick/larry/blob/master/lib/tasks/deploy.rake
250
-
251
- Note that you can also provide per-environment config settings, outside of
252
- deploy.yml. This is most useful for handling per-developer local deployments,
253
- though you could use it to override some settings if that makes sense in some
254
- context. Here's a simple example of that:
255
-
256
- http://github.com/rick/larry/blob/master/config/deploy-local.yml.example
257
-
258
-
259
- - We are using it on a private project with lots of config files, but here's
260
- a gist showing a bit more interesting deploy.rake file for post_setup and
261
- post_deploy work:
262
-
263
- https://gist.github.com/47e23f2980943531beeb
264
-
265
- On the radar for an upcoming release are:
266
-
267
- - common post_* recipes being specifiable by symbol names in deploy.yml ?
268
- - bringing in a very simplified version of mislav/git-deploy
269
- post-{receive,reset} hooks, and a little sugar so you can say:
270
-
271
- task :post_deploy do
272
- if has_changes?('db/migrate') or has_changes?('config/database.yml')
273
- Rake::Task['db:migrate'].invoke
274
- end
275
- end
276
-
277
-
278
- Resources:
279
- - http://github.com/blog/470-deployment-script-spring-cleaning
280
- - http://github.com/mislav/git-deploy
281
- - http://toroid.org/ams/git-website-howto
282
-
283
-