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
|
When I execute the recipe
|
||||||
Then the exit status must be 0
|
Then the exit status must be 0
|
||||||
And the output must contain "hello from recipe"
|
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/cli'
|
||||||
require 'producer/core/env'
|
require 'producer/core/env'
|
||||||
|
require 'producer/core/errors'
|
||||||
require 'producer/core/recipe'
|
require 'producer/core/recipe'
|
||||||
require 'producer/core/recipe/dsl'
|
require 'producer/core/recipe/dsl'
|
||||||
require 'producer/core/task'
|
require 'producer/core/task'
|
||||||
|
@ -24,9 +24,10 @@ module Producer
|
|||||||
env = Env.new(recipe)
|
env = Env.new(recipe)
|
||||||
begin
|
begin
|
||||||
recipe.evaluate env
|
recipe.evaluate env
|
||||||
rescue Recipe::RecipeEvaluationError => e
|
rescue RecipeEvaluationError => e
|
||||||
@stdout.puts [e.backtrace.shift, e.message].join ': '
|
backtrace = e.backtrace.reject { |l| l =~ /\/producer-core\// }
|
||||||
@stdout.puts e.backtrace
|
@stdout.puts [backtrace.shift, e.message].join ': '
|
||||||
|
@stdout.puts backtrace
|
||||||
|
|
||||||
exit 70
|
exit 70
|
||||||
end
|
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 Producer
|
||||||
module Core
|
module Core
|
||||||
class Recipe
|
class Recipe
|
||||||
RecipeEvaluationError = Class.new(StandardError)
|
|
||||||
|
|
||||||
attr_reader :code, :filepath
|
attr_reader :code, :filepath
|
||||||
|
|
||||||
def self.from_file(filepath)
|
def self.from_file(filepath)
|
||||||
|
@ -18,9 +18,9 @@ module Producer
|
|||||||
end
|
end
|
||||||
self
|
self
|
||||||
rescue NameError => e
|
rescue NameError => e
|
||||||
err = RecipeEvaluationError.new("invalid recipe keyword `#{e.name}'")
|
raise RecipeEvaluationError,
|
||||||
err.set_backtrace e.backtrace.reject { |l| l =~ /\/producer-core\// }
|
"invalid recipe keyword `#{e.name}'",
|
||||||
raise err
|
e.backtrace
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -2,8 +2,6 @@ module Producer
|
|||||||
module Core
|
module Core
|
||||||
class Task
|
class Task
|
||||||
class DSL
|
class DSL
|
||||||
ConditionNotMetError = Class.new(StandardError)
|
|
||||||
|
|
||||||
def initialize(&block)
|
def initialize(&block)
|
||||||
@block = block
|
@block = block
|
||||||
end
|
end
|
||||||
@ -11,10 +9,14 @@ module Producer
|
|||||||
def evaluate(env)
|
def evaluate(env)
|
||||||
instance_eval &@block
|
instance_eval &@block
|
||||||
rescue ConditionNotMetError
|
rescue ConditionNotMetError
|
||||||
|
rescue NameError => e
|
||||||
|
raise TaskEvaluationError,
|
||||||
|
"invalid task action `#{e.name}'",
|
||||||
|
e.backtrace
|
||||||
end
|
end
|
||||||
|
|
||||||
def condition(&block)
|
def condition(&block)
|
||||||
raise ConditionNotMetError unless block.call
|
fail ConditionNotMetError unless block.call
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -89,11 +89,13 @@ module Producer::Core
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prints the error' do
|
def trap_exit
|
||||||
begin
|
yield
|
||||||
cli.evaluate_recipe_file
|
rescue SystemExit
|
||||||
rescue SystemExit
|
end
|
||||||
end
|
|
||||||
|
it 'prints the specific error' do
|
||||||
|
trap_exit { cli.evaluate_recipe_file }
|
||||||
expect(stdout.string).to match(/
|
expect(stdout.string).to match(/
|
||||||
\A
|
\A
|
||||||
#{recipe_file}:4:
|
#{recipe_file}:4:
|
||||||
@ -101,6 +103,11 @@ module Producer::Core
|
|||||||
invalid\srecipe\skeyword\s`invalid_keyword'
|
invalid\srecipe\skeyword\s`invalid_keyword'
|
||||||
/x)
|
/x)
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -50,7 +50,7 @@ module Producer::Core
|
|||||||
|
|
||||||
it 'raises a RecipeEvaluationError on NameError' do
|
it 'raises a RecipeEvaluationError on NameError' do
|
||||||
dsl = Recipe::DSL.new { invalid_keyword }
|
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
|
end
|
||||||
end
|
end
|
||||||
|
@ -12,6 +12,14 @@ module Producer::Core
|
|||||||
expect { dsl.evaluate(env) }
|
expect { dsl.evaluate(env) }
|
||||||
.to raise_error(RuntimeError, 'error from task')
|
.to raise_error(RuntimeError, 'error from task')
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe '#condition' do
|
describe '#condition' do
|
||||||
|
Loading…
x
Reference in New Issue
Block a user