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
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
require 'bolt/config/transport/base'
|
5
|
+
|
6
|
+
module Bolt
|
7
|
+
class Config
|
8
|
+
module Transport
|
9
|
+
class LXD < Base
|
10
|
+
OPTIONS = %w[
|
11
|
+
cleanup
|
12
|
+
tmpdir
|
13
|
+
].freeze
|
14
|
+
|
15
|
+
DEFAULTS = {
|
16
|
+
'cleanup' => true
|
17
|
+
}.freeze
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -32,7 +32,7 @@ module Bolt
|
|
32
32
|
"cleanup" => {
|
33
33
|
type: [TrueClass, FalseClass],
|
34
34
|
description: "Whether to clean up temporary files created on targets. When running commands on a target, "\
|
35
|
-
"Bolt
|
35
|
+
"Bolt might create temporary files. After completing the command, these files are "\
|
36
36
|
"automatically deleted. This value can be set to 'false' if you wish to leave these "\
|
37
37
|
"temporary files on the target.",
|
38
38
|
_plugin: true,
|
data/lib/bolt/executor.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
require 'English'
|
5
5
|
require 'json'
|
6
6
|
require 'logging'
|
7
|
+
require 'pathname'
|
7
8
|
require 'set'
|
8
9
|
require 'bolt/analytics'
|
9
10
|
require 'bolt/result'
|
@@ -15,6 +16,7 @@ require 'bolt/transport/ssh'
|
|
15
16
|
require 'bolt/transport/winrm'
|
16
17
|
require 'bolt/transport/orch'
|
17
18
|
require 'bolt/transport/local'
|
19
|
+
require 'bolt/transport/lxd'
|
18
20
|
require 'bolt/transport/docker'
|
19
21
|
require 'bolt/transport/remote'
|
20
22
|
require 'bolt/yarn'
|
@@ -25,6 +27,7 @@ module Bolt
|
|
25
27
|
winrm: Bolt::Transport::WinRM,
|
26
28
|
pcp: Bolt::Transport::Orch,
|
27
29
|
local: Bolt::Transport::Local,
|
30
|
+
lxd: Bolt::Transport::LXD,
|
28
31
|
docker: Bolt::Transport::Docker,
|
29
32
|
remote: Bolt::Transport::Remote
|
30
33
|
}.freeze
|
@@ -39,7 +42,6 @@ module Bolt
|
|
39
42
|
modified_concurrency = false)
|
40
43
|
# lazy-load expensive gem code
|
41
44
|
require 'concurrent'
|
42
|
-
|
43
45
|
@analytics = analytics
|
44
46
|
@logger = Bolt::Logger.logger(self)
|
45
47
|
|
@@ -121,8 +123,8 @@ module Bolt
|
|
121
123
|
def queue_execute(targets)
|
122
124
|
if @warn_concurrency && targets.length > @concurrency
|
123
125
|
@warn_concurrency = false
|
124
|
-
msg = "The ulimit is low, which
|
125
|
-
"'#{@concurrency}' to mitigate those issues, which
|
126
|
+
msg = "The ulimit is low, which might cause file limit issues. Default concurrency has been set to "\
|
127
|
+
"'#{@concurrency}' to mitigate those issues, which might cause Bolt to run slow. "\
|
126
128
|
"Disable this warning by configuring ulimit using 'ulimit -n <limit>' in your shell "\
|
127
129
|
"configuration, or by configuring Bolt's concurrency. "\
|
128
130
|
"See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
|
@@ -231,6 +233,11 @@ module Bolt
|
|
231
233
|
@analytics.report_bundled_content(mode, name)
|
232
234
|
end
|
233
235
|
|
236
|
+
def report_file_source(plan_function, source)
|
237
|
+
label = Pathname.new(source).absolute? ? 'absolute' : 'module'
|
238
|
+
@analytics&.event('Plan', plan_function, label: label)
|
239
|
+
end
|
240
|
+
|
234
241
|
def report_apply(statement_count, resource_counts)
|
235
242
|
data = { statement_count: statement_count }
|
236
243
|
|
data/lib/bolt/logger.rb
CHANGED
@@ -91,6 +91,14 @@ module Bolt
|
|
91
91
|
Logging.logger[:root].appenders.any?
|
92
92
|
end
|
93
93
|
|
94
|
+
def self.stream
|
95
|
+
@stream
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.stream=(stream)
|
99
|
+
@stream = stream
|
100
|
+
end
|
101
|
+
|
94
102
|
# A helper to ensure the Logging library is always initialized with our
|
95
103
|
# custom log levels before retrieving a Logger instance.
|
96
104
|
def self.logger(name)
|
@@ -45,7 +45,7 @@ module Bolt
|
|
45
45
|
# specss. If that fails, fall back to resolving from project specs.
|
46
46
|
# This prevents Bolt from modifying installed modules unless there is
|
47
47
|
# a version conflict.
|
48
|
-
@outputter.print_action_step("Resolving module dependencies, this
|
48
|
+
@outputter.print_action_step("Resolving module dependencies, this might take a moment")
|
49
49
|
|
50
50
|
@outputter.start_spin
|
51
51
|
begin
|
@@ -156,7 +156,7 @@ module Bolt
|
|
156
156
|
# If forcibly installing or if there is no Puppetfile, resolve
|
157
157
|
# and write a Puppetfile.
|
158
158
|
if force || !path.exist?
|
159
|
-
@outputter.print_action_step("Resolving module dependencies, this
|
159
|
+
@outputter.print_action_step("Resolving module dependencies, this might take a moment")
|
160
160
|
|
161
161
|
# This doesn't use the block as it's more testable to just mock *_spin
|
162
162
|
@outputter.start_spin
|
@@ -36,7 +36,7 @@ module Bolt
|
|
36
36
|
raise Bolt::ValidationError, <<~MSG
|
37
37
|
Unable to parse Puppetfile #{path}:
|
38
38
|
#{parsed.validation_errors.join("\n\n")}.
|
39
|
-
This
|
39
|
+
This Puppetfile might not be managed by Bolt.
|
40
40
|
MSG
|
41
41
|
end
|
42
42
|
|
@@ -106,7 +106,7 @@ module Bolt
|
|
106
106
|
|
107
107
|
#{unsatisfied_specs.map(&:to_hash).to_yaml.lines.drop(1).join.chomp}
|
108
108
|
|
109
|
-
This
|
109
|
+
This Puppetfile might not be managed by Bolt. To forcibly overwrite the
|
110
110
|
Puppetfile, run '#{command}'.
|
111
111
|
MESSAGE
|
112
112
|
|
@@ -39,8 +39,8 @@ module Bolt
|
|
39
39
|
unless (match = name.match(NAME_REGEX))
|
40
40
|
raise Bolt::ValidationError,
|
41
41
|
"Invalid name for Forge module specification: #{name}. Name must match "\
|
42
|
-
"'owner/name'. Owner segment
|
43
|
-
"segment must start with a lowercase letter and
|
42
|
+
"'owner/name'. Owner segment can only include letters or digits. Name "\
|
43
|
+
"segment must start with a lowercase letter and can only include lowercase "\
|
44
44
|
"letters, digits, and underscores."
|
45
45
|
end
|
46
46
|
|
@@ -49,8 +49,8 @@ module Bolt
|
|
49
49
|
unless (match = name.match(NAME_REGEX))
|
50
50
|
raise Bolt::ValidationError,
|
51
51
|
"Invalid name for Git module specification: #{name}. Name must match "\
|
52
|
-
"'name' or 'owner/name'. Owner segment
|
53
|
-
"Name segment must start with a lowercase letter and
|
52
|
+
"'name' or 'owner/name'. Owner segment can only include letters or digits. "\
|
53
|
+
"Name segment must start with a lowercase letter and can only include "\
|
54
54
|
"lowercase letters, digits, and underscores."
|
55
55
|
end
|
56
56
|
|
data/lib/bolt/outputter/human.rb
CHANGED
@@ -53,10 +53,21 @@ module Bolt
|
|
53
53
|
string.sub(/\s\z/, '')
|
54
54
|
end
|
55
55
|
|
56
|
+
# Wraps a string to the specified width. Lines only wrap
|
57
|
+
# at whitespace.
|
58
|
+
#
|
56
59
|
def wrap(string, width = 80)
|
60
|
+
return string unless string.is_a?(String)
|
57
61
|
string.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
58
62
|
end
|
59
63
|
|
64
|
+
# Trims a string to a specified width, adding an ellipsis if it's longer.
|
65
|
+
#
|
66
|
+
def truncate(string, width = 80)
|
67
|
+
return string unless string.is_a?(String) && string.length > width
|
68
|
+
string.lines.first[0...width].gsub(/\s\w+\s*$/, '...')
|
69
|
+
end
|
70
|
+
|
60
71
|
def handle_event(event)
|
61
72
|
case event[:type]
|
62
73
|
when :enable_default_output
|
@@ -218,11 +229,11 @@ module Bolt
|
|
218
229
|
@stream.puts total_msg
|
219
230
|
end
|
220
231
|
|
221
|
-
def
|
232
|
+
def format_table(results, padding_left = 0, padding_right = 3)
|
222
233
|
# lazy-load expensive gem code
|
223
234
|
require 'terminal-table'
|
224
235
|
|
225
|
-
|
236
|
+
Terminal::Table.new(
|
226
237
|
rows: results,
|
227
238
|
style: {
|
228
239
|
border_x: '',
|
@@ -238,10 +249,22 @@ module Bolt
|
|
238
249
|
|
239
250
|
def print_tasks(tasks, modulepath)
|
240
251
|
command = Bolt::Util.powershell? ? 'Get-BoltTask -Task <TASK NAME>' : 'bolt task show <TASK NAME>'
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
252
|
+
|
253
|
+
tasks = tasks.map do |name, description|
|
254
|
+
description = truncate(description, 72)
|
255
|
+
[name, description]
|
256
|
+
end
|
257
|
+
|
258
|
+
@stream.puts colorize(:cyan, 'Tasks')
|
259
|
+
@stream.puts tasks.any? ? format_table(tasks, 2) : indent(2, 'No available tasks')
|
260
|
+
@stream.puts
|
261
|
+
|
262
|
+
@stream.puts colorize(:cyan, 'Modulepath')
|
263
|
+
@stream.puts indent(2, modulepath.join(File::PATH_SEPARATOR))
|
264
|
+
@stream.puts
|
265
|
+
|
266
|
+
@stream.puts colorize(:cyan, 'Additional information')
|
267
|
+
@stream.puts indent(2, "Use '#{command}' to view details and parameters for a specific task.")
|
245
268
|
end
|
246
269
|
|
247
270
|
# @param [Hash] task A hash representing the task
|
@@ -322,10 +345,22 @@ module Bolt
|
|
322
345
|
|
323
346
|
def print_plans(plans, modulepath)
|
324
347
|
command = Bolt::Util.powershell? ? 'Get-BoltPlan -Name <PLAN NAME>' : 'bolt plan show <PLAN NAME>'
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
348
|
+
|
349
|
+
plans = plans.map do |name, description|
|
350
|
+
description = truncate(description, 72)
|
351
|
+
[name, description]
|
352
|
+
end
|
353
|
+
|
354
|
+
@stream.puts colorize(:cyan, 'Plans')
|
355
|
+
@stream.puts plans.any? ? format_table(plans, 2) : indent(2, 'No available plans')
|
356
|
+
@stream.puts
|
357
|
+
|
358
|
+
@stream.puts colorize(:cyan, 'Modulepath')
|
359
|
+
@stream.puts indent(2, modulepath.join(File::PATH_SEPARATOR))
|
360
|
+
@stream.puts
|
361
|
+
|
362
|
+
@stream.puts colorize(:cyan, 'Additional information')
|
363
|
+
@stream.puts indent(2, "Use '#{command}' to view details and parameters for a specific plan.")
|
329
364
|
end
|
330
365
|
|
331
366
|
def print_topics(topics)
|
@@ -359,7 +394,7 @@ module Bolt
|
|
359
394
|
[m[:name], version]
|
360
395
|
end
|
361
396
|
|
362
|
-
|
397
|
+
@stream.puts format_table(module_info, 2, 1)
|
363
398
|
end
|
364
399
|
|
365
400
|
@stream.write("\n")
|
@@ -374,7 +409,7 @@ module Bolt
|
|
374
409
|
targets += target_list[:adhoc].map { |target| [target.name, adhoc] }
|
375
410
|
|
376
411
|
if targets.any?
|
377
|
-
|
412
|
+
@stream.puts format_table(targets, 0, 2)
|
378
413
|
@stream.puts
|
379
414
|
end
|
380
415
|
|
data/lib/bolt/pal.rb
CHANGED
@@ -385,7 +385,7 @@ module Bolt
|
|
385
385
|
plan_cache[plan_name] = info
|
386
386
|
end
|
387
387
|
|
388
|
-
list << [plan_name] unless info['private']
|
388
|
+
list << [plan_name, info['description']] unless info['private']
|
389
389
|
end
|
390
390
|
|
391
391
|
File.write(@project.plan_cache_file, plan_cache.to_json) if updated
|
@@ -446,7 +446,7 @@ module Bolt
|
|
446
446
|
params[name] = { 'type' => param.types.first }
|
447
447
|
params[name]['sensitive'] = param.types.first =~ /\ASensitive(\[.*\])?\z/ ? true : false
|
448
448
|
params[name]['default_value'] = defaults[name] if defaults.key?(name)
|
449
|
-
params[name]['description'] = param.text
|
449
|
+
params[name]['description'] = param.text if param.text && !param.text.empty?
|
450
450
|
else
|
451
451
|
Bolt::Logger.warn(
|
452
452
|
"missing_plan_parameter",
|
data/lib/bolt/pal/yaml_plan.rb
CHANGED
@@ -73,8 +73,7 @@ module Bolt
|
|
73
73
|
def duplicate_check(used_names, name, step_number)
|
74
74
|
if used_names.include?(name)
|
75
75
|
error_message = "Duplicate step name or parameter detected: #{name.inspect}"
|
76
|
-
|
77
|
-
raise Bolt::Error.new(err, "bolt/invalid-plan")
|
76
|
+
raise Step::StepError.new(error_message, name, step_number)
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
@@ -12,153 +12,15 @@ module Bolt
|
|
12
12
|
@evaluator = Puppet::Pops::Parser::EvaluatingParser.new
|
13
13
|
end
|
14
14
|
|
15
|
-
def dispatch_step(scope, step)
|
16
|
-
step_body = evaluate_code_blocks(scope, step.body)
|
17
|
-
|
18
|
-
# Dispatch based on the step class name
|
19
|
-
step_type = step.class.name.split('::').last.downcase
|
20
|
-
method = "#{step_type}_step"
|
21
|
-
|
22
|
-
send(method, scope, step_body)
|
23
|
-
end
|
24
|
-
|
25
|
-
def task_step(scope, step)
|
26
|
-
task = step['task']
|
27
|
-
targets = step['targets']
|
28
|
-
description = step['description']
|
29
|
-
params = step['parameters'] || {}
|
30
|
-
|
31
|
-
args = if description
|
32
|
-
[task, targets, description, params]
|
33
|
-
else
|
34
|
-
[task, targets, params]
|
35
|
-
end
|
36
|
-
|
37
|
-
scope.call_function('run_task', args)
|
38
|
-
end
|
39
|
-
|
40
|
-
def plan_step(scope, step)
|
41
|
-
plan = step['plan']
|
42
|
-
parameters = step['parameters'] || {}
|
43
|
-
|
44
|
-
args = [plan, parameters]
|
45
|
-
|
46
|
-
scope.call_function('run_plan', args)
|
47
|
-
end
|
48
|
-
|
49
|
-
def script_step(scope, step)
|
50
|
-
script = step['script']
|
51
|
-
targets = step['targets']
|
52
|
-
description = step['description']
|
53
|
-
arguments = step['arguments'] || []
|
54
|
-
|
55
|
-
options = { 'arguments' => arguments }
|
56
|
-
args = if description
|
57
|
-
[script, targets, description, options]
|
58
|
-
else
|
59
|
-
[script, targets, options]
|
60
|
-
end
|
61
|
-
|
62
|
-
scope.call_function('run_script', args)
|
63
|
-
end
|
64
|
-
|
65
|
-
def command_step(scope, step)
|
66
|
-
command = step['command']
|
67
|
-
targets = step['targets']
|
68
|
-
description = step['description']
|
69
|
-
|
70
|
-
args = [command, targets]
|
71
|
-
args << description if description
|
72
|
-
scope.call_function('run_command', args)
|
73
|
-
end
|
74
|
-
|
75
|
-
def upload_step(scope, step)
|
76
|
-
source = step['upload']
|
77
|
-
destination = step['destination']
|
78
|
-
targets = step['targets']
|
79
|
-
description = step['description']
|
80
|
-
|
81
|
-
args = [source, destination, targets]
|
82
|
-
args << description if description
|
83
|
-
scope.call_function('upload_file', args)
|
84
|
-
end
|
85
|
-
|
86
|
-
def download_step(scope, step)
|
87
|
-
source = step['download']
|
88
|
-
destination = step['destination']
|
89
|
-
targets = step['targets']
|
90
|
-
description = step['description']
|
91
|
-
|
92
|
-
args = [source, destination, targets]
|
93
|
-
args << description if description
|
94
|
-
scope.call_function('download_file', args)
|
95
|
-
end
|
96
|
-
|
97
|
-
def eval_step(_scope, step)
|
98
|
-
step['eval']
|
99
|
-
end
|
100
|
-
|
101
|
-
def resources_step(scope, step)
|
102
|
-
targets = step['targets']
|
103
|
-
|
104
|
-
# TODO: Only call apply_prep when needed
|
105
|
-
scope.call_function('apply_prep', targets)
|
106
|
-
manifest = generate_manifest(step['resources'])
|
107
|
-
|
108
|
-
apply_manifest(scope, targets, manifest)
|
109
|
-
end
|
110
|
-
|
111
|
-
def message_step(scope, step)
|
112
|
-
scope.call_function('out::message', [step['message']])
|
113
|
-
end
|
114
|
-
|
115
|
-
def generate_manifest(resources)
|
116
|
-
# inspect returns the Ruby representation of the resource hashes,
|
117
|
-
# which happens to be the same as the Puppet representation
|
118
|
-
puppet_resources = resources.inspect
|
119
|
-
|
120
|
-
# Because the :tasks setting globally controls which mode the parser
|
121
|
-
# is in, we need to make this snippet of non-tasks manifest code
|
122
|
-
# parseable in tasks mode. The way to do that is by putting it in an
|
123
|
-
# apply statement and taking the body.
|
124
|
-
<<~MANIFEST
|
125
|
-
apply('placeholder') {
|
126
|
-
$resources = #{puppet_resources}
|
127
|
-
$resources.each |$res| {
|
128
|
-
Resource[$res['type']] { $res['title']:
|
129
|
-
* => $res['parameters'],
|
130
|
-
}
|
131
|
-
}
|
132
|
-
|
133
|
-
# Add relationships if there is more than one resource
|
134
|
-
if $resources.length > 1 {
|
135
|
-
($resources.length - 1).each |$index| {
|
136
|
-
$lhs = $resources[$index]
|
137
|
-
$rhs = $resources[$index+1]
|
138
|
-
$lhs_resource = Resource[$lhs['type'] , $lhs['title']]
|
139
|
-
$rhs_resource = Resource[$rhs['type'] , $rhs['title']]
|
140
|
-
$lhs_resource -> $rhs_resource
|
141
|
-
}
|
142
|
-
}
|
143
|
-
}
|
144
|
-
MANIFEST
|
145
|
-
end
|
146
|
-
|
147
|
-
def apply_manifest(scope, targets, manifest)
|
148
|
-
ast = @evaluator.parse_string(manifest)
|
149
|
-
apply_block = ast.body.body
|
150
|
-
applicator = Puppet.lookup(:apply_executor)
|
151
|
-
applicator.apply([targets], apply_block, scope)
|
152
|
-
end
|
153
|
-
|
154
15
|
# This is the method that Puppet calls to evaluate the plan. The name
|
155
16
|
# makes more sense for .pp plans.
|
17
|
+
#
|
156
18
|
def evaluate_block_with_bindings(closure_scope, args_hash, plan)
|
157
19
|
plan_result = closure_scope.with_local_scope(args_hash) do |scope|
|
158
20
|
plan.steps.each do |step|
|
159
|
-
step_result =
|
21
|
+
step_result = step.evaluate(scope, self)
|
160
22
|
|
161
|
-
scope.setvar(step.name, step_result) if step.name
|
23
|
+
scope.setvar(step.body['name'], step_result) if step.body['name']
|
162
24
|
end
|
163
25
|
|
164
26
|
evaluate_code_blocks(scope, plan.return)
|
@@ -168,6 +30,7 @@ module Bolt
|
|
168
30
|
end
|
169
31
|
|
170
32
|
# Recursively evaluate any EvaluableString instances in the object.
|
33
|
+
#
|
171
34
|
def evaluate_code_blocks(scope, value)
|
172
35
|
# XXX We should establish a local scope here probably
|
173
36
|
case value
|
@@ -192,6 +55,7 @@ module Bolt
|
|
192
55
|
# Occasionally the Closure will ask us to evaluate what it assumes are
|
193
56
|
# AST objects. Because we've sidestepped the AST, they aren't, so just
|
194
57
|
# return the values as already evaluated.
|
58
|
+
#
|
195
59
|
def evaluate(value, _scope)
|
196
60
|
value
|
197
61
|
end
|