Skip to content

Instantly share code, notes, and snippets.

@sharplet
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sharplet/bb41ea90413f453b53b5 to your computer and use it in GitHub Desktop.
Save sharplet/bb41ea90413f453b53b5 to your computer and use it in GitHub Desktop.
Normally a rake task won't complete if one of its prerequisites fails. Define a composite task to allow them all to run, capturing exceptions and reporting them only after all have completed.
# Take for example a convenience task, all_tests, that runs our app's
# test suite for multiple architectures:
#
# task :all_tests => [:test_64_bit, :test_32_bit]
#
# Defined as a regular task, Rake will bail out early if
# test_64_bit failed, never getting to the 32 bit tests.
#
# A composite task is almost identical in declaration:
#
# composite :all_tests => [:test_64_bit, :test_32_bit]
#
# This task will instead run *all* its prerequisites, recording if
# they fail, and only reporting failures once all tasks have completed.
#
class CompositeTask < Rake::Task
attr_reader :failures
# Hook into prerequisite invocation to add exception handling
# to each one.
def invoke_prerequisites(*args)
failures = []
prerequisite_tasks.each do |p|
p.define_singleton_method(:execute) do |*args|
begin
super(*args)
failures << nil
rescue => e
failures << e
end
end
end
super(*args).tap { @failures = failures }
end
# When executing this task, see if any failures were reported
# and re-raise them.
def execute(*args)
super(*args)
failed_commands = prerequisite_tasks.zip(failures).delete_if { |_, failure| failure.nil? }
unless failed_commands.empty?
# TODO: work out how to re-raise more than just the first failure
raise failed_commands.map { |_, ex| ex }.first
end
end
end
def composite(*args, &block)
CompositeTask.define_task(*args, &block)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment