Permalink
Browse files

Release 2.7.0

A fairly substantial release. There are fixes so that current_release
works
during dry-runs, (although, apparently still not with bundler.)

The test-suite was also modified to work with Ruby 1.9.2, except in one
case
where Ruby 1.9.x calls `to_ary` and `to_a` on mocks, which still makes
an
error. 1.9.x has always been supported, but due to lack of maintenance
on my
part the tests didn't ever pass.

The `start`, `stop` and `restart` tasks have been reduced to mere hooks
into
which extensions can define their own functionality.

The `readme` was also slightly improved, simply tweaks to express how
best to
run the test suite.

* Ensure dry-run works with `:current_release` variable (Carol Nichols)
* Added a new variable `:git_submodules_recursive`, setting the value to
* false
will ensure Git doesn't recursively initialize and checkout submodules.
(Konstantin Kudryashov)
* Added an additional task option, `:on_no_matching_servers`, setting
* the
value to `:continue` will ensure tasks with no matched servers continue
without error, instead of raising `Capistrano::NoMatchingServersError`
as was
the previous behaviour. (Chris Griego)

A huge thanks to all contributors, as always!

Remember: @capistranorb on twitter for news.
  • Loading branch information...
1 parent edf7092 commit dd21c0f819cbcb14e393b0ca30a805c592f507a0 @leehambley leehambley committed Aug 3, 2011
View
10 Gemfile
@@ -3,4 +3,12 @@ source "http://rubygems.org"
# Specify your gem's dependencies in capistrano.gemspec
gemspec
-gem "rake"
+#
+# Development Dependencies from the Gemfile
+# are merged here.
+#
+group :development do
+ gem 'rake'
+ gem 'ruby-debug', :platform => :mri_18
+ gem 'ruby-debug19', :platform => :mri_19
+end
View
@@ -1,8 +1,15 @@
## Capistrano
-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.
+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.
-Capistrano was originally designed to simplify and automate deployment of web applications to distributed environments, and originally came bundled with a set of tasks designed for deploying Rails applications.
+Capistrano was originally designed to simplify and automate deployment of web
+applications to distributed environments, and originally came bundled with a set
+of tasks designed for deploying Rails applications.
## Documentation
@@ -16,17 +23,18 @@ Capistrano was originally designed to simplify and automate deployment of web ap
* [Net::SSH::Gateway](http://net-ssh.rubyforge.org)
* [HighLine](http://highline.rubyforge.org)
-If you want to run the tests, you'll also need to have the following dependencies installed:
-
-* [Echoe](https://github.com/fauna/echoe)
-* [Mocha](http://mocha.rubyforge.org)
+If you want to run the tests, you'll also need to install the dependencies with
+Bundler, see the `Gemfile` within .
## ASSUMPTIONS
-Capistrano is "opinionated software", which means it has very firm ideas about how things ought to be done, and tries to force those ideas on you. Some of the assumptions behind these opinions are:
+Capistrano is "opinionated software", which means it has very firm ideas about
+how things ought to be done, and tries to force those ideas on you. Some of the
+assumptions behind these opinions are:
* You are using SSH to access the remote servers.
-* You either have the same password to all target machines, or you have public keys in place to allow passwordless access to them.
+* You either have the same password to all target machines, or you have public
+ keys in place to allow passwordless access to them.
Do not expect these assumptions to change.
@@ -39,9 +47,12 @@ In general, you'll use Capistrano as follows:
Use the `cap` script as follows:
- cap sometask
+ cap sometask
-By default, the script will look for a file called one of `capfile` or `Capfile`. The `someaction` text indicates which task to execute. You can do "cap -h" to see all the available options and "cap -T" to see all the available tasks.
+By default, the script will look for a file called one of `capfile` or
+`Capfile`. The `someaction` text indicates which task to execute. You can do
+"cap -h" to see all the available options and "cap -T" to see all the available
+tasks.
## LICENSE:
@@ -33,7 +33,7 @@ The following options are understood:
<%= color '-n, --dry-run', :bold %>
Causes Capistrano to simply display each remote command, without executing it. In this sense it is similar to --debug, but without the prompt. Note that commands executed locally are still run--only remote commands are skipped.
-
+
<%= color '-p, --password', :bold %>
Normally, cap will prompt for the password on-demand, the first time it is needed. This can make it hard to walk away from Capistrano, since you might not know if it will prompt for a password down the road. In such cases, you can use the -p option to force cap to prompt for the password immediately.
@@ -54,9 +54,9 @@ def option_parser #:nodoc:
exit
end
- opts.on("-l", "--logger [STDERR|STDOUT|file]",
+ opts.on("-l", "--logger [STDERR|STDOUT|file]",
"Choose logger method. STDERR used by default."
- ) do |value|
+ ) do |value|
options[:output] = if value.nil? || value.upcase == 'STDERR'
# Using default logger.
nil
@@ -201,7 +201,7 @@ def look_for_default_recipe_file! #:nodoc:
def default_sysconf #:nodoc:
File.join(sysconf_directory, "capistrano.conf")
end
-
+
def default_dotfile #:nodoc:
File.join(home_directory, ".caprc")
end
@@ -211,7 +211,7 @@ def sysconf_directory #:nodoc:
# appropriate location for this file in Windows.
ENV["SystemRoot"] || '/etc'
end
-
+
def home_directory #:nodoc:
ENV["HOME"] ||
(ENV["HOMEPATH"] && "#{ENV["HOMEDRIVE"]}#{ENV["HOMEPATH"]}") ||
View
@@ -22,7 +22,7 @@ def ui
def password_prompt(prompt="Password: ")
ui.ask(prompt) { |q| q.echo = false }
end
-
+
# Debug mode prompt
def debug_prompt(cmd)
ui.say("Preparing to execute command: #{cmd}")
@@ -37,4 +37,4 @@ def debug_prompt(cmd)
end
end
end
-end
+end
@@ -4,21 +4,21 @@ module Capistrano
# Represents the definition of a single task.
class TaskDefinition
attr_reader :name, :namespace, :options, :body, :desc, :on_error, :max_hosts
-
+
def initialize(name, namespace, options={}, &block)
-
+
if name.to_s =~ /^(?:before_|after_)/
Kernel.warn("[Deprecation Warning] Naming tasks with before_ and after_ is deprecated, please see the new before() and after() methods. (Offending task name was #{name})")
end
-
+
@name, @namespace, @options = name, namespace, options
@desc = @options.delete(:desc)
@on_error = options.delete(:on_error)
@max_hosts = options[:max_hosts] && options[:max_hosts].to_i
@body = block or raise ArgumentError, "a task requires a block"
@servers = nil
end
-
+
# Returns the task's fully-qualified name, including the namespace
def fully_qualified_name
@fully_qualified_name ||= begin
@@ -29,15 +29,15 @@ def fully_qualified_name
end
end
end
-
+
# Returns the description for this task, with newlines collapsed and
# whitespace stripped. Returns the empty string if there is no
# description for this task.
def description(rebuild=false)
@description = nil if rebuild
@description ||= begin
description = @desc || ""
-
+
indentation = description[/\A\s+/]
if indentation
reformatted_description = ""
@@ -4,11 +4,11 @@ module Capistrano
class Version
MAJOR = 2
- MINOR = 6
- PATCH = 1
+ MINOR = 7
+ PATCH = 0
def self.to_s
- "#{MAJOR}.#{MINOR}.#{PATCH}.pre"
+ "#{MAJOR}.#{MINOR}.#{PATCH}"
end
end
View
@@ -214,7 +214,9 @@ def test_process_should_loop_until_all_channels_are_closed
mock_session(new_channel[10]),
mock_session(new_channel[7])]
cmd = Capistrano::Command.new("ls", sessions)
- assert_nothing_raised { cmd.process! }
+ assert_nothing_raised do
+ cmd.process!
+ end
end
def test_process_should_instantiate_command_and_process!
@@ -240,11 +242,12 @@ def test_process_with_unknown_placeholder_should_not_replace_placeholder
private
def mock_session(channel=nil)
- stub('session', :open_channel => channel,
- :preprocess => true,
- :postprocess => true,
- :listeners => {},
- :xserver => server("capistrano"))
+ stub('session',
+ :open_channel => channel,
+ :preprocess => true,
+ :postprocess => true,
+ :listeners => {},
+ :xserver => server("capistrano"))
end
class MockChannel < Hash
@@ -71,7 +71,7 @@ def test_connection_factory_as_gateway_should_honor_config_options
Net::SSH::Gateway.expects(:new).with("gateway", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
end
-
+
def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_an_array
@config.values[:gateway] = ["j@gateway1", "k@gateway2"]
gateway1 = mock
@@ -80,7 +80,7 @@ def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable
Net::SSH::Gateway.expects(:new).with("127.0.0.1", "k", :port => 65535, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
end
-
+
def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_a_hash
@config.values[:gateway] = { ["j@gateway1", "k@gateway2"] => :default }
gateway1 = mock
@@ -89,7 +89,7 @@ def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable
Net::SSH::Gateway.expects(:new).with("127.0.0.1", "k", :port => 65535, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
end
-
+
def test_connection_factory_as_gateway_should_share_gateway_between_connections
@config.values[:gateway] = "j@gateway"
Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
@@ -98,7 +98,7 @@ def test_connection_factory_as_gateway_should_share_gateway_between_connections
@config.establish_connections_to(server("capistrano"))
@config.establish_connections_to(server("another"))
end
-
+
def test_connection_factory_as_gateway_should_share_gateway_between_like_connections_if_gateway_variable_is_a_hash
@config.values[:gateway] = { "j@gateway" => [ "capistrano", "another"] }
Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
@@ -107,7 +107,7 @@ def test_connection_factory_as_gateway_should_share_gateway_between_like_connect
@config.establish_connections_to(server("capistrano"))
@config.establish_connections_to(server("another"))
end
-
+
def test_connection_factory_as_gateways_should_not_share_gateway_between_unlike_connections_if_gateway_variable_is_a_hash
@config.values[:gateway] = { "j@gateway" => [ "capistrano", "another"], "k@gateway2" => "yafhost" }
Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
@@ -123,23 +123,23 @@ def test_establish_connections_to_should_accept_a_single_nonarray_parameter
Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.returns(:success)
assert @config.sessions.empty?
@config.establish_connections_to(server("capistrano"))
- assert ["capistrano"], @config.sessions.keys
+ assert_equal ["capistrano"], @config.sessions.keys.map(&:host)
end
def test_establish_connections_to_should_accept_an_array
Capistrano::SSH.expects(:connect).times(3).returns(:success)
assert @config.sessions.empty?
@config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
- assert %w(cap1 cap2 cap3), @config.sessions.keys.sort
+ assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map(&:host)
end
def test_establish_connections_to_should_not_attempt_to_reestablish_existing_connections
Capistrano::SSH.expects(:connect).times(2).returns(:success)
@config.sessions[server("cap1")] = :ok
@config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
- assert %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
+ assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map(&:host)
end
-
+
def test_establish_connections_to_should_raise_one_connection_error_on_failure
Capistrano::SSH.expects(:connect).times(2).raises(Exception)
assert_raises(Capistrano::ConnectionError) {
@@ -149,7 +149,6 @@ def test_establish_connections_to_should_raise_one_connection_error_on_failure
def test_connection_error_should_include_accessor_with_host_array
Capistrano::SSH.expects(:connect).times(2).raises(Exception)
-
begin
@config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
flunk "expected an exception to be raised"
@@ -158,7 +157,7 @@ def test_connection_error_should_include_accessor_with_host_array
assert_equal %w(cap1 cap2), e.hosts.map { |h| h.to_s }.sort
end
end
-
+
def test_connection_error_should_only_include_failed_hosts
Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
@@ -262,7 +261,7 @@ def test_execute_on_servers_with_once_option_should_establish_connection_to_and_
assert block_called
assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
end
-
+
def test_execute_servers_should_raise_connection_error_on_failure_by_default
@config.current_task = mock_task
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1")])
@@ -273,7 +272,7 @@ def test_execute_servers_should_raise_connection_error_on_failure_by_default
end
end
end
-
+
def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_errors_continue
@config.current_task = mock_task(:on_error => :continue)
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2")])
@@ -285,7 +284,7 @@ def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_er
end
}
end
-
+
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_connection_errors_with_on_errors_continue
list = [server("cap1"), server("cap2")]
@config.current_task = mock_task(:on_error => :continue)
@@ -300,7 +299,7 @@ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_connection_e
assert_equal %w(cap2), servers.map { |s| s.host }
end
end
-
+
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_errors_with_on_errors_continue
cap1 = server("cap1")
cap2 = server("cap2")
@@ -317,7 +316,7 @@ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_erro
assert_equal %w(cap2), servers.map { |s| s.host }
end
end
-
+
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_transfer_errors_with_on_errors_continue
cap1 = server("cap1")
cap2 = server("cap2")
@@ -334,7 +333,7 @@ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_transfer_err
assert_equal %w(cap2), servers.map { |s| s.host }
end
end
-
+
def test_connect_should_establish_connections_to_all_servers_in_scope
assert @config.sessions.empty?
@config.current_task = mock_task
@@ -343,7 +342,7 @@ def test_connect_should_establish_connections_to_all_servers_in_scope
@config.connect!
assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
end
-
+
def test_execute_on_servers_should_only_run_on_tasks_max_hosts_hosts_at_once
cap1 = server("cap1")
cap2 = server("cap2")
@@ -361,7 +360,7 @@ def test_execute_on_servers_should_only_run_on_tasks_max_hosts_hosts_at_once
end
assert_equal 2, block_called
end
-
+
def test_execute_on_servers_should_only_run_on_max_hosts_hosts_at_once
cap1 = server("cap1")
cap2 = server("cap2")
@@ -379,7 +378,7 @@ def test_execute_on_servers_should_only_run_on_max_hosts_hosts_at_once
end
assert_equal 2, block_called
end
-
+
def test_execute_on_servers_should_cope_with_already_dropped_connections_when_attempting_to_close_them
cap1 = server("cap1")
cap2 = server("cap2")
@@ -397,7 +396,7 @@ def test_execute_on_servers_should_cope_with_already_dropped_connections_when_at
@config.execute_on_servers {}
@config.execute_on_servers {}
end
-
+
def test_connect_should_honor_once_option
assert @config.sessions.empty?
@config.current_task = mock_task
Oops, something went wrong.

0 comments on commit dd21c0f

Please sign in to comment.