From 825bdec74dd2b94f251881615900442ded22cc26 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Mon, 5 Aug 2013 21:03:18 +0000 Subject: [PATCH] Improve `sh' task action error handling: Handle exit status code in Remote#execute. --- features/actions/sh.feature | 13 +++++++++++++ lib/producer/core/errors.rb | 9 +++++---- lib/producer/core/remote.rb | 13 +++++++++++-- spec/producer/core/remote_spec.rb | 10 ++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/features/actions/sh.feature b/features/actions/sh.feature index 2ff5343..2b23a59 100644 --- a/features/actions/sh.feature +++ b/features/actions/sh.feature @@ -24,3 +24,16 @@ Feature: sh task action """ When I execute the recipe Then the output must contain "from remote" + + Scenario: aborts on failed command execution + Given a recipe with: + """ + target 'some_host.test' + + task :some_task do + sh '\false' + sh '\echo after_fail' + end + """ + When I execute the recipe + Then the output must not contain "after_fail" diff --git a/lib/producer/core/errors.rb b/lib/producer/core/errors.rb index f87d2d7..901946a 100644 --- a/lib/producer/core/errors.rb +++ b/lib/producer/core/errors.rb @@ -1,8 +1,9 @@ module Producer module Core - Error = Class.new(StandardError) - ConditionNotMetError = Class.new(Error) - RecipeEvaluationError = Class.new(StandardError) - TaskEvaluationError = Class.new(RecipeEvaluationError) + Error = Class.new(StandardError) + ConditionNotMetError = Class.new(Error) + RecipeEvaluationError = Class.new(StandardError) + TaskEvaluationError = Class.new(RecipeEvaluationError) + RemoteCommandExecutionError = Class.new(Error) end end diff --git a/lib/producer/core/remote.rb b/lib/producer/core/remote.rb index aa14a10..998b679 100644 --- a/lib/producer/core/remote.rb +++ b/lib/producer/core/remote.rb @@ -16,8 +16,17 @@ module Producer def execute(command) output = '' - session.exec command do |ch, stream, data| - output << data + session.open_channel do |channel| + channel.exec command do |ch, success| + ch.on_data do |c, data| + output << data + end + + ch.on_request('exit-status') do |c, data| + exit_status = data.read_long + raise RemoteCommandExecutionError if exit_status != 0 + end + end end session.loop output diff --git a/spec/producer/core/remote_spec.rb b/spec/producer/core/remote_spec.rb index 2c373cb..c1435eb 100644 --- a/spec/producer/core/remote_spec.rb +++ b/spec/producer/core/remote_spec.rb @@ -49,6 +49,16 @@ module Producer::Core end expect(remote.execute(command)).to eq arguments end + + it 'raises an exception when the exit status code is not 0' do + story_with_new_channel do |ch| + ch.sends_exec command + ch.gets_data arguments + ch.gets_exit_status 1 + end + expect { remote.execute(command) } + .to raise_error(RemoteCommandExecutionError) + end end end end