bolt 2.40.1 → 3.0.1

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.

Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +17 -17
  3. data/bolt-modules/boltlib/lib/puppet/functions/apply_prep.rb +25 -0
  4. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +6 -8
  5. data/bolt-modules/boltlib/lib/puppet/functions/wait_until_available.rb +7 -3
  6. data/lib/bolt/analytics.rb +3 -2
  7. data/lib/bolt/applicator.rb +11 -1
  8. data/lib/bolt/bolt_option_parser.rb +3 -113
  9. data/lib/bolt/catalog.rb +10 -29
  10. data/lib/bolt/cli.rb +58 -157
  11. data/lib/bolt/config.rb +62 -239
  12. data/lib/bolt/config/options.rb +58 -97
  13. data/lib/bolt/config/transport/local.rb +1 -0
  14. data/lib/bolt/config/transport/options.rb +8 -1
  15. data/lib/bolt/config/transport/orch.rb +1 -0
  16. data/lib/bolt/executor.rb +15 -5
  17. data/lib/bolt/inventory.rb +3 -2
  18. data/lib/bolt/inventory/group.rb +35 -4
  19. data/lib/bolt/inventory/inventory.rb +1 -1
  20. data/lib/bolt/logger.rb +115 -11
  21. data/lib/bolt/module.rb +10 -2
  22. data/lib/bolt/module_installer.rb +4 -2
  23. data/lib/bolt/module_installer/resolver.rb +65 -12
  24. data/lib/bolt/module_installer/specs/forge_spec.rb +8 -2
  25. data/lib/bolt/module_installer/specs/git_spec.rb +17 -2
  26. data/lib/bolt/outputter/human.rb +9 -5
  27. data/lib/bolt/outputter/json.rb +16 -16
  28. data/lib/bolt/outputter/rainbow.rb +3 -3
  29. data/lib/bolt/pal.rb +93 -14
  30. data/lib/bolt/pal/yaml_plan.rb +8 -2
  31. data/lib/bolt/pal/yaml_plan/evaluator.rb +7 -19
  32. data/lib/bolt/pal/yaml_plan/step.rb +3 -24
  33. data/lib/bolt/pal/yaml_plan/step/upload.rb +2 -2
  34. data/lib/bolt/pal/yaml_plan/transpiler.rb +6 -1
  35. data/lib/bolt/plugin.rb +3 -3
  36. data/lib/bolt/plugin/cache.rb +7 -7
  37. data/lib/bolt/plugin/module.rb +0 -23
  38. data/lib/bolt/plugin/puppet_connect_data.rb +77 -0
  39. data/lib/bolt/plugin/puppetdb.rb +1 -1
  40. data/lib/bolt/project.rb +54 -81
  41. data/lib/bolt/project_manager.rb +4 -3
  42. data/lib/bolt/project_manager/module_migrator.rb +6 -5
  43. data/lib/bolt/rerun.rb +1 -1
  44. data/lib/bolt/shell/bash.rb +1 -1
  45. data/lib/bolt/shell/bash/tmpdir.rb +4 -1
  46. data/lib/bolt/shell/powershell.rb +3 -4
  47. data/lib/bolt/shell/powershell/snippets.rb +9 -149
  48. data/lib/bolt/task.rb +1 -1
  49. data/lib/bolt/transport/docker/connection.rb +2 -2
  50. data/lib/bolt/transport/local.rb +1 -9
  51. data/lib/bolt/transport/orch/connection.rb +1 -1
  52. data/lib/bolt/transport/ssh.rb +1 -2
  53. data/lib/bolt/transport/ssh/connection.rb +1 -1
  54. data/lib/bolt/validator.rb +2 -2
  55. data/lib/bolt/version.rb +1 -1
  56. data/lib/bolt_server/config.rb +1 -1
  57. data/lib/bolt_server/schemas/partials/task.json +1 -1
  58. data/lib/bolt_server/transport_app.rb +3 -2
  59. data/libexec/bolt_catalog +1 -1
  60. data/modules/aggregate/plans/count.pp +21 -0
  61. data/modules/aggregate/plans/targets.pp +21 -0
  62. data/modules/puppet_connect/plans/test_input_data.pp +31 -0
  63. data/modules/puppetdb_fact/plans/init.pp +10 -0
  64. metadata +27 -18
  65. data/modules/aggregate/plans/nodes.pp +0 -36
