bolt 2.32.0 → 2.36.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.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/Puppetfile +6 -6
  3. data/bolt-modules/boltlib/lib/puppet/datatypes/applyresult.rb +1 -0
  4. data/bolt-modules/boltlib/lib/puppet/functions/catch_errors.rb +1 -3
  5. data/bolt-modules/boltlib/lib/puppet/functions/download_file.rb +17 -6
  6. data/bolt-modules/boltlib/lib/puppet/functions/facts.rb +6 -0
  7. data/bolt-modules/boltlib/lib/puppet/functions/parallelize.rb +56 -0
  8. data/bolt-modules/boltlib/lib/puppet/functions/puppetdb_query.rb +2 -2
  9. data/bolt-modules/boltlib/lib/puppet/functions/run_command.rb +24 -6
  10. data/bolt-modules/boltlib/lib/puppet/functions/run_script.rb +27 -8
  11. data/bolt-modules/boltlib/lib/puppet/functions/run_task.rb +21 -1
  12. data/bolt-modules/boltlib/lib/puppet/functions/run_task_with.rb +18 -1
  13. data/bolt-modules/boltlib/lib/puppet/functions/upload_file.rb +24 -6
  14. data/guides/logging.txt +18 -0
  15. data/lib/bolt/analytics.rb +27 -8
  16. data/lib/bolt/apply_result.rb +3 -3
  17. data/lib/bolt/bolt_option_parser.rb +43 -15
  18. data/lib/bolt/cli.rb +79 -227
  19. data/lib/bolt/config.rb +131 -52
  20. data/lib/bolt/config/options.rb +46 -8
  21. data/lib/bolt/config/transport/base.rb +10 -19
  22. data/lib/bolt/config/transport/local.rb +0 -7
  23. data/lib/bolt/config/transport/options.rb +1 -1
  24. data/lib/bolt/config/transport/ssh.rb +8 -14
  25. data/lib/bolt/config/validator.rb +231 -0
  26. data/lib/bolt/error.rb +37 -3
  27. data/lib/bolt/executor.rb +103 -17
  28. data/lib/bolt/inventory/group.rb +2 -1
  29. data/lib/bolt/module_installer.rb +2 -1
  30. data/lib/bolt/module_installer/specs/forge_spec.rb +5 -4
  31. data/lib/bolt/module_installer/specs/git_spec.rb +4 -3
  32. data/lib/bolt/outputter/human.rb +21 -9
  33. data/lib/bolt/outputter/rainbow.rb +1 -1
  34. data/lib/bolt/pal.rb +48 -30
  35. data/lib/bolt/pal/yaml_plan.rb +11 -2
  36. data/lib/bolt/pal/yaml_plan/evaluator.rb +23 -1
  37. data/lib/bolt/pal/yaml_plan/loader.rb +14 -9
  38. data/lib/bolt/plan_creator.rb +160 -0
  39. data/lib/bolt/plugin.rb +1 -8
  40. data/lib/bolt/project.rb +30 -36
  41. data/lib/bolt/project_manager.rb +199 -0
  42. data/lib/bolt/{project_migrator/config.rb → project_manager/config_migrator.rb} +43 -5
  43. data/lib/bolt/{project_migrator/inventory.rb → project_manager/inventory_migrator.rb} +5 -5
  44. data/lib/bolt/{project_migrator/base.rb → project_manager/migrator.rb} +2 -2
  45. data/lib/bolt/{project_migrator/modules.rb → project_manager/module_migrator.rb} +3 -3
  46. data/lib/bolt/puppetdb/client.rb +3 -2
  47. data/lib/bolt/puppetdb/config.rb +9 -8
  48. data/lib/bolt/result.rb +23 -11
  49. data/lib/bolt/shell/bash.rb +12 -7
  50. data/lib/bolt/shell/powershell.rb +12 -7
  51. data/lib/bolt/task/run.rb +1 -1
  52. data/lib/bolt/transport/base.rb +18 -18
  53. data/lib/bolt/transport/docker.rb +23 -6
  54. data/lib/bolt/transport/orch.rb +23 -19
  55. data/lib/bolt/transport/orch/connection.rb +10 -3
  56. data/lib/bolt/transport/remote.rb +3 -3
  57. data/lib/bolt/transport/simple.rb +6 -6
  58. data/lib/bolt/transport/ssh/exec_connection.rb +6 -2
  59. data/lib/bolt/util.rb +19 -7
  60. data/lib/bolt/version.rb +1 -1
  61. data/lib/bolt/yarn.rb +23 -0
  62. data/lib/bolt_server/base_config.rb +3 -1
  63. data/lib/bolt_server/config.rb +3 -1
  64. data/lib/bolt_server/file_cache.rb +2 -0
  65. data/lib/bolt_server/schemas/partials/task.json +2 -2
  66. data/lib/bolt_server/transport_app.rb +42 -11
  67. data/lib/bolt_spec/plans/action_stubs/command_stub.rb +1 -1
  68. data/lib/bolt_spec/plans/action_stubs/script_stub.rb +1 -1
  69. data/lib/bolt_spec/plans/mock_executor.rb +9 -6
  70. data/libexec/apply_catalog.rb +1 -1
  71. data/libexec/custom_facts.rb +1 -1
  72. data/libexec/query_resources.rb +1 -1
  73. metadata +12 -14
  74. data/lib/bolt/project_migrator.rb +0 -80
  75. data/modules/secure_env_vars/plans/init.pp +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b010e9146d3269d88005be58db6b788f57ea3046f96f28756641b0c7266eec2
