terraspace 0.4.2 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.cody/aws/bin/build.sh +2 -2
- data/.cody/azurerm/bin/build.sh +2 -2
- data/.cody/google/bin/build.sh +2 -2
- data/.github/ISSUE_TEMPLATE.md +1 -1
- data/CHANGELOG.md +31 -0
- data/README.md +4 -3
- data/lib/templates/base/arg/terraform.rb.tt +3 -0
- data/lib/templates/base/helper/%name%_helper.rb.tt +2 -0
- data/lib/templates/base/hook/%kind%.rb.tt +7 -0
- data/lib/terraspace.rb +7 -4
- data/lib/terraspace/all/base.rb +0 -1
- data/lib/terraspace/app.rb +1 -0
- data/lib/terraspace/autoloader.rb +16 -1
- data/lib/terraspace/bundle.rb +6 -0
- data/lib/terraspace/cli.rb +1 -0
- data/lib/terraspace/cli/bundle.rb +0 -1
- data/lib/terraspace/cli/check_setup.rb +5 -0
- data/lib/terraspace/cli/clean/base.rb +0 -1
- data/lib/terraspace/cli/clean/cache.rb +0 -1
- data/lib/terraspace/cli/cloud.rb +2 -0
- data/lib/terraspace/cli/help/new/arg.md +19 -0
- data/lib/terraspace/cli/help/new/helper.md +39 -0
- data/lib/terraspace/cli/help/new/hook.md +25 -0
- data/lib/terraspace/cli/help/new/test.md +34 -0
- data/lib/terraspace/cli/info.rb +12 -0
- data/lib/terraspace/cli/new.rb +22 -16
- data/lib/terraspace/cli/new/arg.rb +62 -0
- data/lib/terraspace/cli/new/helper.rb +44 -12
- data/lib/terraspace/cli/new/helpers.rb +22 -0
- data/lib/terraspace/cli/new/helpers/plugin_gem.rb +25 -0
- data/lib/terraspace/cli/new/hook.rb +70 -0
- data/lib/terraspace/cli/new/module.rb +0 -11
- data/lib/terraspace/cli/new/plugin.rb +4 -4
- data/lib/terraspace/cli/new/plugin/helper.rb +1 -1
- data/lib/terraspace/cli/new/project.rb +16 -7
- data/lib/terraspace/cli/new/sequence.rb +3 -10
- data/lib/terraspace/cli/new/source/core.rb +1 -1
- data/lib/terraspace/cli/new/stack.rb +1 -12
- data/lib/terraspace/cli/new/test.rb +50 -0
- data/lib/terraspace/cli/summary.rb +0 -1
- data/lib/terraspace/command.rb +50 -0
- data/lib/terraspace/compiler/builder.rb +2 -0
- data/lib/terraspace/compiler/dsl/mod.rb +2 -0
- data/lib/terraspace/compiler/dsl/syntax/mod.rb +2 -0
- data/lib/terraspace/compiler/dsl/syntax/mod/backend.rb +1 -1
- data/lib/terraspace/compiler/erb/context.rb +2 -0
- data/lib/terraspace/compiler/helper_extender.rb +27 -0
- data/lib/terraspace/core.rb +0 -6
- data/lib/terraspace/ext/core/module.rb +16 -0
- data/lib/terraspace/hooks/builder.rb +6 -7
- data/lib/terraspace/hooks/concern.rb +2 -2
- data/lib/terraspace/logger.rb +6 -0
- data/lib/terraspace/mod.rb +0 -1
- data/lib/terraspace/plugin.rb +8 -4
- data/lib/terraspace/plugin/config/interface.rb +2 -2
- data/lib/terraspace/plugin/helper/interface.rb +31 -0
- data/lib/terraspace/shell.rb +5 -33
- data/lib/terraspace/shell/error.rb +46 -0
- data/lib/terraspace/terraform/args/custom.rb +2 -3
- data/lib/terraspace/terraform/runner.rb +5 -13
- data/lib/terraspace/terraform/runner/retryer.rb +69 -0
- data/lib/terraspace/version.rb +1 -1
- data/spec/terraspace/terraform/args/custom_spec.rb +6 -4
- data/terraspace.gemspec +4 -4
- metadata +29 -21
- data/lib/terraspace/cli/help/new/bootstrap_test.md +0 -8
- data/lib/terraspace/cli/help/new/module_test.md +0 -12
- data/lib/terraspace/cli/help/new/project_test.md +0 -8
- data/lib/terraspace/cli/new/helper/plugin_gem.rb +0 -12
- data/lib/terraspace/cli/new/test/base.rb +0 -17
- data/lib/terraspace/cli/new/test/bootstrap.rb +0 -18
- data/lib/terraspace/cli/new/test/module.rb +0 -15
- data/lib/terraspace/cli/new/test/project.rb +0 -15
@@ -5,22 +5,11 @@ class Terraspace::CLI::New
|
|
5
5
|
argument :name
|
6
6
|
|
7
7
|
def create_stack
|
8
|
-
plugin_template_source(@options[:lang], "stack") # IE: plugin_template_source("hcl", "stack")
|
9
|
-
|
10
8
|
puts "=> Creating new stack called #{name}."
|
9
|
+
plugin_template_source(@options[:lang], "stack") # IE: plugin_template_source("hcl", "stack")
|
11
10
|
dest = "app/stacks/#{name}"
|
12
11
|
dest = "#{@options[:project_name]}/#{dest}" if @options[:project_name]
|
13
12
|
directory ".", dest
|
14
13
|
end
|
15
|
-
|
16
|
-
def create_test
|
17
|
-
Test::Project.start(component_args(name, @options[:project_name]))
|
18
|
-
end
|
19
|
-
|
20
|
-
def run_generator_hook_script
|
21
|
-
script = ENV['TS_GENERATOR_STACK']
|
22
|
-
return unless script
|
23
|
-
run_script(script, "app/stacks/#{name}")
|
24
|
-
end
|
25
14
|
end
|
26
15
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Terraspace::CLI::New
|
2
|
+
class Test < Thor::Group
|
3
|
+
include Thor::Actions
|
4
|
+
include Terraspace::CLI::New::Helpers
|
5
|
+
|
6
|
+
argument :name
|
7
|
+
|
8
|
+
def self.options
|
9
|
+
[
|
10
|
+
[:force, aliases: %w[y], type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files"],
|
11
|
+
[:test_name, desc: "Test name. Defaults to the project, module or stack name"],
|
12
|
+
[:type, default: "project", desc: "project, stack or module"],
|
13
|
+
]
|
14
|
+
end
|
15
|
+
options.each { |args| class_option(*args) }
|
16
|
+
|
17
|
+
private
|
18
|
+
def type
|
19
|
+
valid_types = %w[project stack module]
|
20
|
+
type = @options[:type]
|
21
|
+
valid_types.include?(type) ? type : "project" # fallback to project if user provides invalid type
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_name
|
25
|
+
options[:test_name] || name
|
26
|
+
end
|
27
|
+
|
28
|
+
def dest
|
29
|
+
map = {
|
30
|
+
project: ".", # Terraspace.root
|
31
|
+
stack: "app/stacks/#{name}",
|
32
|
+
module: "app/modules/#{name}",
|
33
|
+
}
|
34
|
+
map[type.to_sym]
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_template_source(template, type)
|
38
|
+
source = Terraspace::CLI::New::Source::Test.new(self, @options)
|
39
|
+
source.set_source_paths(template, type)
|
40
|
+
end
|
41
|
+
|
42
|
+
public
|
43
|
+
|
44
|
+
def create
|
45
|
+
test_template_source(@options[:lang], type)
|
46
|
+
puts "=> Creating #{type} test: #{name}"
|
47
|
+
directory ".", dest
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/terraspace/command.rb
CHANGED
@@ -27,7 +27,12 @@ Thor::Util.singleton_class.prepend(ThorPrepend::Util)
|
|
27
27
|
module Terraspace
|
28
28
|
class Command < Thor
|
29
29
|
class << self
|
30
|
+
include Terraspace::Util::Logging
|
31
|
+
|
30
32
|
def dispatch(m, args, options, config)
|
33
|
+
check_standalone_install!
|
34
|
+
check_project!(args.first)
|
35
|
+
|
31
36
|
# Allow calling for help via:
|
32
37
|
# terraspace command help
|
33
38
|
# terraspace command -h
|
@@ -54,6 +59,51 @@ module Terraspace
|
|
54
59
|
super
|
55
60
|
end
|
56
61
|
|
62
|
+
def check_standalone_install!
|
63
|
+
return unless opt?
|
64
|
+
version_manager = "rvm" if rvm?
|
65
|
+
version_manager = "rbenv" if rbenv?
|
66
|
+
if rbenv? || rvm?
|
67
|
+
puts <<~EOL.color(:yellow)
|
68
|
+
WARN: It looks like a standalone Terraspace install and #{version_manager} is also in use.
|
69
|
+
Different gems from the standalone Terraspace install and #{version_manager} can cause all kinds of trouble.
|
70
|
+
Please install Terraspace as a gem instead and remove the standalone Terraspace /opt/terraspace installation.
|
71
|
+
See: https://terraspace.cloud/docs/install/gem/
|
72
|
+
EOL
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def opt?
|
77
|
+
paths = ENV['PATH'].split(':')
|
78
|
+
opt = paths.detect { |p| p.include?('/opt/terraspace') }
|
79
|
+
opt && File.exist?('/opt/terraspace')
|
80
|
+
end
|
81
|
+
|
82
|
+
def rvm?
|
83
|
+
paths = ENV['PATH'].split(':')
|
84
|
+
rvm = paths.detect { |p| p.include?('/rvm/') || p.include?('/.rvm/') }
|
85
|
+
rvm && system("type rvm > /dev/null 2>&1")
|
86
|
+
end
|
87
|
+
|
88
|
+
def rbenv?
|
89
|
+
paths = ENV['PATH'].split(':')
|
90
|
+
rbenv = paths.detect { |p| p.include?('/rbenv/') || p.include?('/.rbenv/') }
|
91
|
+
rbenv && system("type rbenv > /dev/null 2>&1")
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_project!(command_name)
|
95
|
+
return if subcommand?
|
96
|
+
return if command_name.nil?
|
97
|
+
return if %w[-h -v completion completion_script help new test version].include?(command_name)
|
98
|
+
return if File.exist?("#{Terraspace.root}/config/app.rb")
|
99
|
+
logger.error "ERROR: It doesnt look like this is a terraspace project. Are you sure you are in a terraspace project?".color(:red)
|
100
|
+
ENV['TS_TEST'] ? raise : exit(1)
|
101
|
+
end
|
102
|
+
|
103
|
+
def subcommand?
|
104
|
+
!!caller.detect { |l| l.include?('in subcommand') }
|
105
|
+
end
|
106
|
+
|
57
107
|
# Override command_help to include the description at the top of the
|
58
108
|
# long_description.
|
59
109
|
def command_help(shell, command_name)
|
@@ -73,6 +73,8 @@ module Terraspace::Compiler
|
|
73
73
|
def skip?(src_path)
|
74
74
|
return true unless File.file?(src_path)
|
75
75
|
# certain folders will be skipped
|
76
|
+
src_path.include?("#{@mod.root}/config/args") ||
|
77
|
+
src_path.include?("#{@mod.root}/config/hooks") ||
|
76
78
|
src_path.include?("#{@mod.root}/test")
|
77
79
|
end
|
78
80
|
end
|
@@ -11,7 +11,7 @@ module Terraspace::Compiler::Dsl::Syntax::Mod
|
|
11
11
|
Terraspace::Compiler::Expander.new(@mod, backend_name).expand(props)
|
12
12
|
end
|
13
13
|
|
14
|
-
# Can set opts to explicitly use an
|
14
|
+
# Can set opts to explicitly use an specific backend. Example:
|
15
15
|
#
|
16
16
|
# opts = {backend: s3}
|
17
17
|
#
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module Terraspace::Compiler::Erb
|
2
2
|
class Context
|
3
3
|
include Helpers
|
4
|
+
include Terraspace::Compiler::HelperExtender
|
4
5
|
|
5
6
|
attr_reader :mod, :options
|
6
7
|
def initialize(mod)
|
7
8
|
@mod = mod
|
8
9
|
@options = mod.options # so user has access to cli options
|
10
|
+
extend_module_level_helpers
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Terraspace::Compiler
|
2
|
+
module HelperExtender
|
3
|
+
private
|
4
|
+
def extend_module_level_helpers
|
5
|
+
full_dir = "#{@mod.root}/config/helpers"
|
6
|
+
Dir.glob("#{full_dir}/**/*").each do |path|
|
7
|
+
regexp = Regexp.new(".*/helpers/")
|
8
|
+
klass = path.sub(regexp, '').sub('.rb','').camelize
|
9
|
+
klass = "#{mod_namespace}::#{klass}"
|
10
|
+
require path # able to use require instead of load since each helper has unique namespace
|
11
|
+
send :extend, klass.constantize
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# IE: mod_namespace = Terraspace::Module::Demo
|
16
|
+
# Use separate namespaces scope with module name so custom helper methods from different modules are isolated.
|
17
|
+
def mod_namespace
|
18
|
+
mod_name = @mod.name.camelize
|
19
|
+
ns = "Terraspace::#{@mod.type.camelize}".constantize # IE: Terraspace::Module or Terraspace::Stack
|
20
|
+
if ns.const_defined?(mod_name.to_sym)
|
21
|
+
"#{ns}::#{mod_name}".constantize
|
22
|
+
else
|
23
|
+
ns.const_set(mod_name, Module.new)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/terraspace/core.rb
CHANGED
@@ -51,11 +51,5 @@ module Terraspace
|
|
51
51
|
def logger=(v)
|
52
52
|
@@logger = v
|
53
53
|
end
|
54
|
-
|
55
|
-
def check_project!
|
56
|
-
return if File.exist?("#{Terraspace.root}/config/app.rb")
|
57
|
-
logger.error "ERROR: It doesnt look like this is a terraspace project. Are you sure you are in a terraspace project?".color(:red)
|
58
|
-
ENV['TS_TEST'] ? raise : exit(1)
|
59
|
-
end
|
60
54
|
end
|
61
55
|
end
|
@@ -16,4 +16,20 @@ class Module
|
|
16
16
|
include klass.constantize
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def include_project_level_helpers
|
21
|
+
full_dir = "#{Terraspace.root}/config/helpers"
|
22
|
+
Dir.glob("#{full_dir}/**/*").each do |path|
|
23
|
+
regexp = Regexp.new(".*/config/helpers/")
|
24
|
+
klass = path.sub(regexp, '').sub('.rb','').camelize
|
25
|
+
klass = "Terraspace::Project::#{klass}"
|
26
|
+
include klass.constantize
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def include_plugin_helpers
|
31
|
+
Terraspace::Plugin.helper_classes.each do |klass|
|
32
|
+
include klass # IE: TerraspacePluginAws::Interfaces::Helper
|
33
|
+
end
|
34
|
+
end
|
19
35
|
end
|
@@ -7,14 +7,14 @@ module Terraspace::Hooks
|
|
7
7
|
|
8
8
|
# IE: dsl_file: config/hooks/terraform.rb
|
9
9
|
attr_accessor :name
|
10
|
-
def initialize(mod,
|
11
|
-
@mod, @
|
10
|
+
def initialize(mod, file, name)
|
11
|
+
@mod, @file, @name = mod, file, name
|
12
12
|
@hooks = {before: {}, after: {}}
|
13
13
|
end
|
14
14
|
|
15
15
|
def build
|
16
|
-
|
17
|
-
evaluate_file(@
|
16
|
+
evaluate_file("#{Terraspace.root}/config/hooks/#{@file}")
|
17
|
+
evaluate_file("#{@mod.root}/config/hooks/#{@file}")
|
18
18
|
@hooks.deep_stringify_keys!
|
19
19
|
end
|
20
20
|
memoize :build
|
@@ -37,11 +37,10 @@ module Terraspace::Hooks
|
|
37
37
|
def run_hook(type, hook)
|
38
38
|
return unless run?(hook)
|
39
39
|
|
40
|
-
command = File.basename(@
|
40
|
+
command = File.basename(@file).sub('.rb','') # IE: terraform or terraspace
|
41
41
|
id = "#{command} #{type} #{@name}"
|
42
42
|
label = " label: #{hook["label"]}" if hook["label"]
|
43
|
-
logger.info "Running #{id} hook.#{label}"
|
44
|
-
logger.debug "Hook options: #{hook}"
|
43
|
+
logger.info "Hook: Running #{id} hook.#{label}".color(:cyan)
|
45
44
|
Runner.new(@mod, hook).run
|
46
45
|
end
|
47
46
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Terraspace::Hooks
|
2
2
|
module Concern
|
3
|
-
def run_hooks(
|
4
|
-
hooks = Builder.new(@mod,
|
3
|
+
def run_hooks(file, name, &block)
|
4
|
+
hooks = Builder.new(@mod, file, name)
|
5
5
|
hooks.build # build hooks
|
6
6
|
hooks.run_hooks(&block)
|
7
7
|
end
|
data/lib/terraspace/logger.rb
CHANGED
@@ -2,6 +2,12 @@ require 'logger'
|
|
2
2
|
|
3
3
|
module Terraspace
|
4
4
|
class Logger < ::Logger
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
self.formatter = Formatter.new
|
8
|
+
self.level = :info
|
9
|
+
end
|
10
|
+
|
5
11
|
def format_message(severity, datetime, progname, msg)
|
6
12
|
line = if @logdev.dev == $stdout || @logdev.dev == $stderr
|
7
13
|
msg # super simple format if stdout
|
data/lib/terraspace/mod.rb
CHANGED
data/lib/terraspace/plugin.rb
CHANGED
@@ -16,14 +16,18 @@ module Terraspace
|
|
16
16
|
@@meta
|
17
17
|
end
|
18
18
|
|
19
|
-
def layer_classes
|
20
|
-
@@meta.map { |plugin, data| data[:layer_class] }.compact
|
21
|
-
end
|
22
|
-
|
23
19
|
def config_classes
|
24
20
|
@@meta.map { |plugin, data| data[:config_class] }.compact
|
25
21
|
end
|
26
22
|
|
23
|
+
def helper_classes
|
24
|
+
@@meta.map { |plugin, data| data[:helper_class] }.compact
|
25
|
+
end
|
26
|
+
|
27
|
+
def layer_classes
|
28
|
+
@@meta.map { |plugin, data| data[:layer_class] }.compact
|
29
|
+
end
|
30
|
+
|
27
31
|
# The resource map can be used to customized the mapping from the resource "first word" to the plugin.
|
28
32
|
#
|
29
33
|
# resource map is in meta structure.
|
@@ -16,8 +16,8 @@ module Terraspace::Plugin::Config
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def load_project_config
|
19
|
-
|
20
|
-
evaluate_file(
|
19
|
+
evaluate_file("#{Terraspace.root}/config/plugins/#{provider}.rb")
|
20
|
+
evaluate_file("#{Terraspace.root}/config/plugins/#{provider}/#{Terraspace.env}.rb")
|
21
21
|
end
|
22
22
|
|
23
23
|
def configure
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Terraspace::Plugin::Helper
|
2
|
+
module Interface
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# Useful for plugin helpers. Can check this only run logic after dependency resolution.
|
6
|
+
def resolved?
|
7
|
+
!!@mod.resolved
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
@@helper_cache = {}
|
12
|
+
# This method is useful to avoid double call of heavy processing logic for tfvars,
|
13
|
+
# since the tfvars files get evaluated twice.
|
14
|
+
# Note: Not setting any cache or doing any logic unless resolved.
|
15
|
+
def cache_helper(meth)
|
16
|
+
uncached_meth = "uncached_#{meth}"
|
17
|
+
alias_method(uncached_meth, meth)
|
18
|
+
define_method(meth) do |*args|
|
19
|
+
return unless resolved? # return nil in first unresolved pass
|
20
|
+
id = Marshal.dump([meth] + args)
|
21
|
+
exist = @@helper_cache.key?(id)
|
22
|
+
if exist
|
23
|
+
@@helper_cache[id]
|
24
|
+
else
|
25
|
+
@@helper_cache[id] = send(uncached_meth, *args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/terraspace/shell.rb
CHANGED
@@ -6,8 +6,6 @@ module Terraspace
|
|
6
6
|
|
7
7
|
def initialize(mod, command, options={})
|
8
8
|
@mod, @command, @options = mod, command, options
|
9
|
-
# error_messages holds aggregation of all error lines
|
10
|
-
@known_error, @error_messages = nil, ''
|
11
9
|
end
|
12
10
|
|
13
11
|
# requires @mod to be set
|
@@ -33,9 +31,9 @@ module Terraspace
|
|
33
31
|
Open3.popen3(env, @command, chdir: @mod.cache_dir) do |stdin, stdout, stderr, wait_thread|
|
34
32
|
mimic_terraform_input(stdin, stdout)
|
35
33
|
while err = stderr.gets
|
36
|
-
@
|
37
|
-
@
|
38
|
-
unless @
|
34
|
+
@error ||= Error.new
|
35
|
+
@error.lines << err # aggregate all error lines
|
36
|
+
unless @error.known?
|
39
37
|
# Sometimes may print a "\e[31m\n" which like during dependencies fetcher init
|
40
38
|
# suppress it so dont get a bunch of annoying "newlines"
|
41
39
|
next if err == "\e[31m\n" && @options[:suppress_error_color]
|
@@ -48,38 +46,12 @@ module Terraspace
|
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
51
|
-
def known_error_type(err)
|
52
|
-
if reinit_required?(err)
|
53
|
-
:reinit_required
|
54
|
-
elsif bucket_not_found?(err)
|
55
|
-
:bucket_not_found
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def bucket_not_found?(err)
|
60
|
-
# Message is included in aws, azurerm, and google. See: https://bit.ly/3iOKDri
|
61
|
-
err.include?("Failed to get existing workspaces")
|
62
|
-
end
|
63
|
-
|
64
|
-
def reinit_required?(err)
|
65
|
-
# Example error: https://gist.github.com/tongueroo/f7e0a44b64f0a2e533089b18f331c21e
|
66
|
-
squeezed = @error_messages.gsub("\n", ' ').squeeze(' ') # remove double whitespaces and newlines
|
67
|
-
general_check = squeezed.include?("terraform init") && squeezed.include?("Error:")
|
68
|
-
|
69
|
-
general_check ||
|
70
|
-
err.include?("reinitialization required") ||
|
71
|
-
err.include?("terraform init") ||
|
72
|
-
err.include?("require reinitialization")
|
73
|
-
end
|
74
|
-
|
75
49
|
def exit_status(status)
|
76
50
|
return if status == 0
|
77
51
|
|
78
52
|
exit_on_fail = @options[:exit_on_fail].nil? ? true : @options[:exit_on_fail]
|
79
|
-
if @
|
80
|
-
raise
|
81
|
-
elsif @known_error == :bucket_not_found
|
82
|
-
raise BucketNotFoundError.new(@error_messages)
|
53
|
+
if @error && @error.known?
|
54
|
+
raise @error.instance
|
83
55
|
elsif exit_on_fail
|
84
56
|
logger.error "Error running command: #{@command}".color(:red)
|
85
57
|
exit status
|