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

@ -6,17 +6,21 @@ 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)
begin
cli = new(arguments) cli = new(arguments)
begin
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,15 +106,24 @@ 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
before do
story_with_new_channel do |ch| story_with_new_channel do |ch|
ch.sends_exec command ch.sends_exec command
ch.gets_data arguments ch.gets_data arguments
ch.gets_exit_status 1 ch.gets_exit_status 1
end end
end
it 'raises an exception' do
expect { remote.execute command } expect { remote.execute command }
.to raise_error(RemoteCommandExecutionError) .to raise_error(RemoteCommandExecutionError)
end end
it 'includes the command in the exception message' do
expect { remote.execute command }.to raise_error /#{command}/
end
end
end end
describe '#environment' do describe '#environment' do