4
- data.tar.gz: ce8d15031143acabc664a7025ef004c69211c25316f9691783388ba74e61dec9
3
+ metadata.gz: 1881e4097a89e606b9326f93e2e6fd9d934a7db1eb8609e6f9a09ffa322ac7c4
4
+ data.tar.gz: '02509b1919e57f137bf4e868332be3b73238d22d83251680dc29c7c93ef90a19'
5
5
  SHA512:
6
- metadata.gz: b45657eb2b985f8e97c59ff4603ad049fd17ee6585292463a57bde3b5c7ca55451883b5e88cb0f61e55c05f1d5415cbde3874320ae446124d646a3d3e8ffa812
7
- data.tar.gz: 673e3f3310bf4f22602153bf8300851fa3a832db8e73abc9352874bea7c0b1fd50a5baa42d18474885caea7ec9fad4aa50c25f44aa27974097e10ea03b31e07e
6
+ metadata.gz: 1fc1215430ac99b765c24c87ee210afb03a247a6c0baac9af3b00e34d56cfb58bacb2140dcfafbe197fd655602713463e2697c2df5083c259b66c8d8cd7bc112
7
+ data.tar.gz: 445a5f77a5beaf8a1a3c4cb2193e973ada23cb4a7a5f3a8caba2ccc47be4fc8a8fdef3ba797e082c0df3b9553c2f2e67c06084f2c2b2684347d2b9a86e45bde0
data/Puppetfile CHANGED
@@ -6,16 +6,16 @@ moduledir File.join(File.dirname(__FILE__), 'modules')
6
6
 
7
7
  # Core modules used by 'apply'
8
8
  mod 'puppetlabs-service', '1.3.0'
9
- mod 'puppetlabs-puppet_agent', '4.1.1'
10
- mod 'puppetlabs-facts', '1.1.0'
9
+ mod 'puppetlabs-puppet_agent', '4.2.0'
10
+ mod 'puppetlabs-facts', '1.2.0'
11
11
 
12
12
  # Core types and providers for Puppet 6
13
13
  mod 'puppetlabs-augeas_core', '1.1.1'
14
14
  mod 'puppetlabs-host_core', '1.0.3'
15
15
  mod 'puppetlabs-scheduled_task', '2.2.1'
16
- mod 'puppetlabs-sshkeys_core', '2.1.0'
17
- mod 'puppetlabs-zfs_core', '1.1.0'
18
- mod 'puppetlabs-cron_core', '1.0.4'
16
+ mod 'puppetlabs-sshkeys_core', '2.2.0'
17
+ mod 'puppetlabs-zfs_core', '1.2.0'
18
+ mod 'puppetlabs-cron_core', '1.0.5'
19
19
  mod 'puppetlabs-mount_core', '1.0.4'
20
20
  mod 'puppetlabs-selinux_core', '1.0.4'
21
21
  mod 'puppetlabs-yumrepo_core', '1.0.7'
@@ -36,6 +36,7 @@ mod 'puppetlabs-azure_inventory', '0.4.1'
36
36
  mod 'puppetlabs-gcloud_inventory', '0.1.3'
37
37
  mod 'puppetlabs-http_request', '0.2.0'
38
38
  mod 'puppetlabs-pkcs7', '0.1.1'
39
+ mod 'puppetlabs-secure_env_vars', '0.1.0'
39
40
  mod 'puppetlabs-terraform', '0.5.0'