@@ -53,31 +53,38 @@ module Bolt
53
53
  # Definitions used to validate config options.
54
54
  # https://github.com/puppetlabs/bolt/blob/main/schemas/README.md
55
55
  OPTIONS = {
56
- "apply_settings" => {
56
+ "apply-settings" => {
57
57
  description: "A map of Puppet settings to use when applying Puppet code using the `apply` "\
58
58
  "plan function or the `bolt apply` command.",
59
59
  type: Hash,
60
60
  properties: {
61
- "show_diff" => {
62
- description: "Whether to log and report a contextual diff.",
61
+ "evaltrace" => {
62
+ description: "Whether each resource should log when it is being evaluated. This allows "\
63
+ "you to interactively see exactly what is being done.",
63
64
  type: [TrueClass, FalseClass],
64
65
  _example: true,
65
66
  _default: false
66
- }
67
- },
68
- _plugin: false,
69
- _deprecation: "This option will be removed in Bolt 3.0. Use `apply-settings` instead."
70
- },
71
- "apply-settings" => {
72
- description: "A map of Puppet settings to use when applying Puppet code using the `apply` "\
73
- "plan function or the `bolt apply` command.",
74
- type: Hash,
75
- properties: {
67
+ },
68
+ "log_level" => {
69
+ description: "The log level for logs in apply reports from Puppet. These can be seen "\
70
+ "in ApplyResults.",
71
+ type: String,
72
+ enum: %w[debug info notice warning err alert emerg crit],
73
+ _example: "debug",
74
+ _default: "notice"
75
+ },
76
76
  "show_diff" => {
77
77
  description: "Whether to log and report a contextual diff.",
78
78
  type: [TrueClass, FalseClass],
79
79
  _example: true,
80
80
  _default: false
81
+ },
82
+ "trace" => {
83
+ description: "Whether to print stack traces on some errors. Will print internal Ruby "\
84
+ "stack trace interleaved with Puppet function frames.",
85
+ type: [TrueClass, FalseClass],
86
+ _example: true,
87
+ _default: false
81
88
  }
82
89
  },
83
90
  _plugin: false
@@ -105,6 +112,17 @@ module Bolt
105
112
  _example: 50,
106
113
  _default: "100 or 1/7 the ulimit, whichever is lower."
107
114
  },
115
+ "disable-warnings" => {
116
+ description: "An array of IDs of warnings to suppress. Warnings with a matching ID will not be logged "\
117
+ "by Bolt. If you are upgrading Bolt to a new major version, you should re-enable all warnings "\
118
+ "until you have finished upgrading.",
119
+ type: Array,
120
+ items: {
121
+ type: String
122
+ },
123
+ _plugin: false,
124
+ _example: ["powershell_2"]
125
+ },
108
126
  "format" => {
109
127
  description: "The format to use when printing results.",
110
128
  type: String,
@@ -128,18 +146,6 @@ module Bolt
128
146
  _plugin: false,
129
147
  _example: {}
130
148
  },
131
- "inventoryfile" => {
132
- description: "The path to a structured data inventory file used to refer to groups of targets on the "\
133
- "command line and from plans. Read more about using inventory files in [Inventory "\
134
- "files](inventory_file_v2.md).",
135
- type: String,
136
- _plugin: false,
137
- _deprecation: "This option will be removed in Bolt 3.0. Use the `--inventoryfile` command-line option "\
138
- "to use a non-default inventory file or move the file contents to `inventory.yaml` in the "\
139
- "project directory.",
140
- _example: "~/.puppetlabs/bolt/inventory.yaml",
141
- _default: "project/inventory.yaml"
142
- },
143
149
  "plugin-cache" => {
144
150
  description: "This feature is experimental. Enable plugin caching and set the time-to-live.",
145
151
  type: Hash,
@@ -171,7 +177,7 @@ module Bolt
171
177
  "level" => {
172
178
  description: "The type of information to log.",
173
179
  type: String,
174
- enum: %w[trace debug error info notice warn fatal any],
180
+ enum: %w[trace debug error info warn fatal any],
175
181
  _default: "warn"
176
182
  }
177
183
  }
@@ -190,7 +196,7 @@ module Bolt
190
196
  "level" => {
191
197
  description: "The type of information to log.",
192
198
  type: String,
193
- enum: %w[trace debug error info notice warn fatal any],
199
+ enum: %w[trace debug error info warn fatal any],
194
200
  _default: "warn"
195
201
  }
196
202
  }
@@ -208,7 +214,7 @@ module Bolt
208
214
  },
