How can I have an rcov task know if a subtask failed? - ruby

I have this task:
task :all => ['foo', 'bar', 'announce_success']
If foo and bar don't raise exceptions, then announce_success happens. How can I have a particular task or code block execute if they do raise exceptions?

The way you have defined your tasks will cause rake to exit as soon as one of the dependencies fails/raises and exception. This is the core functionality of rake.
One way to work around though is to do something like
task :all do
task :tmp => ['foo','bar']
begin
Rake::Task[:tmp].invoke
rescue
#do something with the exception
end
end

Unfortunately that goes against the grain of Rake.
Ruby has an at_exit hook you can add a block of code to, if you want to run a bit of cleanup when Rake terminates. You can combine rake-tasks and at_exit hook like this:
task :cleanup do
at_exit {
# cleanup code here
}
end
Just make sure :cleanup is executed early in the list of dependencies.

Related

Can I catch errors and continue to next Rake task?

I invoke Rake tasks in another Rake task like following:
namespace :test do
task :migrate do
Rake::Task['A:migrate'].invoke
Rake::Task['B:migrate'].invoke
end
end
What I want to know is whether I can continue to the next Rake task even if the earlier one fails. For instance, there is an error in A:migrate, I want to catch it and log it but move ahead with B:migrate. How can I do this?
Rake is just Ruby, so you can use Ruby's error handling feature.
namespace :test do
task :migrate do
begin
Rake::Task['A:migrate'].invoke
rescue => e
log(e)
end
Rake::Task['B:migrate'].invoke
end
end

Rake task return value for Ruby system() call

I have a Rake task which looks something like the following. What I’m trying to do run a system command, and return its error-value. Before returning I’d like to display a message saying something like “[OK]” or “[FAILED]".
With this code, Rake returns success every time.
How do I get the Rake task to return the correct error value?
task :build do
status = system BUILD_SHELL_COMMAND
puts status ? "[OK]" : "[FAILED]"
status
end
It appears there isn’t a way to specify a “return value” from a rake task. The task should fail if the system() method fails.
The standard way to do this would be to use Rake’s sh utility method:
task :build do
sh BUILD_SHELL_COMMAND
end
To display an error/success message however, for the case in question, the following would not work:
task :build do
sh BUILD_SHELL_COMMAND or fail “[FAILED]”
puts “[OK]"
end
because as soon as the shell command fails, it would not display the failure message (which in reality would be a longer non-trivial message :), which is what we want.
This works:
task :build do
system BUILD_SHELL_COMMAND or fail “[FAILED]”
puts “[OK]"
end

Run rake tasks in sequence

I have rake tasks which i want to run in proper sequence.
I want to run one rake task which run other rake tasks in proper sequence.
How may i do that?
you should consider defining dependencies between your tasks like this
task :primary => [:secondary]
task :secondary do
puts "Doing Secondary Task"
end
But if you really, really need to call the tasks directly you can use invoke to call another task
task :primary do
Rake::Task[:secondary].invoke
end
task :secondary do
puts "Doing Secondary Task"
end
see also here

How do I return early from a rake task?

I have a rake task where I do some checks at the beginning, if one of the checks fails I would like to return early from the rake task, I don't want to execute any of the remaining code.
I thought the solution would be to place a return where I wanted to return from the code but I get the following error
unexpected return
A Rake task is basically a block. A block, except lambdas, doesn't support return but you can skip to the next statement using next which in a rake task has the same effect of using return in a method.
task :foo do
puts "printed"
next
puts "never printed"
end
Or you can move the code in a method and use return in the method.
task :foo do
do_something
end
def do_something
puts "startd"
return
puts "end"
end
I prefer the second choice.
You can use abort(message) from inside the task to abort that task with a message.
Return with an Error ❌
If you're returning with an error (i.e. an exit code of 1) you'll want to use abort, which also takes an optional string param that will get outputted on exit:
task :check do
# If any of your checks fail, you can exit early like this.
abort( "One of the checks has failed!" ) if check_failed?
end
On the command line:
$ rake check && echo "All good"
#=> One of the checks has failed!
Return with Success ✅
If you're returning without an error (i.e. an exit code of 0) you'll want to use exit, which does not take a string param.
task :check do
# If any of your checks fail, you can exit early like this.
exit if check_failed?
end
On the command line:
$ rake check && echo "All good"
#=> All good
This is important if you're using this in a cron job or something that needs to do something afterwards based on whether the rake task was successful or not.
Bonus: Return with an Error from a rescue block without the stacktrace.
By default, if you use abort inside of a rescue block, it will output the entire stack trace, even if you just use abort without re-raising the error.
To get around this, you can supply a non-zero exit code to the exit command, like:
task :check do
begin
do_the_thing_that_raises_an_exception
rescue => error
puts error.message
exit( 1 )
end
end
I tend to use abort which is a better alternative in such situations, for example:
task :foo do
something = false
abort 'Failed to proceed' unless something
end
If you need to break out of multiple block levels, you can use fail.
For example
task :something do
[1,2,3].each do |i|
...
fail "some error" if ...
end
end
(See https://stackoverflow.com/a/3753955/11543.)
If you meant exiting from a rake task without causing the "rake aborted!" message to be printed, then you can use either "abort" or "exit". But "abort", when used in a rescue block, terminates the task as well as prints the whole error (even without using --trace). So "exit" is what I use.
I used next approach suggested by Simone Carletti, since when testing rake task, abort, which in fact is just a wrapper for exit, is not the desired behavior.
Example:
task auto_invoice: :environment do
if Application.feature_disabled?(:auto_invoice)
$stderr.puts 'Feature is disabled, aborting.'
next
end

Rescue RuntimeError in Rake

I have a custom Rakefile which calls different file tasks. Sometimes a file that is expected doesn't exist, and rake throws a RuntimeError and fails. However, I'd like to do a few things before it fails. So is there any way I could rescue a RuntimeError? Or is there some sort of a magic task which gets called before a complete fail?
I haven't run into this issue with rake myself, but you could try simply wrapping your call to the file tasks in a begin-rescue block, i.e.
begin
file_task
rescue RuntimeError => e
puts e
end
and then do your rescuing in the rescue block.

Resources