40
41
  mod 'puppetlabs-vault', '0.3.0'
41
42
  mod 'puppetlabs-yaml', '0.2.0'
@@ -44,4 +45,3 @@ mod 'puppetlabs-yaml', '0.2.0'
44
45
  mod 'canary', local: true
45
46
  mod 'aggregate', local: true
46
47
  mod 'puppetdb_fact', local: true
47
- mod 'secure_env_vars', local: true
@@ -12,6 +12,7 @@ Puppet::DataTypes.create_type('ApplyResult') do
12
12
  message => Callable[[], Optional[String]],
13
13
  action => Callable[[], String],
14
14
  to_data => Callable[[], Hash],
15
+ value => Callable[[], Hash]
15
16
  }
16
17
  PUPPET
17
18
 
@@ -44,9 +44,7 @@ Puppet::Functions.create_function(:catch_errors) do
44
44
  yield
45
45
  rescue Puppet::PreformattedError => e
46
46
  if e.cause.is_a?(Bolt::Error)
47
- if error_types.nil?
48
- e.cause.to_puppet_error
49
- elsif error_types.include?(e.cause.to_h['kind'])
47
+ if error_types.nil? || error_types.include?(e.cause.to_h['kind'])
50
48
  e.cause.to_puppet_error
51
49
  else
52
50
  raise e
