Permalink
Browse files

Merge pull request #50 from rgo/ticket-193-alias-task

Alias Task.
  • Loading branch information...
2 parents 0b7c374 + ce70379 commit 45ed09761548b75f9d87c52421222289ef7f4b07 @leehambley leehambley committed Dec 11, 2011
@@ -1,5 +1,6 @@
require 'capistrano/logger'
+require 'capistrano/configuration/alias_task'
require 'capistrano/configuration/callbacks'
require 'capistrano/configuration/connections'
require 'capistrano/configuration/execution'
@@ -33,7 +34,7 @@ def initialize(options={}) #:nodoc:
# The includes must come at the bottom, since they may redefine methods
# defined in the base class.
- include Connections, Execution, Loading, Namespaces, Roles, Servers, Variables
+ include AliasTask, Connections, Execution, Loading, Namespaces, Roles, Servers, Variables
# Mix in the actions
include Actions::FileTransfer, Actions::Inspect, Actions::Invocation
@@ -0,0 +1,25 @@
+module Capistrano
+ class Configuration
+ module AliasTask
+ # Attempts to find the task at the given fully-qualified path, and
+ # alias it. If arguments don't have correct task names, an ArgumentError
+ # wil be raised. If no such task exists, a Capistrano::NoSuchTaskError
+ # will be raised.
+ #
+ # Usage:
+ #
+ # alias_task :original_deploy, :deploy
+ #
+ def alias_task(new_name, old_name)
+ if !new_name.respond_to?(:to_sym) or !old_name.respond_to?(:to_sym)
+ raise ArgumentError, "expected a valid task name"
+ end
+
+ task = find_task(old_name) or raise NoSuchTaskError, "the task `#{old_name}' does not exist"
+ task.name = new_name
+
+ define_task(task)
+ end
+ end
+ end
+end
@@ -140,4 +140,4 @@ def invoke_task_directly(task)
end
end
end
-end
+end
@@ -97,12 +97,17 @@ def task(name, options={}, &block)
raise ArgumentError, "defining a task named `#{name}' would shadow an existing #{thing} with that name"
end
- tasks[name] = TaskDefinition.new(name, self, {:desc => next_description(:reset)}.merge(options), &block)
- if !task_already_defined
- metaclass = class << self; self; end
- metaclass.send(:define_method, name) { execute_task(tasks[name]) }
- end
+ task = TaskDefinition.new(name, self, {:desc => next_description(:reset)}.merge(options), &block)
+
+ define_task(task)
+ end
+
+ def define_task(task)
+ tasks[task.name] = task
+
+ metaclass = class << self; self; end
+ metaclass.send(:define_method, task.name) { execute_task(tasks[task.name]) }
end
# Find the task with the given name, where name is the fully-qualified
@@ -189,9 +194,10 @@ def method_missing(sym, *args, &block)
end
end
+ include Capistrano::Configuration::AliasTask
include Capistrano::Configuration::Namespaces
undef :desc, :next_description
end
end
end
-end
+end
@@ -29,6 +29,11 @@ def fully_qualified_name
end
end
end
+
+ def name=(value)
+ raise ArgumentError, "expected a valid task name" if !value.respond_to?(:to_sym)
+ @name = value.to_sym
+ end
# Returns the description for this task, with newlines collapsed and
# whitespace stripped. Returns the empty string if there is no
@@ -0,0 +1,110 @@
+require 'utils'
+require 'capistrano/configuration/alias_task'
+require 'capistrano/configuration/execution'
+require 'capistrano/configuration/namespaces'
+require 'capistrano/task_definition'
+
+class AliasTaskTest < Test::Unit::TestCase
+ class MockConfig
+ attr_reader :options
+ attr_accessor :logger
+
+ def initialize(options={})
+ @options = {}
+ @logger = options.delete(:logger)
+ end
+
+ include Capistrano::Configuration::AliasTask
+ include Capistrano::Configuration::Execution
+ include Capistrano::Configuration::Namespaces
+ end
+
+ def setup
+ @config = MockConfig.new( :logger => stub(:debug => nil, :info => nil, :important => nil) )
+ end
+
+ def test_makes_a_copy_of_the_task
+ @config.task(:foo) { 42 }
+ @config.alias_task 'new_foo', 'foo'
+
+ assert @config.tasks.key?(:new_foo)
+ end
+
+ def test_aliased_task_do_the_same
+ @config.task(:foo) { 42 }
+ @config.alias_task 'new_foo', 'foo'
+
+ assert_equal 42, @config.find_and_execute_task('new_foo')
+ end
+
+ def test_aliased_task_should_preserve_description
+ @config.task(:foo, :desc => "the Ultimate Question of Life, the Universe, and Everything" ) { 42 }
+ @config.alias_task 'new_foo', 'foo'
+
+ task = @config.find_task('foo')
+ new_task = @config.find_task('new_foo')
+
+ assert_equal task.description, new_task.description
+ end
+
+ def test_aliased_task_should_preserve_on_error
+ @config.task(:foo, :on_error => :continue) { 42 }
+ @config.alias_task 'new_foo', 'foo'
+
+ task = @config.find_task('foo')
+ new_task = @config.find_task('new_foo')
+
+ assert_equal task.on_error, new_task.on_error
+ end
+
+ def test_aliased_task_should_preserve_max_hosts
+ @config.task(:foo, :max_hosts => 5) { 42 }
+ @config.alias_task 'new_foo', 'foo'
+
+ task = @config.find_task('foo')
+ new_task = @config.find_task('new_foo')
+
+ assert_equal task.max_hosts, new_task.max_hosts
+ end
+
+ def test_raise_exception_when_task_doesnt_exist
+ assert_raises(Capistrano::NoSuchTaskError) { @config.alias_task 'non_existant_task', 'fail_miserably' }
+ end
+
+ def test_convert_task_names_using_to_str
+ @config.task(:foo, :role => :app) { 42 }
+
+ @config.alias_task 'one', 'foo'
+ @config.alias_task :two, 'foo'
+ @config.alias_task 'three', :foo
+ @config.alias_task :four, :foo
+
+ assert @config.tasks.key?(:one)
+ assert @config.tasks.key?(:two)
+ assert @config.tasks.key?(:three)
+ assert @config.tasks.key?(:four)
+ end
+
+ def test_raise_an_exception_when_task_names_can_not_be_converted
+ @config.task(:foo, :role => :app) { 42 }
+
+ assert_raises(ArgumentError) { @config.alias_task mock('x'), :foo }
+ end
+
+ def test_should_include_namespace
+ @config.namespace(:outer) do
+ task(:foo) { 42 }
+ alias_task 'new_foo', 'foo'
+
+ namespace(:inner) do
+ task(:foo) { 43 }
+ alias_task 'new_foo', 'foo'
+ end
+ end
+
+ assert_equal 42, @config.find_and_execute_task('outer:new_foo')
+ assert_equal 42, @config.find_and_execute_task('outer:foo')
+ assert_equal 43, @config.find_and_execute_task('outer:inner:new_foo')
+ assert_equal 43, @config.find_and_execute_task('outer:inner:foo')
+ end
+end
@@ -25,6 +25,19 @@ def test_fqn_at_top_level_when_default_should_be_default
assert_equal "default", task.fully_qualified_name
end
+ def test_name_should_change_task_name
+ task = new_task(:foo)
+ task.name = :bar
+
+ assert_equal :bar, task.name
+ end
+
+ def test_raise_an_exception_when_task_names_can_not_be_converted
+ task = new_task('valid task name')
+
+ assert_raises(ArgumentError) { task.name = ['invalid task name'] }
+ end
+
def test_deprecation_warning_on_method_name_beginning_with_before_underscore
name = "before_test"
Kernel.expects(:warn).with("[Deprecation Warning] Naming tasks with before_ and after_ is deprecated, please see the new before() and after() methods. (Offending task name was #{name})")
@@ -113,4 +126,4 @@ def test_brief_description_should_not_break_at_period_in_middle_of_sentence
task = new_task(:testing, @namespace, :desc => "Take file.txt and copy it. Then do something else.")
assert_equal "Take file.txt and copy it.", task.brief_description
end
-end
+end

0 comments on commit 45ed097

Please sign in to comment.