bolt 3.1.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Puppetfile +8 -8
- data/bolt-modules/boltlib/lib/puppet/functions/add_facts.rb +1 -1
- data/bolt-modules/boltlib/lib/puppet/functions/run_plan.rb +2 -2
- data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -5
- data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +1 -1
- data/bolt-modules/file/lib/puppet/functions/file/read.rb +3 -2
- data/lib/bolt/apply_result.rb +1 -1
- data/lib/bolt/bolt_option_parser.rb +6 -3
- data/lib/bolt/cli.rb +37 -12
- data/lib/bolt/config.rb +4 -0
- data/lib/bolt/config/options.rb +21 -3
- data/lib/bolt/config/transport/lxd.rb +21 -0
- data/lib/bolt/config/transport/options.rb +1 -1
- data/lib/bolt/executor.rb +10 -3
- data/lib/bolt/logger.rb +8 -0
- data/lib/bolt/module_installer.rb +2 -2
- data/lib/bolt/module_installer/puppetfile.rb +2 -2
- data/lib/bolt/module_installer/specs/forge_spec.rb +2 -2
- data/lib/bolt/module_installer/specs/git_spec.rb +2 -2
- data/lib/bolt/outputter/human.rb +47 -12
- data/lib/bolt/pal.rb +2 -2
- data/lib/bolt/pal/yaml_plan.rb +1 -2
- data/lib/bolt/pal/yaml_plan/evaluator.rb +5 -141
- data/lib/bolt/pal/yaml_plan/step.rb +91 -31
- data/lib/bolt/pal/yaml_plan/step/command.rb +16 -16
- data/lib/bolt/pal/yaml_plan/step/download.rb +15 -16
- data/lib/bolt/pal/yaml_plan/step/eval.rb +11 -11
- data/lib/bolt/pal/yaml_plan/step/message.rb +13 -4
- data/lib/bolt/pal/yaml_plan/step/plan.rb +19 -15
- data/lib/bolt/pal/yaml_plan/step/resources.rb +82 -21
- data/lib/bolt/pal/yaml_plan/step/script.rb +32 -17
- data/lib/bolt/pal/yaml_plan/step/task.rb +19 -16
- data/lib/bolt/pal/yaml_plan/step/upload.rb +16 -17
- data/lib/bolt/pal/yaml_plan/transpiler.rb +1 -1
- data/lib/bolt/plan_creator.rb +1 -1
- data/lib/bolt/project_manager.rb +1 -1
- data/lib/bolt/project_manager/module_migrator.rb +1 -1
- data/lib/bolt/shell.rb +16 -0
- data/lib/bolt/shell/bash.rb +48 -21
- data/lib/bolt/shell/bash/tmpdir.rb +2 -2
- data/lib/bolt/shell/powershell.rb +24 -5
- data/lib/bolt/task.rb +1 -1
- data/lib/bolt/transport/lxd.rb +26 -0
- data/lib/bolt/transport/lxd/connection.rb +99 -0
- data/lib/bolt/transport/ssh/connection.rb +1 -1
- data/lib/bolt/transport/winrm/connection.rb +1 -1
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/transport_app.rb +13 -1
- data/lib/bolt_spec/plans/action_stubs.rb +1 -1
- data/lib/bolt_spec/plans/mock_executor.rb +4 -0
- metadata +5 -2
@@ -6,11 +6,7 @@ module Bolt
|
|
6
6
|
class PAL
|
7
7
|
class YamlPlan
|
8
8
|
class Step
|
9
|
-
attr_reader :
|
10
|
-
|
11
|
-
def self.allowed_keys
|
12
|
-
Set['name', 'description', 'targets']
|
13
|
-
end
|
9
|
+
attr_reader :body
|
14
10
|
|
15
11
|
STEP_KEYS = %w[
|
16
12
|
command
|
@@ -24,15 +20,42 @@ module Bolt
|
|
24
20
|
upload
|
25
21
|
].freeze
|
26
22
|
|
23
|
+
class StepError < Bolt::Error
|
24
|
+
def initialize(message, name, step_number)
|
25
|
+
identifier = name ? name.inspect : "number #{step_number}"
|
26
|
+
error = "Parse error in step #{identifier}: \n #{message}"
|
27
|
+
|
28
|
+
super(error, 'bolt/invalid-plan')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Keys that are allowed for the step
|
33
|
+
#
|
34
|
+
def self.allowed_keys
|
35
|
+
required_keys + option_keys + Set['name', 'description', 'targets']
|
36
|
+
end
|
37
|
+
|
38
|
+
# Keys that translate to metaparameters for the plan step's function call
|
39
|
+
#
|
40
|
+
def self.option_keys
|
41
|
+
Set.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# Keys that are required for the step
|
45
|
+
#
|
46
|
+
def self.required_keys
|
47
|
+
Set.new
|
48
|
+
end
|
49
|
+
|
27
50
|
def self.create(step_body, step_number)
|
28
51
|
type_keys = (STEP_KEYS & step_body.keys)
|
29
52
|
case type_keys.length
|
30
53
|
when 0
|
31
|
-
raise
|
54
|
+
raise StepError.new("No valid action detected", step_body['name'], step_number)
|
32
55
|
when 1
|
33
56
|
type = type_keys.first
|
34
57
|
else
|
35
|
-
raise
|
58
|
+
raise StepError.new("Multiple action keys detected: #{type_keys.inspect}", step_body['name'], step_number)
|
36
59
|
end
|
37
60
|
|
38
61
|
step_class = const_get("Bolt::PAL::YamlPlan::Step::#{type.capitalize}")
|
@@ -40,15 +63,49 @@ module Bolt
|
|
40
63
|
step_class.new(step_body)
|
41
64
|
end
|
42
65
|
|
43
|
-
def initialize(
|
44
|
-
@
|
45
|
-
@description = step_body['description']
|
46
|
-
@targets = step_body['targets']
|
47
|
-
@body = step_body
|
66
|
+
def initialize(body)
|
67
|
+
@body = body
|
48
68
|
end
|
49
69
|
|
70
|
+
# Transpiles the step into the plan language
|
71
|
+
#
|
50
72
|
def transpile
|
51
|
-
|
73
|
+
code = String.new(" ")
|
74
|
+
code << "$#{body['name']} = " if body['name']
|
75
|
+
code << function_call(function, format_args(body))
|
76
|
+
code << "\n"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Evaluates the step
|
80
|
+
#
|
81
|
+
def evaluate(scope, evaluator)
|
82
|
+
evaluated = evaluator.evaluate_code_blocks(scope, body)
|
83
|
+
scope.call_function(function, format_args(evaluated))
|
84
|
+
end
|
85
|
+
|
86
|
+
# Formats a list of args from the provided body
|
87
|
+
#
|
88
|
+
private def format_args(_body)
|
89
|
+
raise NotImplementedError, "Step class #{self.class} does not implement #format_args"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the step's corresponding Puppet language function call
|
93
|
+
#
|
94
|
+
private def function_call(function, args)
|
95
|
+
code_args = args.map { |arg| Bolt::Util.to_code(arg) }
|
96
|
+
"#{function}(#{code_args.join(', ')})"
|
97
|
+
end
|
98
|
+
|
99
|
+
# The function that corresponds to the step
|
100
|
+
#
|
101
|
+
private def function
|
102
|
+
raise NotImplementedError, "Step class #{self.class} does not implement #function"
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a hash of options formatted for function calls
|
106
|
+
#
|
107
|
+
private def format_options(body)
|
108
|
+
body.slice(*self.class.option_keys).transform_keys { |key| "_#{key}" }
|
52
109
|
end
|
53
110
|
|
54
111
|
def self.validate(body, step_number)
|
@@ -57,19 +114,35 @@ module Bolt
|
|
57
114
|
begin
|
58
115
|
body.each { |k, v| validate_puppet_code(k, v) }
|
59
116
|
rescue Bolt::Error => e
|
60
|
-
raise
|
117
|
+
raise StepError.new(e.msg, body['name'], step_number)
|
118
|
+
end
|
119
|
+
|
120
|
+
if body.key?('parameters')
|
121
|
+
unless body['parameters'].is_a?(Hash)
|
122
|
+
raise StepError.new("Parameters key must be a hash", body['name'], step_number)
|
123
|
+
end
|
124
|
+
|
125
|
+
metaparams = option_keys.map { |key| "_#{key}" }
|
126
|
+
|
127
|
+
if (dups = body['parameters'].keys & metaparams).any?
|
128
|
+
raise StepError.new(
|
129
|
+
"Cannot specify metaparameters when using top-level keys with same name: #{dups.join(', ')}",
|
130
|
+
body['name'],
|
131
|
+
step_number
|
132
|
+
)
|
133
|
+
end
|
61
134
|
end
|
62
135
|
|
63
136
|
unless body.fetch('parameters', {}).is_a?(Hash)
|
64
137
|
msg = "Parameters key must be a hash"
|
65
|
-
raise
|
138
|
+
raise StepError.new(msg, body['name'], step_number)
|
66
139
|
end
|
67
140
|
|
68
141
|
if body.key?('name')
|
69
142
|
name = body['name']
|
70
143
|
unless name.is_a?(String) && name.match?(Bolt::PAL::YamlPlan::VAR_NAME_PATTERN)
|
71
144
|
error_message = "Invalid step name: #{name.inspect}"
|
72
|
-
raise
|
145
|
+
raise StepError.new(error_message, body['name'], step_number)
|
73
146
|
end
|
74
147
|
end
|
75
148
|
end
|
@@ -81,8 +154,7 @@ module Bolt
|
|
81
154
|
illegal_keys = body.keys.to_set - allowed_keys
|
82
155
|
if illegal_keys.any?
|
83
156
|
error_message = "The #{step_type.inspect} step does not support: #{illegal_keys.to_a.inspect} key(s)"
|
84
|
-
|
85
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
157
|
+
raise StepError.new(error_message, body['name'], step_number)
|
86
158
|
end
|
87
159
|
|
88
160
|
# Ensure all required keys are present
|
@@ -90,8 +162,7 @@ module Bolt
|
|
90
162
|
|
91
163
|
if missing_keys.any?
|
92
164
|
error_message = "The #{step_type.inspect} step requires: #{missing_keys.to_a.inspect} key(s)"
|
93
|
-
|
94
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
165
|
+
raise StepError.new(error_message, body['name'], step_number)
|
95
166
|
end
|
96
167
|
end
|
97
168
|
|
@@ -123,12 +194,6 @@ module Bolt
|
|
123
194
|
raise Bolt::Error.new("Error parsing #{step_key.inspect}: #{e.basic_message}", "bolt/invalid-plan")
|
124
195
|
end
|
125
196
|
|
126
|
-
def self.step_error(message, name, step_number)
|
127
|
-
identifier = name ? name.inspect : "number #{step_number}"
|
128
|
-
error = "Parse error in step #{identifier}: \n #{message}"
|
129
|
-
Bolt::Error.new(error, 'bolt/invalid-plan')
|
130
|
-
end
|
131
|
-
|
132
197
|
# Parses the an evaluable string, optionally quote it before parsing
|
133
198
|
def self.parse_code_string(code, quote = false)
|
134
199
|
if quote
|
@@ -138,11 +203,6 @@ module Bolt
|
|
138
203
|
Puppet::Pops::Parser::EvaluatingParser.new.parse_string(code)
|
139
204
|
end
|
140
205
|
end
|
141
|
-
|
142
|
-
def function_call(function, args)
|
143
|
-
code_args = args.map { |arg| Bolt::Util.to_code(arg) }
|
144
|
-
"#{function}(#{code_args.join(', ')})"
|
145
|
-
end
|
146
206
|
end
|
147
207
|
end
|
148
208
|
end
|
@@ -5,30 +5,30 @@ module Bolt
|
|
5
5
|
class YamlPlan
|
6
6
|
class Step
|
7
7
|
class Command < Step
|
8
|
-
def self.
|
9
|
-
|
8
|
+
def self.option_keys
|
9
|
+
Set['catch_errors', 'env_vars', 'run_as']
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.required_keys
|
13
|
-
Set['targets']
|
13
|
+
Set['command', 'targets']
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def transpile
|
22
|
-
code = String.new(" ")
|
23
|
-
code << "$#{@name} = " if @name
|
16
|
+
# Returns an array of arguments to pass to the step's function call
|
17
|
+
#
|
18
|
+
private def format_args(body)
|
19
|
+
opts = format_options(body)
|
24
20
|
|
25
|
-
|
26
|
-
args
|
27
|
-
args <<
|
21
|
+
args = [body['command'], body['targets']]
|
22
|
+
args << body['description'] if body['description']
|
23
|
+
args << opts if opts.any?
|
28
24
|
|
29
|
-
|
25
|
+
args
|
26
|
+
end
|
30
27
|
|
31
|
-
|
28
|
+
# Returns the function corresponding to the step
|
29
|
+
#
|
30
|
+
private def function
|
31
|
+
'run_command'
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -5,31 +5,30 @@ module Bolt
|
|
5
5
|
class YamlPlan
|
6
6
|
class Step
|
7
7
|
class Download < Step
|
8
|
-
def self.
|
9
|
-
|
8
|
+
def self.option_keys
|
9
|
+
Set['catch_errors', 'run_as']
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.required_keys
|
13
13
|
Set['download', 'destination', 'targets']
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
def transpile
|
23
|
-
code = String.new(" ")
|
24
|
-
code << "$#{@name} = " if @name
|
16
|
+
# Returns an array of arguments to pass to the step's function call
|
17
|
+
#
|
18
|
+
private def format_args(body)
|
19
|
+
opts = format_options(body)
|
25
20
|
|
26
|
-
|
27
|
-
args
|
28
|
-
args <<
|
21
|
+
args = [body['download'], body['destination'], body['targets']]
|
22
|
+
args << body['description'] if body['description']
|
23
|
+
args << opts if opts.any?
|
29
24
|
|
30
|
-
|
25
|
+
args
|
26
|
+
end
|
31
27
|
|
32
|
-
|
28
|
+
# Returns the function corresponding to the step
|
29
|
+
#
|
30
|
+
private def function
|
31
|
+
'download_file'
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
@@ -5,28 +5,28 @@ module Bolt
|
|
5
5
|
class YamlPlan
|
6
6
|
class Step
|
7
7
|
class Eval < Step
|
8
|
-
def self.allowed_keys
|
9
|
-
super + Set['eval']
|
10
|
-
end
|
11
|
-
|
12
8
|
def self.required_keys
|
13
|
-
Set
|
9
|
+
Set['eval']
|
14
10
|
end
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
# Evaluates the step
|
13
|
+
#
|
14
|
+
def evaluate(scope, evaluator)
|
15
|
+
evaluated = evaluator.evaluate_code_blocks(scope, body)
|
16
|
+
evaluated['eval']
|
19
17
|
end
|
20
18
|
|
19
|
+
# Transpiles the step into the plan language
|
20
|
+
#
|
21
21
|
def transpile
|
22
22
|
code = String.new(" ")
|
23
|
-
code << "$#{
|
23
|
+
code << "$#{body['name']} = " if body['name']
|
24
24
|
|
25
|
-
code_body = Bolt::Util.to_code(
|
25
|
+
code_body = Bolt::Util.to_code(body['eval']) || 'undef'
|
26
26
|
|
27
27
|
# If we're trying to assign the result of a multi-line eval to a name
|
28
28
|
# variable, we need to wrap it in `with()`.
|
29
|
-
if
|
29
|
+
if body['name'] && code_body.lines.count > 1
|
30
30
|
indented = code_body.gsub(/\n/, "\n ").chomp(" ")
|
31
31
|
code << "with() || {\n #{indented}}"
|
32
32
|
else
|
@@ -13,14 +13,23 @@ module Bolt
|
|
13
13
|
Set['message']
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
# Returns an array of arguments to pass to the step's function call
|
17
|
+
#
|
18
|
+
private def format_args(body)
|
19
|
+
[body['message']]
|
19
20
|
end
|
20
21
|
|
22
|
+
# Returns the function corresponding to the step
|
23
|
+
#
|
24
|
+
private def function
|
25
|
+
'out::message'
|
26
|
+
end
|
27
|
+
|
28
|
+
# Transpiles the step into the plan language
|
29
|
+
#
|
21
30
|
def transpile
|
22
31
|
code = String.new(" ")
|
23
|
-
code << function_call(
|
32
|
+
code << function_call(function, format_args(body))
|
24
33
|
code << "\n"
|
25
34
|
end
|
26
35
|
end
|
@@ -6,30 +6,34 @@ module Bolt
|
|
6
6
|
class Step
|
7
7
|
class Plan < Step
|
8
8
|
def self.allowed_keys
|
9
|
-
super + Set['
|
9
|
+
super + Set['parameters']
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.
|
13
|
-
Set
|
12
|
+
def self.option_keys
|
13
|
+
Set['catch_errors', 'run_as']
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
@plan = step_body['plan']
|
19
|
-
@parameters = step_body.fetch('parameters', {})
|
16
|
+
def self.required_keys
|
17
|
+
Set['plan']
|
20
18
|
end
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
# Returns an array of arguments to pass to the step's function call
|
21
|
+
#
|
22
|
+
private def format_args(body)
|
23
|
+
opts = format_options(body)
|
24
|
+
params = (body['parameters'] || {}).merge(opts)
|
25
25
|
|
26
|
-
|
27
|
-
args
|
28
|
-
args <<
|
26
|
+
args = [body['plan']]
|
27
|
+
args << body['targets'] if body['targets']
|
28
|
+
args << params if params.any?
|
29
29
|
|
30
|
-
|
30
|
+
args
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
+
# Returns the function corresponding to the step
|
34
|
+
#
|
35
|
+
private def function
|
36
|
+
'run_plan'
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -5,18 +5,81 @@ module Bolt
|
|
5
5
|
class YamlPlan
|
6
6
|
class Step
|
7
7
|
class Resources < Step
|
8
|
-
def self.
|
9
|
-
|
8
|
+
def self.option_keys
|
9
|
+
Set['catch_errors', 'description', 'noop', 'run_as']
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.required_keys
|
13
|
-
Set['targets']
|
13
|
+
Set['resources', 'targets']
|
14
14
|
end
|
15
15
|
|
16
|
-
def initialize(
|
16
|
+
def initialize(body)
|
17
17
|
super
|
18
|
-
@resources =
|
19
|
-
|
18
|
+
@body['resources'] = normalize_resources(@body['resources'])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns an array of arguments to pass to the apply function call
|
22
|
+
#
|
23
|
+
private def format_args(body)
|
24
|
+
opts = format_options(body)
|
25
|
+
|
26
|
+
args = [body['targets']]
|
27
|
+
args << opts if opts.any?
|
28
|
+
|
29
|
+
args
|
30
|
+
end
|
31
|
+
|
32
|
+
def evaluate(scope, evaluator)
|
33
|
+
evaluated = evaluator.evaluate_code_blocks(scope, body)
|
34
|
+
|
35
|
+
scope.call_function('apply_prep', evaluated['targets'])
|
36
|
+
|
37
|
+
apply_args = format_args(evaluated)
|
38
|
+
manifest = generate_manifest(evaluated['resources'])
|
39
|
+
apply_manifest(scope, apply_args, manifest)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Generates a manifest from the resources
|
43
|
+
#
|
44
|
+
private def generate_manifest(resources)
|
45
|
+
# inspect returns the Ruby representation of the resource hashes,
|
46
|
+
# which happens to be the same as the Puppet representation
|
47
|
+
puppet_resources = resources.inspect
|
48
|
+
|
49
|
+
# Because the :tasks setting globally controls which mode the parser
|
50
|
+
# is in, we need to make this snippet of non-tasks manifest code
|
51
|
+
# parseable in tasks mode. The way to do that is by putting it in an
|
52
|
+
# apply statement and taking the body.
|
53
|
+
<<~MANIFEST
|
54
|
+
apply('placeholder') {
|
55
|
+
$resources = #{puppet_resources}
|
56
|
+
$resources.each |$res| {
|
57
|
+
Resource[$res['type']] { $res['title']:
|
58
|
+
* => $res['parameters'],
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
# Add relationships if there is more than one resource
|
63
|
+
if $resources.length > 1 {
|
64
|
+
($resources.length - 1).each |$index| {
|
65
|
+
$lhs = $resources[$index]
|
66
|
+
$rhs = $resources[$index+1]
|
67
|
+
$lhs_resource = Resource[$lhs['type'] , $lhs['title']]
|
68
|
+
$rhs_resource = Resource[$rhs['type'] , $rhs['title']]
|
69
|
+
$lhs_resource -> $rhs_resource
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
MANIFEST
|
74
|
+
end
|
75
|
+
|
76
|
+
# Applies the manifest block on the targets
|
77
|
+
#
|
78
|
+
private def apply_manifest(scope, args, manifest)
|
79
|
+
ast = self.class.parse_code_string(manifest)
|
80
|
+
apply_block = ast.body.body
|
81
|
+
applicator = Puppet.lookup(:apply_executor)
|
82
|
+
applicator.apply(args, apply_block, scope)
|
20
83
|
end
|
21
84
|
|
22
85
|
def self.validate(body, step_number)
|
@@ -26,26 +89,28 @@ module Bolt
|
|
26
89
|
if resource['type'] || resource['title']
|
27
90
|
if !resource['type']
|
28
91
|
err = "Resource declaration must include type key if title key is set"
|
29
|
-
raise
|
92
|
+
raise StepError.new(err, body['name'], step_number)
|
30
93
|
elsif !resource['title']
|
31
94
|
err = "Resource declaration must include title key if type key is set"
|
32
|
-
raise
|
95
|
+
raise StepError.new(err, body['name'], step_number)
|
33
96
|
end
|
34
97
|
else
|
35
98
|
type_keys = (resource.keys - ['parameters'])
|
36
99
|
if type_keys.empty?
|
37
100
|
err = "Resource declaration is missing a type"
|
38
|
-
raise
|
101
|
+
raise StepError.new(err, body['name'], step_number)
|
39
102
|
elsif type_keys.length > 1
|
40
103
|
err = "Resource declaration has ambiguous type: could be #{type_keys.join(' or ')}"
|
41
|
-
raise
|
104
|
+
raise StepError.new(err, body['name'], step_number)
|
42
105
|
end
|
43
106
|
end
|
44
107
|
end
|
45
108
|
end
|
46
109
|
|
110
|
+
# Normalizes the resources so they are in a format compatible with apply blocks
|
47
111
|
# What if this comes from a code block?
|
48
|
-
|
112
|
+
#
|
113
|
+
private def normalize_resources(resources)
|
49
114
|
resources.map do |resource|
|
50
115
|
if resource['type'] && resource['title']
|
51
116
|
type = resource['type']
|
@@ -59,25 +124,21 @@ module Bolt
|
|
59
124
|
end
|
60
125
|
end
|
61
126
|
|
62
|
-
def body
|
63
|
-
@body.merge('resources' => @normalized_resources)
|
64
|
-
end
|
65
|
-
|
66
127
|
def transpile
|
67
128
|
code = StringIO.new
|
68
129
|
|
69
130
|
code.print " "
|
70
|
-
|
71
|
-
args = [@targets]
|
72
|
-
code << function_call(fn, args)
|
131
|
+
code << function_call('apply_prep', [body['targets']])
|
73
132
|
code.print "\n"
|
74
133
|
|
75
134
|
code.print " "
|
76
|
-
code.print "$#{
|
135
|
+
code.print "$#{body['name']} = " if body['name']
|
136
|
+
|
137
|
+
code << function_call('apply', format_args(body))
|
77
138
|
|
78
|
-
code.
|
139
|
+
code.print " {\n"
|
79
140
|
|
80
|
-
declarations =
|
141
|
+
declarations = body['resources'].map do |resource|
|
81
142
|
type = resource['type'].is_a?(EvaluableString) ? resource['type'].value : resource['type']
|
82
143
|
title = Bolt::Util.to_code(resource['title'])
|
83
144
|
parameters = resource['parameters'].transform_values do |val|
|