capistrano 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,241 @@
1
+ *SVN*
2
+
3
+ * Add experimental 'shell' task [Jamis Buck]
4
+
5
+ * Display file for external configurations, rather than inspected proc. [Jamis Buck]
6
+
7
+ * Connect to multiple servers in parallel, rather than serially. [Jamis Buck]
8
+
9
+ * Add SCM module for Mercurial (closes #4150) [Matthew Elder]
10
+
11
+ * Remove unused line in SCM::Base (closes #5619) [chris@seagul.co.uk]
12
+
13
+ * More efficient "svn log" usage (closes #5620) [Anatol Pomozov]
14
+
15
+ * Better support for key passphrases in the SVN module (closes #5920) [llasram@gmail.com]
16
+
17
+ * Fix missing default for :local in cvs.rb (closes #3645) [jeremy@hinegardner.org]
18
+
19
+ * Fix awkward spacing in gemspec file (closes #3888) [grant@antiflux.org]
20
+
21
+ * Add support for :sudo variable to specify path to sudo (closes #4578) [timothee.peignier@tryphon.org]
22
+
23
+ * Make previous_release return nil if there are no previous releases (closes #4959) [bdabney@cavoksolutions.com]
24
+
25
+ * Uncache releases list after update_code is called so that newly released dir is included (closes #3766) [Jamis Buck]
26
+
27
+ * Allow the subversion scm to accept HTTPS certificates (closes #4792) [Jamis Buck]
28
+
29
+ * Make sure rollbacks occur within the scope of the task that triggered them [Jamis Buck]
30
+
31
+ * Fixed the default recipe to work with setups that haven't yet gone pids [DHH]
32
+
33
+ * Symlink and setup for shared/pids to tmp/pids [DHH]
34
+
35
+ * Fix some incorrect usage text (closes #4507) [gerry_shaw@yahoo.com]
36
+
37
+ * Added Actor#stream method that makes it easy to create cross-server streams [DHH]. Example:
38
+
39
+ desc "Run a tail on multiple log files at the same time"
40
+ task :tail_fcgi, :roles => :app do
41
+ stream "tail -f #{shared_path}/log/fastcgi.crash.log"
42
+ end
43
+
44
+ * Make update_code and symlink a macro task under the name "update" for easy of deploy to servers that does not run fcgis [DHH]
45
+
46
+ * Changed setup, update_code, rollback_code, and symlink to work on all servers instead of only those in the :app, :web, and :db roles. A server can opt out of being part of the release deployment by setting :no_release => true [DHH]
47
+
48
+ * Added support for :except on task declarations as the opposite of :only [DHH]. Example:
49
+
50
+ role :app, "192.168.0.2"
51
+ role :file, "192.168.0.3", :no_release => true
52
+
53
+ task :symlink, :except => { :no_release => true } do
54
+ on_rollback { run "ln -nfs #{previous_release} #{current_path}" }
55
+ run "ln -nfs #{current_release} #{current_path}"
56
+ end
57
+
58
+ cap symlink # will not run on 192.168.0.3
59
+
60
+ * Deprecate the -r/--recipe switch in favor of -f/--file (for more make/rake-like semantics) [Jamis Buck]
61
+
62
+ * Fix gemspec to include a dependency on rake 0.7 [Jamis Buck]
63
+
64
+ * Added respect for ENV["HOSTS"] that'll be used instead of the roles specified in the task definition [DHH]. Example:
65
+
66
+ HOSTS=192.168.0.1 cap setup # one-off setup for that server, doesn't need to be prespecified in the recipes file
67
+
68
+ * Added respect for ENV["ROLES"] that'll be used instead of the roles specified in the task definition [DHH]. Example:
69
+
70
+ task :setup, :roles => [ :app, :web, :db ]
71
+ # normally this would run every where
72
+ end
73
+
74
+ ROLES=app cap setup # this will only run for the app role, overwritting the default declaration
75
+
76
+ * Added :hosts option to task definition that allows you to specify cross-cutting tasks [DHH]. Example:
77
+
78
+ task :setup, :hosts => [ "06.example.com", "01.example.com" ] do
79
+ # this task will happen on 06 and 01 regardless of which roles they belong to
80
+ end
81
+
82
+ * Fix operator precedence problem in script for touching the revisions.log #3223 [jason.garber@emu.edu]
83
+
84
+
85
+ *1.1.0* (March 6th, 2006)
86
+
87
+ * Simplify the generated capistrano.rake file, and make it easier to customize
88
+
89
+ * Use rake-like command-line semantics ("cap deploy", in addition to "cap -a deploy")
90
+
91
+ * Rename to capistrano
92
+
93
+ * Make the generated capistrano.rake file use rake namespaces, and include all default tasks
94
+
95
+ * Look for config/deploy.rb, capfile, and Capfile by default
96
+
97
+
98
+ *1.0.1* (February 20th, 2006)
99
+
100
+ * Fix broken switchtower_invoke function in switchtower.rake (missing require statement)
101
+
102
+
103
+ *1.0.0* (Feburary 18th, 2006)
104
+
105
+ * Make CVS module's :local value default to "."
106
+
107
+ * Add "invoke" task for executing one-off commands
108
+
109
+ * Make port selection smarter for gateway connections
110
+
111
+ * Add extension mechanism for custom ST operations and third-party task libraries
112
+
113
+ * Make ST rails rake tasks more configurable
114
+
115
+ * Add Actor#current_task and simplify Task#servers
116
+
117
+ * Add Actor#connect! method for working around lazy connection establishing
118
+
119
+ * Make sure IO::TRUNC is specified for Net::SFTP uploads (#3510)
120
+
121
+ * Add branch support to CVS [jeremy@hinegardner.org] (#3596)
122
+
123
+ * Add bazaar-ng SCM module [Damien Merenne]
124
+
125
+ * Add optional :svn_username and :svn_password variables
126
+
127
+ * Allow Proc-valued variables to be set more conveniently (set(:foo) { "bar" })
128
+
129
+ * Add perforce SCM module [Richard McMahon]
130
+
131
+ * Add bazaar (v1) SCM module [Edd Dumbill] (#3533)
132
+
133
+ * Fix stftime format string used in CVS module to be Windows-compatible (fixes #3383)
134
+
135
+ * Add an better error when a task is run and no servers match the required conditions
136
+
137
+ * Add default spinner and cold_deploy tasks, and spinner_user variable
138
+
139
+ * Changed restart_via variable to (boolean) use_sudo
140
+
141
+ * Only chmod when the revisions.log file is first created
142
+
143
+ * Make UPPERCASE variables work
144
+
145
+ * Added rails_env variable (defaults to production) for use by tasks that employ the RAILS_ENV environment variable
146
+
147
+ * Added Actor.default_io_proc
148
+
149
+ * Set :actor key on SSH channel instances
150
+
151
+
152
+ *0.10.0* (January 2nd, 2006)
153
+
154
+ * Handle ssh password prompts like "someone's password:"
155
+
156
+ * Make CLI#echo available as a class method.
157
+
158
+ * Add CLI#with_echo.
159
+
160
+ * Make the default password prompt available as a class method.
161
+
162
+ # Add documentation for the CLI class.
163
+
164
+ * Add a sanity check to make sure the correct versions of Net::SSH and Net::SFTP are installed.
165
+
166
+ * Added a cleanup task to remove unused releases from the deployment directory
167
+
168
+ * Allow password to be reentered on sudo if it was entered incorrectly
169
+
170
+ * Use && as the command separator for the checkouts, so that errors are caught early.
171
+
172
+ * Ping each SSH connection every 1s during command processing so that long-running commands don't cause the connection to timeout.
173
+
174
+ * Add a 0.01s sleep during the command loop so that the CPU doesn't go ballistic while ST is doing its thing.
175
+
176
+ * Add :restart_via variable for specifying whether restart ought to use :sudo (default, use sudo)
177
+
178
+ * Use SFTP for file transfers (if available).
179
+
180
+ * Add an "update_current" task that will do an svn up on the current release
181
+
182
+ * Use the :checkout variable to determine what operation to use for svn checkouts (instead of co, like "export").
183
+
184
+ * The Rails rake tasks now load ST directly, instead of invoking it via system
185
+
186
+ * Added ssh_options variable to configure the SSH connection parameters #2734 [jerrett@bravenet.com]
187
+
188
+ * Require Net::SSH 1.0.5
189
+
190
+
191
+ *0.9.0* (October 18th, 2005)
192
+
193
+ * Use process reaper instead of custom reap script for restarting
194
+
195
+ * Use -S switch to set variables before reading recipe files #2242
196
+
197
+ * Have setup.rb create a switchtower.cmd file on Win32 platforms #2402
198
+
199
+ * Add diff_from_last_deploy to the rails switchtower rakefile template
200
+
201
+ * Add diff_from_last_deploy task (currently only works with subversion)
202
+
203
+ * Add deploy_with_migrations task.
204
+
205
+ * Make the migrate task more customizable.
206
+
207
+ * If no password is given with the -p switch, prompt for password immediately.
208
+
209
+ * Do not install a switchtower stub in the script directory. Assume the switchtower executable is in the path.
210
+
211
+ * Remove trailing newlines from commands to prevent trailing backslash #2141
212
+
213
+ * Default parameters work correctly with the generator #2218 [Scott Barron]
214
+
215
+ * Attempt to require 'rubygems' explicitly when running the switchtower utility #2134
216
+
217
+ * Make default tasks work only on app/db/web roles, so that additional roles may be created for boxes with specific needs without needing to (for instance) deploy the app to those boxes
218
+
219
+ * Default the application name to "Application" when using --apply-to
220
+
221
+ * Show the help screen instead of an error when no arguments are given
222
+
223
+ * Make SwitchTower easier to invoke programmatically via SwitchTower::CLI
224
+
225
+ * Specify the revision to release via the :revision variable (defaults to latest revision)
226
+
227
+ * Allow variables to be set via the cli using the -s switch
228
+
229
+ * Log checkouts to a "revisions.log" file
230
+
231
+ * Changed behavior of checkout to use the timestamp as the release name, instead of the revision number
232
+
233
+ * Added CVS module (very very experimental!)
234
+
235
+ * Works with public keys now, for passwordless deployment
236
+
237
+ * Subversion module recognizes the password prompt for HTTP authentication
238
+
239
+ * Preserve +x on scripts when using darcs #1929 [Scott Barron]
240
+
241
+ * When executing multiline commands, use a backslash to escape the newline
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2005,2006 Jamis Buck
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,35 @@
1
+ = Capistrano
2
+
3
+ Capistrano is a utility and framework for executing commands in parallel on multiple remote machines, via SSH. It uses a simple DSL (borrowed in part from Rake, http://rake.rubyforge.org/) that allows you to define _tasks_, which may be applied to machines in certain roles. It also supports tunneling connections via some gateway machine to allow operations to be performed behind VPN's and firewalls.
4
+
5
+ Capistrano was originally designed to simplify and automate deployment of web applications to distributed environments, and so it comes with many tasks predefined for that ("update_code" and "deploy", for instance).
6
+
7
+ == Dependencies
8
+
9
+ Capistrano depends upon the Net::SSH library by Jamis Buck (http://net-ssh.rubyforge.org). Net::SSH itself depends on the Needle library (http://needle.rubyforge.org), also by Jamis Buck.
10
+
11
+ == Assumptions
12
+
13
+ In keeping with Rails' "convention over configuration", Capistrano makes several assumptions about how you will use it (most, if not all, of which may be explicitly overridden):
14
+
15
+ * You are writing web applications and want to use Capistrano to deploy them.
16
+ * You are using Ruby on Rails (http://www.rubyonrails.com) to build your apps.
17
+ * You are using Subversion (http://subversion.tigris.org/) to manage your source code.
18
+ * You are running your apps using FastCGI, together with Rails' spinner/reaper utilities.
19
+
20
+ As with the rest of Rails, if you can abide by these assumptions, you can use Capistrano "out of the box". If any of these assumptions do not hold, you'll need to make some adjustments to your deployment recipe files.
21
+
22
+ == Usage
23
+
24
+ More documentation is always pending, but you'll want to see the user manual for detailed usage instructions. (The manual is online at http://manuals.rubyonrails.org/read/book/17).
25
+
26
+ In general, you'll use Capistrano as follows:
27
+
28
+ * Create a deployment recipe ("deploy.rb") for your application. You can use the sample recipe in examples/sample.rb as a starting point.
29
+ * Use the +cap+ script to execute your recipe (see below).
30
+
31
+ Use the +cap+ script as follows:
32
+
33
+ cap -vvv someaction
34
+
35
+ By default, the script will look for a file called one of <tt>config/deploy</tt>, <tt>config/deploy.rb</tt>, <tt>capistrano</tt>, or <tt>capistrano.rb</tt>. You can the <tt>-v</tt> switch multiple times (as shown) to increase the verbosity of the output. The +someaction+ text indicates which action to execute.
data/THANKS ADDED
@@ -0,0 +1,4 @@
1
+ * Bazaar (v1) SCM Module: Edd Dumbill <edd@usefulinc.com>
2
+ * Perforce SCM Module: Richard McMahon <richie.mcmahon@gmail.com>
3
+ * Bazaar-NG SCM Module: Damien Merenne <dam@capsule.org>
4
+ * Mercurial SCM Module: Matthew Elder <mae@mindflowsolutions.com>
@@ -78,31 +78,65 @@ module Capistrano
78
78
 
79
79
  # Returns the list of servers (_not_ connections to servers) that are
80
80
  # the target of this task.
81
- def servers
82
- unless @servers
83
- roles = [*(@options[:roles] || actor.configuration.roles.keys)].
84
- map { |name|
85
- actor.configuration.roles[name] or
86
- raise ArgumentError, "task #{self.name.inspect} references non-existant role #{name.inspect}"
87
- }.flatten
88
- only = @options[:only] || {}
81
+ def servers(reevaluate=false)
82
+ @servers = nil if reevaluate
83
+ @servers ||=
84
+ if hosts = find_hosts
85
+ hosts
86
+ else
87
+ roles = find_roles
88
+ apply_only!(roles)
89
+ apply_except!(roles)
90
+
91
+ roles.map { |role| role.host }.uniq
92
+ end
93
+ end
94
+
95
+ private
96
+ def find_roles
97
+ role_names = [ *(environment_values(:roles, true) || @options[:roles] || actor.configuration.roles.keys) ]
98
+ role_names.collect do |name|
99
+ actor.configuration.roles[name] ||
100
+ raise(ArgumentError, "task #{self.name.inspect} references non-existant role #{name.inspect}")
101
+ end.flatten
102
+ end
103
+
104
+ def find_hosts
105
+ environment_values(:hosts) || @options[:hosts]
106
+ end
107
+
108
+ def environment_values(key, use_symbols = false)
109
+ if variable = ENV[key.to_s.upcase]
110
+ values = variable.split(",")
111
+ use_symbols ? values.collect { |e| e.to_sym } : values
112
+ end
113
+ end
114
+
115
+ def apply_only!(roles)
116
+ only = @options[:only] || {}
89
117
 
90
118
  unless only.empty?
91
119
  roles = roles.delete_if do |role|
92
120
  catch(:done) do
93
- only.keys.each do |key|
94
- throw(:done, true) if role.options[key] != only[key]
95
- end
121
+ only.keys.each { |key| throw(:done, true) if role.options[key] != only[key] }
96
122
  false
97
123
  end
98
124
  end
99
- end
100
-
101
- @servers = roles.map { |role| role.host }.uniq
125
+ end
102
126
  end
127
+
128
+ def apply_except!(roles)
129
+ except = @options[:except] || {}
103
130
 
104
- @servers
105
- end
131
+ unless except.empty?
132
+ roles = roles.delete_if do |role|
133
+ catch(:done) do
134
+ except.keys.each { |key| throw(:done, true) if role.options[key] == except[key] }
135
+ false
136
+ end
137
+ end
138
+ end
139
+ end
106
140
  end
107
141
 
108
142
  def initialize(config) #:nodoc:
@@ -177,6 +211,27 @@ module Capistrano
177
211
  end
178
212
  end
179
213
 
214
+ # Streams the result of the command from all servers that are the target of the
215
+ # current task. All these streams will be joined into a single one,
216
+ # so you can, say, watch 10 log files as though they were one. Do note that this
217
+ # is quite expensive from a bandwidth perspective, so use it with care.
218
+ #
219
+ # Example:
220
+ #
221
+ # desc "Run a tail on multiple log files at the same time"
222
+ # task :tail_fcgi, :roles => :app do
223
+ # stream "tail -f #{shared_path}/log/fastcgi.crash.log"
224
+ # end
225
+ def stream(command)
226
+ run(command) do |ch, stream, out|
227
+ puts out if stream == :out
228
+ if stream == :err
229
+ puts "[err : #{ch[:host]}] #{out}"
230
+ break
231
+ end
232
+ end
233
+ end
234
+
180
235
  # Deletes the given file from all servers targetted by the current task.
181
236
  # If <tt>:recursive => true</tt> is specified, it may be used to remove
182
237
  # directories.
@@ -210,6 +265,12 @@ module Capistrano
210
265
  # Like #run, but executes the command via <tt>sudo</tt>. This assumes that
211
266
  # the sudo password (if required) is the same as the password for logging
212
267
  # in to the server.
268
+ #
269
+ # Also, this module accepts a <tt>:sudo</tt> configuration variable,
270
+ # which (if specified) will be used as the full path to the sudo
271
+ # executable on the remote machine:
272
+ #
273
+ # set :sudo, "/opt/local/bin/sudo"
213
274
  def sudo(command, options={}, &block)
214
275
  block ||= default_io_proc
215
276
 
@@ -218,7 +279,7 @@ module Capistrano
218
279
  # prompts from that host.
219
280
  prompt_host = nil
220
281
 
221
- run "sudo #{command}", options do |ch, stream, out|
282
+ run "#{sudo_command} #{command}", options do |ch, stream, out|
222
283
  if out =~ /^Password:/
223
284
  ch.send_data "#{password}\n"
224
285
  elsif out =~ /try again/
@@ -293,16 +354,14 @@ module Capistrano
293
354
  # Inspects the remote servers to determine the list of all released versions
294
355
  # of the software. Releases are sorted with the most recent release last.
295
356
  def releases
296
- unless @releases
357
+ @releases ||= begin
297
358
  buffer = ""
298
359
  run "ls -x1 #{releases_path}", :once => true do |ch, str, out|
299
360
  buffer << out if str == :out
300
361
  raise "could not determine releases #{out.inspect}" if str == :err
301
362
  end
302
- @releases = buffer.split.sort
363
+ buffer.split.sort
303
364
  end
304
-
305
- @releases
306
365
  end
307
366
 
308
367
  # Returns the most recent deployed release
@@ -312,7 +371,7 @@ module Capistrano
312
371
 
313
372
  # Returns the release immediately before the currently deployed one
314
373
  def previous_release
315
- release_path(releases[-2])
374
+ release_path(releases[-2]) if releases[-2]
316
375
  end
317
376
 
318
377
  # Invoke a set of tasks in a transaction. If any task fails (raises an
@@ -333,10 +392,16 @@ module Capistrano
333
392
  logger.important "transaction: rollback", current ? current.name : "transaction start"
334
393
  task_call_history.reverse.each do |task|
335
394
  begin
395
+ # throw the task back on the stack so that roles are properly
396
+ # interpreted in the scope of the task in question.
397
+ push_task_call_frame(task.name)
398
+
336
399
  logger.debug "rolling back", task.name
337
400
  task.rollback.call if task.rollback
338
401
  rescue Object => e
339
402
  logger.info "exception while rolling back: #{e.class}, #{e.message}", task.name
403
+ ensure
404
+ pop_task_call_frame
340
405
  end
341
406
  end
342
407
  raise
@@ -376,6 +441,10 @@ module Capistrano
376
441
  end
377
442
 
378
443
  private
444
+
445
+ def sudo_command
446
+ configuration[:sudo] || "sudo"
447
+ end
379
448
 
380
449
  def define_method(name, &block)
381
450
  metaclass.send(:define_method, name, &block)
@@ -393,9 +462,27 @@ module Capistrano
393
462
 
394
463
  def establish_connections(servers)
395
464
  @factory = establish_gateway if needs_gateway?
396
- servers.each do |server|
397
- @sessions[server] ||= @factory.connect_to(server)
465
+ servers = Array(servers)
466
+
467
+ # because Net::SSH uses lazy loading for things, we need to make sure
468
+ # that at least one connection has been made successfully, to kind of
469
+ # "prime the pump", before we go gung-ho and do mass connection in
470
+ # parallel. Otherwise, the threads start doing things in wierd orders
471
+ # and causing Net::SSH to die of confusion.
472
+
473
+ if !@established_gateway && @sessions.empty?
474
+ server, servers = servers.first, servers[1..-1]
475
+ @sessions[server] = @factory.connect_to(server)
398
476
  end
477
+
478
+ servers.map { |server| establish_connection_to(server) }.each { |t| t.join }
479
+ end
480
+
481
+ # We establish the connection by creating a thread in a new method--this
482
+ # prevents problems with the thread's scope seeing the wrong 'server'
483
+ # variable if the thread just happens to take too long to start up.
484
+ def establish_connection_to(server)
485
+ Thread.new { @sessions[server] ||= @factory.connect_to(server) }
399
486
  end
400
487
 
401
488
  def establish_gateway