Improve error reporting during recipe evaluation
* Report invalid action usages from tasks; * Implement backtrace cleaning in CLI; * Extract error class declarations in a new errors file; * Replace raise with fail keyword in task DSL class.
This commit is contained in:
parent
836f9ffc29
commit
c4fc9828db
@ -10,3 +10,17 @@ Feature: tasks
|
||||
When I execute the recipe
|
||||
Then the exit status must be 0
|
||||
And the output must contain "hello from recipe"
|
||||
|
||||
Scenario: reports errors for invalid action calls in a task
|
||||
Given a recipe with:
|
||||
"""
|
||||
task 'some_task' do
|
||||
invalid_action
|
||||
end
|
||||
"""
|
||||
When I execute the recipe
|
||||
Then the exit status must be 70
|
||||
And the output must match:
|
||||
"""
|
||||
\Arecipe.rb:2:.+invalid task action `invalid_action'
|
||||
"""
|
||||
|
@ -1,5 +1,6 @@
|
||||
require 'producer/core/cli'
|
||||
require 'producer/core/env'
|
||||
require 'producer/core/errors'
|
||||
require 'producer/core/recipe'
|
||||
require 'producer/core/recipe/dsl'
|
||||
require 'producer/core/task'
|
||||
|
@ -24,9 +24,10 @@ module Producer
|
||||
env = Env.new(recipe)
|
||||
begin
|
||||
recipe.evaluate env
|
||||
rescue Recipe::RecipeEvaluationError => e
|
||||
@stdout.puts [e.backtrace.shift, e.message].join ': '
|
||||
@stdout.puts e.backtrace
|
||||
rescue RecipeEvaluationError => e
|
||||
backtrace = e.backtrace.reject { |l| l =~ /\/producer-core\// }
|
||||
@stdout.puts [backtrace.shift, e.message].join ': '
|
||||
@stdout.puts backtrace
|
||||
|
||||
exit 70
|
||||
end
|
||||
|
8
lib/producer/core/errors.rb
Normal file
8
lib/producer/core/errors.rb
Normal file
@ -0,0 +1,8 @@
|
||||
module Producer
|
||||
module Core
|
||||
Error = Class.new(StandardError)
|
||||
ConditionNotMetError = Class.new(Error)
|
||||
RecipeEvaluationError = Class.new(StandardError)
|
||||
TaskEvaluationError = Class.new(RecipeEvaluationError)
|
||||
end
|
||||
end
|
@ -1,8 +1,6 @@
|
||||
module Producer
|
||||
module Core
|
||||
class Recipe
|
||||
RecipeEvaluationError = Class.new(StandardError)
|
||||
|
||||
attr_reader :code, :filepath
|
||||
|
||||
def self.from_file(filepath)
|
||||
|
@ -18,9 +18,9 @@ module Producer
|
||||
end
|
||||
self
|
||||
rescue NameError => e
|
||||
err = RecipeEvaluationError.new("invalid recipe keyword `#{e.name}'")
|
||||
err.set_backtrace e.backtrace.reject { |l| l =~ /\/producer-core\// }
|
||||
raise err
|
||||
raise RecipeEvaluationError,
|
||||
"invalid recipe keyword `#{e.name}'",
|
||||
e.backtrace
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -2,8 +2,6 @@ module Producer
|
||||
module Core
|
||||
class Task
|
||||
class DSL
|
||||
ConditionNotMetError = Class.new(StandardError)
|
||||
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
end
|
||||
@ -11,10 +9,14 @@ module Producer
|
||||
def evaluate(env)
|
||||
instance_eval &@block
|
||||
rescue ConditionNotMetError
|
||||
rescue NameError => e
|
||||
raise TaskEvaluationError,
|
||||
"invalid task action `#{e.name}'",
|
||||
e.backtrace
|
||||
end
|
||||
|
||||
def condition(&block)
|
||||
raise ConditionNotMetError unless block.call
|
||||
fail ConditionNotMetError unless block.call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -89,11 +89,13 @@ module Producer::Core
|
||||
}
|
||||
end
|
||||
|
||||
it 'prints the error' do
|
||||
begin
|
||||
cli.evaluate_recipe_file
|
||||
rescue SystemExit
|
||||
end
|
||||
def trap_exit
|
||||
yield
|
||||
rescue SystemExit
|
||||
end
|
||||
|
||||
it 'prints the specific error' do
|
||||
trap_exit { cli.evaluate_recipe_file }
|
||||
expect(stdout.string).to match(/
|
||||
\A
|
||||
#{recipe_file}:4:
|
||||
@ -101,6 +103,11 @@ module Producer::Core
|
||||
invalid\srecipe\skeyword\s`invalid_keyword'
|
||||
/x)
|
||||
end
|
||||
|
||||
it 'excludes producer own source code from the error backtrace' do
|
||||
trap_exit { cli.evaluate_recipe_file }
|
||||
expect(stdout.string).to_not match /\/producer-core\//
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -50,7 +50,7 @@ module Producer::Core
|
||||
|
||||
it 'raises a RecipeEvaluationError on NameError' do
|
||||
dsl = Recipe::DSL.new { invalid_keyword }
|
||||
expect { dsl.evaluate(env) }.to raise_error(Recipe::RecipeEvaluationError)
|
||||
expect { dsl.evaluate(env) }.to raise_error(RecipeEvaluationError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -12,6 +12,14 @@ module Producer::Core
|
||||
expect { dsl.evaluate(env) }
|
||||
.to raise_error(RuntimeError, 'error from task')
|
||||
end
|
||||
|
||||
context 'when given block is invalid' do
|
||||
it 'raises a TaskEvaluationError on NameError' do
|
||||
dsl = Task::DSL.new { invalid_action }
|
||||
expect { dsl.evaluate(env) }
|
||||
.to raise_error(TaskEvaluationError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#condition' do
|
||||
|
Loading…
x
Reference in New Issue
Block a user