209
215
  _plugin: false,
210
216
  _example: ["~/.puppetlabs/bolt/modules", "~/.puppetlabs/bolt/site-modules"],
211
- _default: ["project/modules", "project/site-modules", "project/site"]
217
+ _default: ["project/modules"]
212
218
  },
213
219
  "module-install" => {
214
220
  description: "Options that configure where Bolt downloads modules from. This option is only used when "\
@@ -260,6 +266,10 @@ module Bolt
260
266
  description: "The name of the module.",
261
267
  type: String
262
268
  },
269
+ "resolve" => {
270
+ description: "Whether to resolve the module's dependencies when installing modules.",
271
+ type: [TrueClass, FalseClass]
272
+ },
263
273
  "version_requirement" => {
264
274
  description: "The version requirement for the module. Accepts a specific version (1.2.3), version "\
265
275
  "shorthand (1.2.x), or a version range (>= 1.2.0).",
@@ -274,15 +284,24 @@ module Bolt
274
284
  description: "The URL to the public git repository.",
275
285
  type: String
276
286
  },
287
+ "name" => {
288
+ description: "The name of the module. Required when `resolve` is `false`.",
289
+ type: String
290
+ },
277
291
  "ref" => {
278
292
  description: "The git reference to check out. Can be either a branch, tag, or commit SHA.",
279
293
  type: String
294
+ },
295
+ "resolve" => {
296
+ description: "Whether to resolve the module's dependencies when installing modules.",
297
+ type: [TrueClass, FalseClass]
280
298
  }
281
299
  }
282
300
  }
283
301
  ]
284
302
  },
285
303
  _plugin: false,
304
+ _default: [],
286
305
  _example: [
287
306
  "puppetlabs-facts",
288
307
  { "name" => "puppetlabs-mysql" },
@@ -311,16 +330,6 @@ module Bolt
311
330
  _plugin: false,
312
331
  _example: ["myproject", "myproject::foo", "myproject::bar", "myproject::deploy::*"]
313
332
  },
314
- "plugin_hooks" => {
315
- description: "A map of [plugin hooks](writing_plugins.md#hooks) and which plugins a hook should use. "\
316
- "The only configurable plugin hook is `puppet_library`, which can use two possible plugins: "\
317
- "[`puppet_agent`](https://github.com/puppetlabs/puppetlabs-puppet_agent#puppet_agentinstall) "\
318
- "and [`task`](using_plugins.md#task).",
319
- type: Hash,
320
- _plugin: true,
321
- _example: { "puppet_library" => { "plugin" => "puppet_agent", "version" => "6.15.0", "_run_as" => "root" } },
322
- _deprecation: "This option will be removed in Bolt 3.0. Use `plugin-hooks` instead."
323
- },
324
333
  "plugin-hooks" => {
325
334
  description: "A map of [plugin hooks](writing_plugins.md#hooks) and which plugins a hook should use. "\
326
335
  "The only configurable plugin hook is `puppet_library`, which can use two possible plugins: "\
@@ -398,40 +407,6 @@ module Bolt
398
407
  },
399
408
  _plugin: true
400
409
  },
