50

I'm using Capistrano run a remote task. My task looks like this:

task :my_task do
  run "my_command"
end

My problem is that if my_command has an exit status != 0, then Capistrano considers it failed and exits. How can I make capistrano keep going when exit when the exit status is not 0? I've changed my_command to my_command;echo and it works but it feels like a hack.

nicholaides
  • 19,211
  • 12
  • 66
  • 82

7 Answers7

79

The simplest way is to just append true to the end of your command.

  task :my_task do
    run "my_command"
  end

Becomes

  task :my_task do
    run "my_command; true"
  end
mthorley
  • 2,592
  • 2
  • 18
  • 8
  • 12
    Not sure what capistano is but I found my way here due to the same problem with bash. And then you can use "my_command || true" instead of "my_command; true" – Zitrax Sep 30 '10 at 16:03
42

For Capistrano 3, you can (as suggested here) use the following:

execute "some_command.sh", raise_on_non_zero_exit: false
Ciryon
  • 2,637
  • 3
  • 31
  • 33
6

The +grep+ command exits non-zero based on what it finds. In the use case where you care about the output but don't mind if it's empty, you'll discard the exit state silently:

run %Q{bash -c 'grep #{escaped_grep_command_args} ; true' }

Normally, I think the first solution is just fine -- I'd make it document itself tho:

cmd = "my_command with_args escaped_correctly"
run %Q{bash -c '#{cmd} || echo "Failed: [#{cmd}] -- ignoring."'}
mrflip
  • 822
  • 6
  • 7
5

I find the easiest option to do this:

run "my_command || :"

Notice: : is the NOP command so the exit code will simply be ignored.

Besi
  • 22,579
  • 24
  • 131
  • 223
5

You'll need to patch the Capistrano code if you want it to do different things with the exit codes; it's hard-coded to raise an exception if the exit status is not zero.

Here's the relevant portion of lib/capistrano/command.rb. The line that starts with if (failed... is the important one. Basically it says if there are any nonzero return values, raise an error.

# Processes the command in parallel on all specified hosts. If the command
# fails (non-zero return code) on any of the hosts, this will raise a
# Capistrano::CommandError.
def process!
  loop do
    break unless process_iteration { @channels.any? { |ch| !ch[:closed] } }
  end

  logger.trace "command finished" if logger

  if (failed = @channels.select { |ch| ch[:status] != 0 }).any?
    commands = failed.inject({}) { |map, ch| (map[ch[:command]] ||= []) << ch[:server]; map }
    message = commands.map { |command, list| "#{command.inspect} on #{list.join(',')}" }.join("; ")
    error = CommandError.new("failed: #{message}")
    error.hosts = commands.values.flatten
    raise error
  end

  self
end
Sarah Mei
  • 18,154
  • 5
  • 45
  • 45
  • I guess this is only for Capistrano 2, for Capistrano 3, you can use [Ciryon’s answer](http://stackoverflow.com/a/23424213/345959) – Smar Feb 20 '17 at 15:47
2

I just redirect STDERR and STDOUT to /dev/null, so your

run "my_command"

becomes

run "my_command > /dev/null 2> /dev/null"

this works for standard unix tools pretty well, where, say, cp or ln could fail, but you don't want to halt deployment on such a failure.

Terry
  • 1,088
  • 6
  • 10
0

I not sure what version they added this code but I like handling this problem by using raise_on_non_zero_exit

namespace :invoke do
  task :cleanup_workspace do
    on release_roles(:app), in: :parallel do
      execute 'sudo /etc/cron.daily/cleanup_workspace', raise_on_non_zero_exit: false
    end
  end
end

Here is where that feature is implemented in the gem. https://github.com/capistrano/sshkit/blob/4cfddde6a643520986ed0f66f21d1357e0cd458b/lib/sshkit/command.rb#L94

User128848244
  • 3,250
  • 3
  • 24
  • 22