@@ -110,14 +110,25 @@ Puppet::Functions.create_function(:download_file, Puppet::Functions::InternalFun
110
110
  targets = inventory.get_targets(targets)
111
111
  if targets.empty?
112
112
  call_function('debug', "Simulating file download of '#{source}' - no targets given - no action taken")
113
- r = Bolt::ResultSet.new([])
113
+ Bolt::ResultSet.new([])
114
114
  else
115
- r = executor.download_file(targets, source, destination, options)
116
- end
115
+ r = if executor.in_parallel
116
+ require 'concurrent'
117
+ require 'fiber'
118
+ future = Concurrent::Future.execute do
119
+ executor.download_file(targets, source, destination, options, Puppet::Pops::PuppetStack.top_of_stack)
120
+ end
121
+
122
+ Fiber.yield('unfinished') while future.incomplete?
123
+ future.value || future.reason
124
+ else
125
+ executor.download_file(targets, source, destination, options, Puppet::Pops::PuppetStack.top_of_stack)
126
+ end
117
127
 
118
- if !r.ok && !options[:catch_errors]
119
- raise Bolt::RunFailure.new(r, 'download_file', source)
128
+ if !r.ok && !options[:catch_errors]
129
+ raise Bolt::RunFailure.new(r, 'download_file', source)
130
+ end
131
+ r
120
132
  end
121
- r
122
133
  end
123
134
  end
@@ -3,6 +3,12 @@
3
3
  require 'bolt/error'
4
4
 
5
5
  # Returns the facts hash for a target.
6
+ #
7
+ # Using the `facts` function does not automatically collect facts for a target,
8
+ # and will only return facts that are currently set in the inventory. To collect
9
+ # facts from a target and set them in the inventory, run the
10
+ # [facts](writing_plans.md#collect-facts-from-targets) plan or
11
+ # [puppetdb_fact](writing_plans.md#collect-facts-from-puppetdb) plan.
6
12
  Puppet::Functions.create_function(:facts) do
7
13
  # @param target A target.
8
14
  # @return The target's facts.
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bolt/yarn'
4
+
5
+ # Map a code block onto an array, where each array element executes in parallel.
6
+ # This function is experimental.
7
+ #
8
+ # > **Note:** Not available in apply block.
9
+ Puppet::Functions.create_function(:parallelize, Puppet::Functions::InternalFunction) do
10
+ # Map a block onto an array, where each array element executes in parallel.
11
+ # This function is experimental.
12
+ # @param data The array to apply the block to.
13
+ # @return [Array] An array of PlanResult objects. Each input from the input
14
+ # array returns a corresponding PlanResult object.
15
+ # @example Execute two tasks on multiple targets. Once the task finishes on one
16
+ # target, that target can move to the next step without waiting for the task
17
+ # to finish on the second target.
18
+ # $targets = get_targets(["host1", "host2"])
19
+ # $result = parallelize ($targets) |$t| {
20
+ # run_task('a', $t)
21
+ # run_task('b', $t)
22
+ # }
23
+ dispatch :parallelize do
24
+ scope_param
25
+ param 'Array[Any]', :data
26
+ block_param 'Callable[Any]', :block
27
+ return_type 'Array[Boltlib::PlanResult]'
28
+ end
29
+
30
+ def parallelize(scope, data, &block)
31
+ unless Puppet[:tasks]
32
+ raise Puppet::ParseErrorWithIssue
33
+ .from_issue_and_stack(Bolt::PAL::Issues::PLAN_OPERATION_NOT_SUPPORTED_WHEN_COMPILING, action: 'parallelize')
34
+ end
35
+
36
+ executor = Puppet.lookup(:bolt_executor)
37
+ executor.report_function_call(self.class.name)
38
+
39
+ skein = data.each_with_index.map do |object, index|
40
+ executor.create_yarn(scope, block, object, index)
41
+ end
42
+
43
+ result = executor.round_robin(skein)
44
+
45
+ failed_indices = result.each_index.select do |i|
46
+ result[i].is_a?(Bolt::Error)
47
+ end
48
+
49
+ # TODO: Inner catch errors block?
50
+ if failed_indices.any?
51
+ raise Bolt::ParallelFailure.new(result, failed_indices)
52
+ end
53
+
54
+ result
55
+ end
56
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  require 'bolt/error'
4
4
 
5
- # Makes a query to {https://puppet.com/docs/puppetdb/latest/index.html puppetdb}
5
+ # Makes a query to [puppetdb](https://puppet.com/docs/puppetdb/latest/index.html)
6
6
  # using Bolt's PuppetDB client.
7
7
  Puppet::Functions.create_function(:puppetdb_query) do
8
8
  # rubocop:disable Layout/LineLength
9
9
  # @param query A PQL query.
10
- # {https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html Learn more about Puppet's query language, PQL}
10
+ # Learn more about [Puppet's query language](https://puppet.com/docs/puppetdb/latest/api/query/tutorial-pql.html), PQL.
11
11
  # @return Results of the PuppetDB query.
12
12
  # @example Request certnames for all nodes
13
13
  # puppetdb_query('nodes[certname] {}')
@@ -67,14 +67,32 @@ Puppet::Functions.create_function(:run_command) do
67
67
 
68
68
  if targets.empty?
69
69
  call_function('debug', "Simulating run_command('#{command}') - no targets given - no action taken")
70
- r = Bolt::ResultSet.new([])
70
+ Bolt::ResultSet.new([])
71
71
  else
72
- r = executor.run_command(targets, command, options)
73
- end
72
+ r = if executor.in_parallel
73
+ require 'concurrent'
74
+ require 'fiber'
75
+ future = Concurrent::Future.execute do
76
+ executor.run_command(targets,
77
+ command,
78
+ options,
79
+ Puppet::Pops::PuppetStack.top_of_stack)
80
+ end
81
+
82
+ Fiber.yield('unfinished') while future.incomplete?
83
+ future.value || future.reason
84
+ else
85
+ executor.run_command(targets,
86
+ command,
87
+ options,
88
+ Puppet::Pops::PuppetStack.top_of_stack)
89
+ end
90
+
91
+ if !r.ok && !options[:catch_errors]
92
+ raise Bolt::RunFailure.new(r, 'run_command', command)
93
+ end
74
94
 
75
- if !r.ok && !options[:catch_errors]
76
- raise Bolt::RunFailure.new(r, 'run_command', command)
95
+ r
77
96
  end
78
- r
79
97
  end
80
98
  end
@@ -84,15 +84,34 @@ Puppet::Functions.create_function(:run_script, Puppet::Functions::InternalFuncti
84
84
  # Ensure that given targets are all Target instances)
85
85
  targets = inventory.get_targets(targets)
86
86
 
87
- r = if targets.empty?
88
- Bolt::ResultSet.new([])
89
- else
90
- executor.run_script(targets, found, arguments, options)
91
- end
87
+ if targets.empty?
88
+ Bolt::ResultSet.new([])
89
+ else
90
+ r = if executor.in_parallel
91
+ require 'concurrent'
92
+ require 'fiber'
93
+ future = Concurrent::Future.execute do
94
+ executor.run_script(targets,
95
+ found,
96
+ arguments,
97
+ options,
98
+ Puppet::Pops::PuppetStack.top_of_stack)
99
+ end
92
100
 
93
- if !r.ok && !options[:catch_errors]
94
- raise Bolt::RunFailure.new(r, 'run_script', script)
101
+ Fiber.yield('unfinished') while future.incomplete?
102
+ future.value || future.reason
103
+ else
104
+ executor.run_script(targets,
105
+ found,
106
+ arguments,
107
+ options,
108
+ Puppet::Pops::PuppetStack.top_of_stack)
109
+ end
110
+
111
+ if !r.ok && !options[:catch_errors]
112
+ raise Bolt::RunFailure.new(r, 'run_script', script)
113
+ end
114
+ r
95
115
  end
96
- r
97
116
  end
98
117
  end
@@ -133,7 +133,27 @@ Puppet::Functions.create_function(:run_task) do
133
133
  if targets.empty?
134
134
  Bolt::ResultSet.new([])
135
135
  else
136
- result = executor.run_task(targets, task, params, options)
136
+ result = if executor.in_parallel
137
+ require 'concurrent'
138
+ require 'fiber'
139
+ future = Concurrent::Future.execute do
140
+ executor.run_task(targets,
141
+ task,
142
+ params,
143
+ options,
144
+ Puppet::Pops::PuppetStack.top_of_stack)
145
+ end
146
+
147
+ Fiber.yield('unfinished') while future.incomplete?
148
+ future.value || future.reason
149
+ else
150
+ executor.run_task(targets,
151
+ task,
152
+ params,
153
+ options,
154
+ Puppet::Pops::PuppetStack.top_of_stack)
155
+ end
156
+
137
157
  if !result.ok && !options[:catch_errors]
138
158
  raise Bolt::RunFailure.new(result, 'run_task', task_name)
139
159
  end
@@ -180,7 +180,24 @@ Puppet::Functions.create_function(:run_task_with) do
180
180
  else
181
181
  # Combine the results from the task run with any failing results that were
182
182
  # generated earlier when creating the target mapping
183
- task_result = executor.run_task_with(target_mapping, task, options)
183
+ task_result = if executor.in_parallel
184
+ require 'concurrent'
185
+ require 'fiber'
186
+ future = Concurrent::Future.execute do
187
+ executor.run_task_with(target_mapping,
188
+ task,
189
+ options,
190
+ Puppet::Pops::PuppetStack.top_of_stack)
191
+ end
192
+
193
+ Fiber.yield('unfinished') while future.incomplete?
194
+ future.value || future.reason
195
+ else
196
+ executor.run_task_with(target_mapping,
197
+ task,
198
+ options,
199
+ Puppet::Pops::PuppetStack.top_of_stack)
200
+ end
184
201
  result = Bolt::ResultSet.new(task_result.results + error_set)
185
202
 
186
203
  if !result.ok && !options[:catch_errors]
@@ -81,14 +81,32 @@ Puppet::Functions.create_function(:upload_file, Puppet::Functions::InternalFunct
81
81
  targets = inventory.get_targets(targets)
82
82
  if targets.empty?
83
83
  call_function('debug', "Simulating file upload of '#{found}' - no targets given - no action taken")
84
- r = Bolt::ResultSet.new([])
84
+ Bolt::ResultSet.new([])
85
85
  else
86
- r = executor.upload_file(targets, found, destination, options)
87
- end
86
+ r = if executor.in_parallel
87
+ require 'concurrent'
88
+ require 'fiber'
89
+ future = Concurrent::Future.execute do
90
+ executor.upload_file(targets,
91
+ found,
92
+ destination,
93
+ options,
94
+ Puppet::Pops::PuppetStack.top_of_stack)
95
+ end
88
96
 
89
- if !r.ok && !options[:catch_errors]
90
- raise Bolt::RunFailure.new(r, 'upload_file', source)
97
+ Fiber.yield('unfinished') while future.incomplete?
98
+ future.value || future.reason
99
+ else
100
+ executor.upload_file(targets,
101
+ found,
102
+ destination,
103
+ options,
104
+ Puppet::Pops::PuppetStack.top_of_stack)
105
+ end
106
+ if !r.ok && !options[:catch_errors]
107
+ raise Bolt::RunFailure.new(r, 'upload_file', source)
108
+ end
109
+ r
91
110
  end
92
- r
93
111
  end
94
112
  end
@@ -0,0 +1,18 @@
1
+ TOPIC
2
+ logging
3
+
4
+ DESCRIPTION
5
+ Bolt prints messages both to the console and to log files. Messages can
6
+ either come from Bolt's 'outputter', which logs user-facing messages like
7
+ progress and results, or from the 'logger', which logs warnings, errors, and
8
+ log-structured output to log files. Both of these message streams are
9
+ configurable.
10
+
11
+ By default, Bolt logs to the console at 'warn' level and writes a log file to
12
+ '<project>/bolt-debug.log' at 'debug' level. Unless you are running a plan,
13
+ Bolt runs in verbose mode by default.
14
+
15
+ To learn more about projects, see the 'project' guide.
16
+
17
+ DOCUMENTATION
18
+ https://pup.pt/bolt-logging
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'bolt/util'
4
4
  require 'bolt/version'
5
+ require 'find'
5
6
  require 'json'
6
7
  require 'logging'
7
8
  require 'securerandom'
@@ -23,14 +24,16 @@ module Bolt
23
24
  plan_steps: :cd8,
24
25
  return_type: :cd9,
25
26
  inventory_version: :cd10,
26
- boltdir_type: :cd11
27
+ boltdir_type: :cd11,
28
+ puppet_plan_count: :cd12,
29
+ yaml_plan_count: :cd13
27
30
  }.freeze
28
31
 
29
32
  def self.build_client
30
33
  logger = Bolt::Logger.logger(self)
31
34
  begin
32
- config_file = config_path(logger)
33
- config = load_config(config_file, logger)
35
+ config_file = config_path
36
+ config = load_config(config_file)
34
37
  rescue ArgumentError
35
38
  config = { 'disabled' => true }
36
39
  end
@@ -51,7 +54,7 @@ module Bolt
51
54
  NoopClient.new
52
55
  end
53
56
 
54
- def self.config_path(logger)
57
+ def self.config_path
55
58
  path = File.expand_path(File.join('~', '.puppetlabs', 'etc', 'bolt', 'analytics.yaml'))
56
59
  old_path = File.expand_path(File.join('~', '.puppetlabs', 'bolt', 'analytics.yaml'))
57
60
 
@@ -59,7 +62,7 @@ module Bolt
59
62
  if File.exist?(old_path)
60
63
  message = "Detected analytics configuration files at '#{old_path}' and '#{path}'. Loading "\
61
64
  "analytics configuration from '#{path}'."
62
- logger.warn(message)
65
+ Bolt::Logger.warn_once('duplicate_analytics', message)
63
66
  end
64
67
 
65
68
  path
@@ -70,12 +73,12 @@ module Bolt
70
73
  end
71
74
  end
72
75
 
73
- def self.load_config(filename, logger)
76
+ def self.load_config(filename)
74
77
  if File.exist?(filename)
75
78
  Bolt::Util.read_optional_yaml_hash(filename, 'analytics')
76
79
  else
77
80
  unless ENV['BOLT_DISABLE_ANALYTICS']
78
- logger.warn <<~ANALYTICS
81
+ Bolt::Logger.warn_once('analytics_opt_out', <<~ANALYTICS)
79
82
  Bolt collects data about how you use it. You can opt out of providing this data.
80
83
 
81
84
  To disable analytics data collection, add this line to ~/.puppetlabs/etc/bolt/analytics.yaml :
@@ -134,11 +137,23 @@ module Bolt
134
137
  end
135
138
 
136
139
  def report_bundled_content(mode, name)
137
- if bundled_content[mode.split(' ').first]&.include?(name)
140
+ if bundled_content[mode.split.first]&.include?(name)
138
141
  event('Bundled Content', mode, label: name)
139
142
  end
140
143
  end
141
144
 
145
+ def plan_counts(plans_path)
146
+ pp_count, yaml_count = if File.exist?(plans_path)
147
+ %w[pp yaml].map do |extension|
148
+ Find.find(plans_path.to_s).grep(/.*\.#{extension}/).length
149
+ end
150
+ else
151
+ [0, 0]
152
+ end
153
+
154
+ { puppet_plan_count: pp_count, yaml_plan_count: yaml_count }
155
+ end
156
+
142
157
  def event(category, action, label: nil, value: nil, **kwargs)
143
158
  custom_dimensions = Bolt::Util.walk_keys(kwargs) do |k|
144
159
  CUSTOM_DIMENSIONS[k] || raise("Unknown analytics key '#{k}'")
@@ -224,6 +239,10 @@ module Bolt
224
239
 
225
240
  def report_bundled_content(mode, name); end
226
241
 
242
+ def plan_counts(_)
243
+ {}
244
+ end
245
+
227
246
  def event(category, action, **_kwargs)
228
247
  @logger.trace "Skipping submission of '#{category} #{action}' event because analytics is disabled"
229
248
  end