Show command when remote execution fail

This commit is contained in:
Thibault Jouan 2014-05-25 15:51:33 +00:00
parent 8168e68a2d
commit 0db2d90b72
6 changed files with 61 additions and 19 deletions

View File

@ -37,3 +37,15 @@ Feature: `sh' task action
""" """
When I execute the recipe When I execute the recipe
Then the output must not contain "after_fail" Then the output must not contain "after_fail"
Scenario: prints command when execution fail
Given a recipe with:
"""
target 'some_host.test'
task :some_task do
sh '\false'
end
"""
When I execute the recipe
Then the output must match /\A\w+Error:\s+\\false/

View File

@ -5,18 +5,22 @@ module Producer
USAGE = "Usage: #{File.basename $0} [-v] [-n] recipe_file".freeze USAGE = "Usage: #{File.basename $0} [-v] [-n] recipe_file".freeze
EX_USAGE = 64 EX_USAGE = 64
EX_SOFTWARE = 70
class << self class << self
def run!(arguments, output: $stderr) def run!(arguments, output: $stderr)
cli = new(arguments)
begin begin
cli = new(arguments)
cli.parse_arguments! cli.parse_arguments!
cli.run
rescue ArgumentError rescue ArgumentError
output.puts USAGE output.puts USAGE
exit EX_USAGE exit EX_USAGE
rescue RuntimeError => e
output.puts "#{e.class.name.split('::').last}: #{e.message}"
exit EX_SOFTWARE
end end
cli.run
end end
end end

View File

@ -1,7 +1,8 @@
module Producer module Producer
module Core module Core
Error = Class.new(StandardError) Error = Class.new(StandardError)
RuntimeError = Class.new(RuntimeError)
ConditionNotMetError = Class.new(Error) ConditionNotMetError = Class.new(Error)
RemoteCommandExecutionError = Class.new(Error) RemoteCommandExecutionError = Class.new(RuntimeError)
end end
end end

View File

@ -32,7 +32,7 @@ module Producer
ch.on_request 'exit-status' do |c, data| ch.on_request 'exit-status' do |c, data|
exit_status = data.read_long exit_status = data.read_long
raise RemoteCommandExecutionError if exit_status != 0 raise RemoteCommandExecutionError, command if exit_status != 0
end end
end end
end end

View File

@ -17,35 +17,33 @@ module Producer::Core
let(:output) { StringIO.new } let(:output) { StringIO.new }
subject(:run) { described_class.run! arguments, output: output } subject(:run) { described_class.run! arguments, output: output }
before { allow(described_class).to receive(:new) { cli } }
it 'builds a new CLI with given arguments' do it 'builds a new CLI with given arguments' do
expect(described_class) expect(described_class).to receive(:new).with(arguments)
.to receive(:new).with(arguments).and_call_original
run run
end end
it 'runs the CLI' do it 'runs the CLI' do
allow(described_class).to receive(:new) { cli }
expect(cli).to receive :run expect(cli).to receive :run
run run
end end
it 'parses CLI arguments' do it 'parses CLI arguments' do
allow(described_class).to receive(:new) { cli }
expect(cli).to receive :parse_arguments! expect(cli).to receive :parse_arguments!
run run
end end
context 'when an argument error is raised' do context 'when an argument error is raised' do
before do before do
allow(described_class).to receive(:new) { cli }
allow(cli).to receive(:parse_arguments!) allow(cli).to receive(:parse_arguments!)
.and_raise described_class::ArgumentError .and_raise described_class::ArgumentError
end end
it 'exits with a return status of 64' do it 'exits with a return status of 64' do
expect { run }.to raise_error(SystemExit) { |e| expect { run }.to raise_error(SystemExit) do |e|
expect(e.status).to eq 64 expect(e.status).to eq 64
} end
end end
it 'prints the usage' do it 'prints the usage' do
@ -53,6 +51,24 @@ module Producer::Core
expect(output.string).to match /\AUsage: .+/ expect(output.string).to match /\AUsage: .+/
end end
end end
context 'when a runtime error is raised' do
before do
allow(cli).to receive(:run)
.and_raise RuntimeError, 'some message'
end
it 'exits with a return status of 70' do
expect { run }.to raise_error(SystemExit) do |e|
expect(e.status).to eq 70
end
end
it 'prints exception name and message' do
trap_exit { run }
expect(output.string).to match /\ARuntimeError: some message/
end
end
end end
describe '#initialize' do describe '#initialize' do

View File

@ -106,14 +106,23 @@ module Producer::Core
expect(output.string).to eq arguments expect(output.string).to eq arguments
end end
it 'raises an exception when the exit status code is not 0' do context 'when command execution fails' do
story_with_new_channel do |ch| before do
ch.sends_exec command story_with_new_channel do |ch|
ch.gets_data arguments ch.sends_exec command
ch.gets_exit_status 1 ch.gets_data arguments
ch.gets_exit_status 1
end
end
it 'raises an exception' do
expect { remote.execute command }
.to raise_error(RemoteCommandExecutionError)
end
it 'includes the command in the exception message' do
expect { remote.execute command }.to raise_error /#{command}/
end end
expect { remote.execute command }
.to raise_error(RemoteCommandExecutionError)
end end
end end