Skip to content

Commit

Permalink
Merge pull request #50 from rgo/ticket-193-alias-task
Browse files Browse the repository at this point in the history
Alias Task.
  • Loading branch information
leehambley committed Dec 11, 2011
2 parents 0b7c374 + ce70379 commit 45ed097
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 9 deletions.
3 changes: 2 additions & 1 deletion lib/capistrano/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require 'capistrano/logger'

require 'capistrano/configuration/alias_task'
require 'capistrano/configuration/callbacks'
require 'capistrano/configuration/connections'
require 'capistrano/configuration/execution'
Expand Down Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions lib/capistrano/configuration/alias_task.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion lib/capistrano/configuration/execution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,4 @@ def invoke_task_directly(task)
end
end
end
end
end
18 changes: 12 additions & 6 deletions lib/capistrano/configuration/namespaces.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions lib/capistrano/task_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
110 changes: 110 additions & 0 deletions test/configuration/alias_task_test.rb
Original file line number Diff line number Diff line change
@@ -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
15 changes: 14 additions & 1 deletion test/task_definition_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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})")
Expand Down Expand Up @@ -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.