401
- "puppetfile" => {
402
- description: "A map containing options for the `bolt puppetfile install` command and "\
403
- "`Install-BoltPuppetfile` cmdlet.",
404
- type: Hash,
405
- properties: {
406
- "forge" => {
407
- description: "A subsection that can have its own `proxy` setting to set an HTTP proxy for Forge "\
408
- "operations only, and a `baseurl` setting to specify a different Forge host.",
409
- type: Hash,
410
- properties: {
411
- "baseurl" => {
412
- description: "The URL to the Forge host.",
413
- type: String,
414
- format: "uri",
415
- _example: "https://forge.example.com"
416
- },
417
- "proxy" => {
418
- description: "The HTTP proxy to use for Forge operations.",
419
- type: String,
420
- format: "uri",
421
- _example: "https://my-forge-proxy.com:8080"
422
- }
423
- },
424
- _example: { "baseurl" => "https://forge.example.com", "proxy" => "https://my-forge-proxy.com:8080" }
425
- },
426
- "proxy" => {
427
- description: "The HTTP proxy to use for Git and Forge operations.",
428
- type: String,
429
- format: "uri",
430
- _example: "https://my-proxy.com:8080"
431
- }
432
- },
433
- _plugin: false
434
- },
435
410
  "save-rerun" => {
436
411
  description: "Whether to update `.rerun.json` in the Bolt project directory. If "\
437
412
  "your target names include passwords, set this value to `false` to avoid "\
@@ -475,8 +450,8 @@ module Bolt
475
450
 
476
451
  # Options that configure the inventory, specifically the default transport
477
452
  # used by targets and the transports themselves. These options are used in
478
- # bolt.yaml, under a 'config' key in inventory.yaml, and under the
479
- # 'inventory-config' key in bolt-defaults.yaml.
453
+ # bolt-defaults.yaml under 'inventory-config' and in inventory.yaml under
454
+ # 'config'.
480
455
  INVENTORY_OPTIONS = {
481
456
  "transport" => {
482
457
  description: "The default transport to use when the transport for a target is not "\
@@ -527,57 +502,45 @@ module Bolt
527
502
  }
528
503
  }.freeze
529
504
 
530
- # Options that are available in a bolt.yaml file
531
- BOLT_OPTIONS = %w[
532
- apply-settings
533
- apply_settings
534
- color
505
+ # Options that are available on the command line
506
+ # This only includes options where users can provide arbitrary
507
+ # values from the command-line, allowing the validator to check them
508
+ CLI_OPTIONS = %w[
535
509
  compile-concurrency
536
510
  concurrency
537
511
  format
538
- hiera-config
539
- inventoryfile
540
512
  log
541
513
  modulepath
542
- plugin-hooks
543
- plugin_hooks
544
- plugins
545
- puppetdb
546
- puppetfile
547
- save-rerun
548
- spinner
549
- trusted-external-command
514
+ transport
550
515
  ].freeze
551
516
 
552
517
  # Options that are available in a bolt-defaults.yaml file
553
- BOLT_DEFAULTS_OPTIONS = %w[
518
+ DEFAULTS_OPTIONS = %w[
554
519
  color
555
520
  compile-concurrency
556
521
  concurrency
522
+ disable-warnings
557
523
  format
558
524
  inventory-config
559
525
  log
560
526
  module-install
561
527
  plugin-cache
562
528
  plugin-hooks
563
- plugin_hooks
564
529
  plugins
565
530
  puppetdb
566
- puppetfile
567
531
  save-rerun
568
532
  spinner
569
533
  ].freeze
570
534
 
571
535
  # Options that are available in a bolt-project.yaml file
572
- BOLT_PROJECT_OPTIONS = %w[
536
+ PROJECT_OPTIONS = %w[
573
537
  apply-settings
574
- apply_settings
575
538
  color
576
539
  compile-concurrency
577
540
  concurrency
541
+ disable-warnings
578
542
  format
579
543
  hiera-config
580
- inventoryfile
581
544
  log
582
545
  modulepath
583
546
  module-install
@@ -586,10 +549,8 @@ module Bolt
586
549
  plans
587
550
  plugin-cache
588
551
  plugin-hooks
589
- plugin_hooks
590
552
  plugins
591
553
  puppetdb
592
- puppetfile
593
554
  save-rerun
594
555
  spinner
595
556
  tasks
@@ -17,6 +17,7 @@ module Bolt
17
17
  OPTIONS = WINDOWS_OPTIONS.dup.concat(RUN_AS_OPTIONS).sort.freeze
18
18
 
19
19
  DEFAULTS = {
20
+ 'bundled-ruby' => true,
20
21
  'cleanup' => true
21
22
  }.freeze
22
23
 
@@ -21,7 +21,7 @@ module Bolt
21
21
  type: [TrueClass, FalseClass],
22
22
  _plugin: false,
23
23
  _example: true,
24
- _default: false
24
+ _default: true
25
25
  },
26
26
  "cacert" => {
27
27
  type: String,
@@ -253,6 +253,13 @@ module Bolt
253
253
  _plugin: true,
254
254
  _example: "jump.example.com"
255
255
  },
256
+ "read-timeout" => {
257
+ type: Integer,
258
+ description: "How long to wait in seconds when making requests to the Orchestrator.",
259
+ minimum: 1,
260
+ _plugin: true,
261
+ _example: 15
262
+ },
256
263
  "realm" => {
257
264
  type: String,
258
265
  description: "The Kerberos realm (Active Directory domain) to authenticate against.",
@@ -12,6 +12,7 @@ module Bolt
12
12
  host
13
13
  job-poll-interval
14
14
  job-poll-timeout
15
+ read-timeout
15
16
  service-url
16
17
  task-environment
17
18
  token-file
data/lib/bolt/executor.rb CHANGED
@@ -100,6 +100,8 @@ module Bolt
100
100
  # that type of event, publish the event
101
101
  next unless types.nil? || types.include?(event[:type])
102
102
  @publisher.post(subscriber) do |sub|
103
+ # Wait for user to input to prompt before printing anything
104
+ sleep(0.1) while @prompting
103
105
  sub.handle_event(event)
104
106
  end
105
107
  end
@@ -119,11 +121,12 @@ module Bolt
119
121
  def queue_execute(targets)
120
122
  if @warn_concurrency && targets.length > @concurrency
121
123
  @warn_concurrency = false
122
- @logger.warn("The ulimit is low, which may cause file limit issues. Default concurrency has been set to "\
123
- "'#{@concurrency}' to mitigate those issues, which may cause Bolt to run slow. "\
124
- "Disable this warning by configuring ulimit using 'ulimit -n <limit>' in your shell "\
125
- "configuration, or by configuring Bolt's concurrency. "\
126
- "See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details.")
124
+ msg = "The ulimit is low, which may cause file limit issues. Default concurrency has been set to "\
125
+ "'#{@concurrency}' to mitigate those issues, which may cause Bolt to run slow. "\
126
+ "Disable this warning by configuring ulimit using 'ulimit -n <limit>' in your shell "\
127
+ "configuration, or by configuring Bolt's concurrency. "\
128
+ "See https://puppet.com/docs/bolt/latest/bolt_known_issues.html for details."
129
+ Bolt::Logger.warn("low_ulimit", msg)
127
130
  end
128
131
 
129
132
  targets.group_by(&:transport).flat_map do |protocol, protocol_targets|
@@ -258,7 +261,9 @@ module Bolt
258
261
 
259
262
  def with_node_logging(description, batch, log_level = :info)
260
263
  @logger.send(log_level, "#{description} on #{batch.map(&:safe_name)}")
264
+ publish_event(type: :start_spin)
261
265
  result = yield
266
+ publish_event(type: :stop_spin)
262
267
  @logger.send(log_level, result.to_json)
263
268
  result
264
269
  end
@@ -410,6 +415,7 @@ module Bolt
410
415
  subscribe(self, [:node_result])
411
416
  results = Array.new(skein.length)
412
417
  @in_parallel = true
418
+ publish_event(type: :stop_spin)
413
419
 
414
420
  until skein.empty?
415
421
  @thread_completed = false
@@ -417,6 +423,7 @@ module Bolt
417
423
 
418
424
  skein.each do |yarn|
419
425
  if yarn.alive?
426
+ publish_event(type: :stop_spin)
420
427
  r = yarn.resume
421
428
  else
422
429
  results[yarn.index] = yarn.value
@@ -428,6 +435,7 @@ module Bolt
428
435
  sleep(0.1) until @thread_completed || skein.empty?
429
436
  end
430
437
 
438
+ publish_event(type: :stop_spin)
431
439
  @in_parallel = false
432
440
  unsubscribe(self, [:node_result])
433
441
  results
@@ -469,6 +477,7 @@ module Bolt
469
477
  end
470
478
 
471
479
  def prompt(prompt, options)
480
+ @prompting = true
472
481
  unless $stdin.tty?
473
482
  raise Bolt::Error.new('STDIN is not a tty, unable to prompt', 'bolt/no-tty-error')
474
483
  end
@@ -480,6 +489,7 @@ module Bolt
480
489
  else
481
490
  $stdin.gets.to_s.chomp
482
491
  end
492
+ @prompting = false
483
493
 
484
494
  $stderr.puts if options[:sensitive]
485
495
 
@@ -55,7 +55,8 @@ module Bolt
55
55
  schema = {
56
56
  type: Hash,
57
57
  properties: OPTIONS.map { |opt| [opt, _ref: opt] }.to_h,
58
- definitions: DEFINITIONS
58
+ definitions: DEFINITIONS,
59
+ _plugin: true
59
60
  }
60
61
 
61
62
  schema[:definitions]['config'][:properties] = Bolt::Config.transport_definitions
@@ -96,7 +97,7 @@ module Bolt
96
97
 
97
98
  Bolt::Validator.new.tap do |validator|
98
99
  validator.validate(data, schema, source)
99
- validator.warnings.each { |warning| logger.warn(warning) }
100
+ validator.warnings.each { |warning| Bolt::Logger.warn(warning[:id], warning[:msg]) }
100
101
  end
101
102
 
102
103
  inventory = create_version(data, config.transport, config.transports, plugins)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bolt/config/options'
3
4
  require 'bolt/inventory/group'
4
5
  require 'bolt/inventory/inventory'
5
6
  require 'bolt/inventory/target'
@@ -18,12 +19,23 @@ module Bolt
18
19
  GROUP_KEYS = DATA_KEYS + %w[name groups targets]
19
20
  CONFIG_KEYS = Bolt::Config::INVENTORY_OPTIONS.keys
20
21
 
21
- def initialize(input, plugins)
22
+ def initialize(input, plugins, all_group: false)
22
23
  @logger = Bolt::Logger.logger(self)
23
24
  @plugins = plugins
24
25
 
25
26
  input = @plugins.resolve_top_level_references(input) if @plugins.reference?(input)
26
27
 
28
+ if all_group
29
+ if input.key?('name') && input['name'] != 'all'
30
+ Bolt::Logger.warn(
31
+ "top_level_group_name",
32
+ "Top-level group '#{input['name']}' cannot specify a name, using 'all' instead."
33
+ )
34
+ end
35
+
36
+ input = input.merge('name' => 'all')
37
+ end
38
+
27
39
  raise ValidationError.new("Group does not have a name", nil) unless input.key?('name')
28
40
 
29
41
  @name = @plugins.resolve_references(input['name'])
@@ -125,7 +137,7 @@ module Bolt
125
137
 
126
138
  unless (unexpected_keys = target.keys - TARGET_KEYS).empty?
127
139
  msg = "Found unexpected key(s) #{unexpected_keys.join(', ')} in target #{t_name}"
128
- @logger.warn(msg)
140
+ Bolt::Logger.warn("unknown_target_keys", msg)
129
141
  end
130
142
 
131
143
  validate_data_keys(target, t_name)
@@ -252,7 +264,7 @@ module Bolt
252
264
 
253
265
  unless (unexpected_keys = input.keys - GROUP_KEYS).empty?
254
266
  msg = "Found unexpected key(s) #{unexpected_keys.join(', ')} in group #{@name}"
255
- @logger.warn(msg)
267
+ Bolt::Logger.warn("unknown_group_keys", msg)
256
268
  end
257
269
  end
258
270
 
@@ -315,7 +327,26 @@ module Bolt
315
327
  'features' => @plugins.resolve_references(data.fetch('features', [])),
316
328
  'plugin_hooks' => @plugins.resolve_references(data.fetch('plugin_hooks', {}))
317
329
  }
330
+
318
331
  validate_data_keys(result, target)
332
+
333
+ Bolt::Config::Options::TRANSPORT_CONFIG.each_key do |transport|
334
+ next unless result['config'].key?(transport)
335
+ transport_config = result['config'][transport]
336
+ next unless transport_config.is_a?(Hash)
337
+ transport_config = Bolt::Util.postwalk_vals(transport_config) do |val|
338
+ if val.is_a?(Hash)
339
+ val = val.compact
340
+ val = nil if val.empty?
341
+ end
342
+ val
343
+ end
344
+ # the transport config is user-specified data so we
345
+ # still want to preserve it even if it exclusively
346
+ # contains nil-resolved keys
347
+ result['config'][transport] = transport_config || {}
348
+ end
349
+
319
350
  result['features'] = Set.new(result['features'].flatten)
320
351
  result
321
352
  end
@@ -340,7 +371,7 @@ module Bolt
340
371
  msg = +"Found unexpected key(s) #{unexpected_keys.join(', ')} in config for"
341
372
  msg << " target #{target} in" if target
342
373
  msg << " group #{@name}"
343
- @logger.warn(msg)
374
+ Bolt::Logger.warn("unknown_config_keys", msg)
344
375
  end
345
376
  end
346
377
  end