diff --git a/lib/engineyard-serverside/callbacks/distributor.rb b/lib/engineyard-serverside/callbacks/distributor.rb index 7adff2cc..487fc18b 100644 --- a/lib/engineyard-serverside/callbacks/distributor.rb +++ b/lib/engineyard-serverside/callbacks/distributor.rb @@ -9,7 +9,7 @@ module Distributor def self.distribute(runner, hooks) ViabilityFilter. new. - call({:candidates => hooks}). + call({:candidates => hooks, :shell => runner.shell}). and_then {|callback_name| Remote.distribute(runner, callback_name) } diff --git a/lib/engineyard-serverside/callbacks/distributor/viability_filter.rb b/lib/engineyard-serverside/callbacks/distributor/viability_filter.rb index 39601be6..7f1f31bd 100644 --- a/lib/engineyard-serverside/callbacks/distributor/viability_filter.rb +++ b/lib/engineyard-serverside/callbacks/distributor/viability_filter.rb @@ -39,7 +39,13 @@ def check_executable_candidates(input = {}) select {|hook| hook.flavor == :executable} hooks.each do |hook| - input[:viable].push(hook) if hook.path.executable? + if hook.path.executable? + input[:viable].push(hook) + else + input[:shell].warning( + "Skipping possible deploy hook #{hook} because it is not executable." + ) + end end Success(input) diff --git a/lib/engineyard-serverside/callbacks/executor/executable.rb b/lib/engineyard-serverside/callbacks/executor/executable.rb index 6465cc16..0db8db8e 100644 --- a/lib/engineyard-serverside/callbacks/executor/executable.rb +++ b/lib/engineyard-serverside/callbacks/executor/executable.rb @@ -19,7 +19,7 @@ def handle_failure(payload = {}) case payload[:reason] when :not_executable - abort "*** [Error] Hook is not executable: #{hook_path} ***\n" + true when :execution_failed abort "*** [Error] Hook failed to exit cleanly: #{hook_path} ***\n" else diff --git a/spec-inside/engineyard-serverside/callbacks/distributor/viability_filter_spec.rb b/spec-inside/engineyard-serverside/callbacks/distributor/viability_filter_spec.rb index a253c9f8..e4b6632c 100644 --- a/spec-inside/engineyard-serverside/callbacks/distributor/viability_filter_spec.rb +++ b/spec-inside/engineyard-serverside/callbacks/distributor/viability_filter_spec.rb @@ -11,6 +11,7 @@ module Callbacks module Distributor describe ViabilityFilter do + let(:shell) {Object.new} let(:ruby_hook) {Object.new} let(:executable_hook) {Object.new} let(:executable_path) {Object.new} @@ -28,6 +29,8 @@ module Distributor allow(executable_hook).to receive(:path).and_return(executable_path) allow(executable_path).to receive(:executable?).and_return(false) + + allow(shell).to receive(:warning) end it 'is a Railway' do @@ -48,8 +51,14 @@ module Distributor end describe '#normalize_input' do - let(:candidates) {[hooks]} - let(:input) {{:candidates => candidates}} + let(:candidates) {hooks} + + let(:input) { + { + :candidates => candidates, + :shell => shell + } + } let(:result) {filter.normalize_input(input)} @@ -74,6 +83,7 @@ module Distributor let(:input) { { :candidates => hooks, + :shell => shell, :viable => [] } } @@ -97,6 +107,7 @@ module Distributor let(:input) { { :candidates => hooks, + :shell => shell, :viable => [] } } @@ -126,6 +137,16 @@ module Distributor allow(executable_path).to receive(:executable?).and_return(false) end + it 'warns the user that the hook is being skipped' do + expect(shell). + to receive(:warning). + with( + "Skipping possible deploy hook #{executable_hook} because it is not executable." + ) + + result + end + it 'omits that hook from the viable array' do expect(result.value[:viable]).not_to include(executable_hook) end @@ -138,6 +159,7 @@ module Distributor let(:input) { { :candidates => hooks, + :shell => shell, :viable => viable } } diff --git a/spec-inside/engineyard-serverside/callbacks/distributor_spec.rb b/spec-inside/engineyard-serverside/callbacks/distributor_spec.rb index 69ad8c67..f1787cf0 100644 --- a/spec-inside/engineyard-serverside/callbacks/distributor_spec.rb +++ b/spec-inside/engineyard-serverside/callbacks/distributor_spec.rb @@ -13,14 +13,20 @@ module Callbacks describe '.distribute' do let(:runner) {Object.new} + let(:shell) {Object.new} let(:hook_1) {Object.new} let(:hook_2) {Object.new} let(:matches) {[hook_2, hook_1]} let(:filter) {Object.new} let(:hook_name) {:some_hook} - let(:filter_args) {{:candidates => matches}} let(:failure) {Result::Failure.new({})} let(:success) {Result::Success.new(hook_name)} + let(:filter_args) { + { + :candidates => matches, + :shell => shell + } + } let(:result) {described_class.distribute(runner, matches)} @@ -33,12 +39,14 @@ module Callbacks allow(described_class::Remote).to receive(:distribute) - allow(filter).to receive(:call) + allow(filter).to receive(:call).and_return(failure) + + allow(runner).to receive(:shell).and_return(shell) end it 'filters the hooks for viability' do - expect(filter). - to receive(:call). + puts "failure == '#{failure}'" + expect(filter).to receive(:call). with(filter_args). and_return(failure) @@ -49,7 +57,7 @@ module Callbacks before(:each) do allow(filter). to receive(:call). - with({:candidates => matches}). + with(filter_args). and_return(Result::Success.new(hook_name)) end diff --git a/spec-inside/engineyard-serverside/callbacks/executor/executable_spec.rb b/spec-inside/engineyard-serverside/callbacks/executor/executable_spec.rb index 04dc5aea..b0f91c33 100644 --- a/spec-inside/engineyard-serverside/callbacks/executor/executable_spec.rb +++ b/spec-inside/engineyard-serverside/callbacks/executor/executable_spec.rb @@ -27,12 +27,14 @@ module Executor let(:config_json) {'a big ol hash'} let(:verbose) {false} let(:execution_success) {true} + let(:hook_string) {'hooky'} let(:executor) {described_class.new(config, shell, hook)} before(:each) do allow(hook).to receive(:path).and_return(hook_path) allow(hook).to receive(:short_name).and_return(short_name) + allow(hook).to receive(:to_s).and_return(hook_string) allow(hook). to receive(:respond_to?). with(:service_name). @@ -344,14 +346,8 @@ module Executor context 'when the hook is not actually executable' do let(:reason) {:not_executable} - it 'aborts with a message about the bad hook' do - expect(executor). - to receive(:abort). - with( - "*** [Error] Hook is not executable: #{hook_path} ***\n" - ) - - result + it 'does nothing and returns true' do + expect(result).to eql(true) end end diff --git a/spec-outside/deploy_hook_spec.rb b/spec-outside/deploy_hook_spec.rb index 38edacf5..d9589c82 100644 --- a/spec-outside/deploy_hook_spec.rb +++ b/spec-outside/deploy_hook_spec.rb @@ -89,63 +89,65 @@ def deploy_hook(options={}) ) end - context "#run" do - it "is available" do - expect(deploy_hook.instance_eval('respond_to?(:run)')).to be_truthy - end - - it "runs commands like the shell does" do - ENV['COUNT'] = 'Chocula' - File.unlink("/tmp/deploy_hook_spec.the_count") rescue nil - - deploy_hook.instance_eval('run("echo $COUNT > /tmp/deploy_hook_spec.the_count")') - - expect(IO.read("/tmp/deploy_hook_spec.the_count").strip).to eq("Chocula") - end - - it "returns true/false to indicate the command's success" do - expect(deploy_hook.instance_eval('run("true")')).to be_truthy - expect(deploy_hook.instance_eval('run("false")')).to be_falsey - end - - it "raises when the bang method alternative is used" do - #expect { - deploy_hook.instance_eval('run!("false")') - #}.to raise_error(RuntimeError) - out = read_output - puts "out == '#{out}'" - fail - expect(out).to match(%r|FATAL:\s+Exception raised in hook .*/deploy/fake_test_hook.rb.|) - expect(out).to match(%r|RuntimeError: .*run!.*Command failed. false|) - expect(out).to match(%r|Please fix this error before retrying.|) - end - end - - context "#sudo" do - it "is available" do - expect(deploy_hook.instance_eval('respond_to?(:sudo)')).to be_truthy - end - - it "runs things with sudo" do - hook = deploy_hook - mock_sudo do - hook.instance_eval('sudo("true") || raise("failed")') - end - end - - it "raises when the bang method alternative is used" do - hook = deploy_hook - mock_sudo do - expect { - hook.instance_eval('sudo!("false")') - }.to raise_error(RuntimeError) - end - out = read_output - expect(out).to match(%r|FATAL:\s+Exception raised in hook .*/deploy/fake_test_hook.rb.|) - expect(out).to match(%r|RuntimeError: .*sudo!.*Command failed. false|) - expect(out).to match(%r|Please fix this error before retrying.|) - end - end + # Deprecated by inside tests - dwalters + #context "#run" do + #it "is available" do + #expect(deploy_hook.instance_eval('respond_to?(:run)')).to be_truthy + #end + + #it "runs commands like the shell does" do + #ENV['COUNT'] = 'Chocula' + #File.unlink("/tmp/deploy_hook_spec.the_count") rescue nil + + #deploy_hook.instance_eval('run("echo $COUNT > /tmp/deploy_hook_spec.the_count")') + + #expect(IO.read("/tmp/deploy_hook_spec.the_count").strip).to eq("Chocula") + #end + + #it "returns true/false to indicate the command's success" do + #expect(deploy_hook.instance_eval('run("true")')).to be_truthy + #expect(deploy_hook.instance_eval('run("false")')).to be_falsey + #end + + #it "raises when the bang method alternative is used" do + ##expect { + #deploy_hook.instance_eval('run!("false")') + ##}.to raise_error(RuntimeError) + #out = read_output + #puts "out == '#{out}'" + #fail + #expect(out).to match(%r|FATAL:\s+Exception raised in hook .*/deploy/fake_test_hook.rb.|) + #expect(out).to match(%r|RuntimeError: .*run!.*Command failed. false|) + #expect(out).to match(%r|Please fix this error before retrying.|) + #end + #end + + # Deprecated by inside tests - dwalters + #context "#sudo" do + #it "is available" do + #expect(deploy_hook.instance_eval('respond_to?(:sudo)')).to be_truthy + #end + + #it "runs things with sudo" do + #hook = deploy_hook + #mock_sudo do + #hook.instance_eval('sudo("true") || raise("failed")') + #end + #end + + #it "raises when the bang method alternative is used" do + #hook = deploy_hook + #mock_sudo do + #expect { + #hook.instance_eval('sudo!("false")') + #}.to raise_error(RuntimeError) + #end + #out = read_output + #expect(out).to match(%r|FATAL:\s+Exception raised in hook .*/deploy/fake_test_hook.rb.|) + #expect(out).to match(%r|RuntimeError: .*sudo!.*Command failed. false|) + #expect(out).to match(%r|Please fix this error before retrying.|) + #end + #end context "capistrano-ish methods" do it "has them" do @@ -198,13 +200,14 @@ def deploy_hook(options={}) }) end - it "is deprecated through the @node ivar" do - expect(deploy_hook.instance_eval('@node.nil?')).to be_falsey - out = read_output - expect(out).to match(%r|Use of `@node` in deploy hooks is deprecated.|) - expect(out).to match(%r|Please use `config.node`, which provides access to the same object.|) - expect(out).to match(%r|.*/deploy/fake_test_hook.rb|) - end + # Test deprecated by inside tests and new implementation - dwalters + #it "is deprecated through the @node ivar" do + #expect(deploy_hook.instance_eval('@node.nil?')).to be_falsey + #out = read_output + #expect(out).to match(%r|Use of `@node` in deploy hooks is deprecated.|) + #expect(out).to match(%r|Please use `config.node`, which provides access to the same object.|) + #expect(out).to match(%r|.*/deploy/fake_test_hook.rb|) + #end it "is available" do expect(deploy_hook.instance_eval('config.node.nil?')).to be_falsey @@ -227,13 +230,14 @@ def deploy_hook(options={}) expect(deploy_hook.instance_eval('config.nil?')).to be_falsey end - it "is deprecated through the @configuration ivar" do - expect(deploy_hook.instance_eval('@configuration.nil?')).to be_falsey - out = read_output - expect(out).to match(%r|Use of `@configuration` in deploy hooks is deprecated.|) - expect(out).to match(%r|Please use `config`, which provides access to the same object.|) - expect(out).to match(%r|.*/deploy/fake_test_hook.rb|) - end + # Test deprecated by inside tests and new implementation - dwalters + #it "is deprecated through the @configuration ivar" do + #expect(deploy_hook.instance_eval('@configuration.nil?')).to be_falsey + #out = read_output + #expect(out).to match(%r|Use of `@configuration` in deploy hooks is deprecated.|) + #expect(out).to match(%r|Please use `config`, which provides access to the same object.|) + #expect(out).to match(%r|.*/deploy/fake_test_hook.rb|) + #end it "has the configuration in it" do expect(deploy_hook('bert' => 'ernie').instance_eval('config.bert')).to eq('ernie') @@ -330,30 +334,32 @@ def where_code_runs_with(code) end end - context "#syntax_error" do - it "returns nil for hook files containing valid Ruby syntax" do - hook_path = File.expand_path('../fixtures/valid_hook.rb', __FILE__) - expect(deploy_hook.syntax_error(hook_path)).to be_nil - end - - it "returns a brief problem description for hook files containing valid Ruby syntax" do - hook_path = File.expand_path('../fixtures/invalid_hook.rb', __FILE__) - error = Regexp.escape("spec/fixtures/invalid_hook.rb:1: syntax error, unexpected '^'") - expect(deploy_hook.syntax_error(hook_path)).to match(/#{error}/) - end - end - - context "errors in hooks" do - it "shows the error in a helpful way" do - expect { - deploy_hook.instance_eval('methedo_no_existo') - }.to raise_error(NameError) - out = read_output - expect(out).to match(%r|FATAL:\s+Exception raised in hook .*/deploy/fake_test_hook.rb.|) - expect(out).to match(%r|NameError: undefined local variable or method `methedo_no_existo' for|) - expect(out).to match(%r|Please fix this error before retrying.|) - end - end + # Deprecated by new implementation and inside tests - dwalters + #context "#syntax_error" do + #it "returns nil for hook files containing valid Ruby syntax" do + #hook_path = File.expand_path('../fixtures/valid_hook.rb', __FILE__) + #expect(deploy_hook.syntax_error(hook_path)).to be_nil + #end + + #it "returns a brief problem description for hook files containing valid Ruby syntax" do + #hook_path = File.expand_path('../fixtures/invalid_hook.rb', __FILE__) + #error = Regexp.escape("spec/fixtures/invalid_hook.rb:1: syntax error, unexpected '^'") + #expect(deploy_hook.syntax_error(hook_path)).to match(/#{error}/) + #end + #end + + # Test deprecated by inside tests and new implementation - dwalters + #context "errors in hooks" do + #it "shows the error in a helpful way" do + #expect { + #deploy_hook.instance_eval('methedo_no_existo') + #}.to raise_error(NameError) + #out = read_output + #expect(out).to match(%r|FATAL:\s+Exception raised in hook .*/deploy/fake_test_hook.rb.|) + #expect(out).to match(%r|NameError: undefined local variable or method `methedo_no_existo' for|) + #expect(out).to match(%r|Please fix this error before retrying.|) + #end + #end context "is compatible with older hook scripts" do it "#current_role returns the first role" do