pdk 3.0.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -1
  3. data/lib/pdk/cli/build.rb +0 -2
  4. data/lib/pdk/cli/bundle.rb +0 -2
  5. data/lib/pdk/cli/console.rb +0 -2
  6. data/lib/pdk/cli/convert.rb +3 -3
  7. data/lib/pdk/cli/env.rb +0 -2
  8. data/lib/pdk/cli/new/class.rb +0 -2
  9. data/lib/pdk/cli/new/defined_type.rb +0 -2
  10. data/lib/pdk/cli/new/fact.rb +0 -2
  11. data/lib/pdk/cli/new/function.rb +0 -2
  12. data/lib/pdk/cli/new/module.rb +0 -2
  13. data/lib/pdk/cli/new/provider.rb +0 -2
  14. data/lib/pdk/cli/new/task.rb +0 -2
  15. data/lib/pdk/cli/new/test.rb +0 -2
  16. data/lib/pdk/cli/release/prep.rb +0 -2
  17. data/lib/pdk/cli/release/publish.rb +0 -2
  18. data/lib/pdk/cli/release.rb +0 -8
  19. data/lib/pdk/cli/test/unit.rb +0 -2
  20. data/lib/pdk/cli/update.rb +3 -3
  21. data/lib/pdk/cli/util.rb +0 -38
  22. data/lib/pdk/cli/validate.rb +0 -7
  23. data/lib/pdk/cli.rb +0 -2
  24. data/lib/pdk/config/namespace.rb +3 -3
  25. data/lib/pdk/config/setting.rb +3 -3
  26. data/lib/pdk/config.rb +0 -80
  27. data/lib/pdk/module/convert.rb +7 -2
  28. data/lib/pdk/module/metadata.rb +1 -1
  29. data/lib/pdk/module/update_manager.rb +29 -3
  30. data/lib/pdk/report/event.rb +1 -1
  31. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +10 -13
  32. data/lib/pdk/template/renderer/v1/renderer.rb +3 -1
  33. data/lib/pdk/template.rb +0 -3
  34. data/lib/pdk/util/filesystem.rb +10 -0
  35. data/lib/pdk/version.rb +2 -2
  36. data/lib/pdk.rb +0 -14
  37. metadata +2 -49
  38. data/lib/pdk/analytics/client/google_analytics.rb +0 -141
  39. data/lib/pdk/analytics/client/noop.rb +0 -25
  40. data/lib/pdk/analytics/util.rb +0 -18
  41. data/lib/pdk/analytics.rb +0 -30
  42. data/lib/pdk/config/analytics_schema.json +0 -26
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c39902d0ebbac37358fd3fccf5de760b47f77860054b08864ccdae63150b7597
4
- data.tar.gz: 6a4d8beb3013edf1ed946b9cf94cd90b055ad63500102e131734600c81c3a5a5
3
+ metadata.gz: 61c49c154cc69ce1e3c47ddfdd089b42c9c4c5e610bfb2e6caf3256939a16d5d
4
+ data.tar.gz: 420c70b35bfaf64077b990f6853bfc92062659fc7ba36379cb053232b99313a5
5
5
  SHA512:
6
- metadata.gz: 7af78ce8b0c4bb9122081a2c6449d862da04c9fec85d428b2e8ace3e88a74930fcf809462062b07994307c54c3ee5a827a83ae26e5c67b95f659c3f5c0cb89b5
7
- data.tar.gz: c5af71c375d94c9e22f4c7ae284213a39aaa87b8bc21980580ce4e79743979d4cbb967f330c775dcd2ebc4d3046c4c9c5080480172e07dec33afd9546b94da7e
6
+ metadata.gz: 3e2e8f1e63a936c310459a67a14b632e00a4ac1694fa4cc77f2849b3d19bf09cc9a5e4a19d7ce3e3a0eb6493a31141c76a72bc98d30cbb4eb7ffd1f5d3da7ca0
7
+ data.tar.gz: fe219a60e2cf9f7263e1b8fd8e721f143349aa3f03125649e551f9978ae3a9012c4b051f21b2707a266ed31a67772ad6c3cef026f1c5a1a0dadaf8257dc888dc
data/CHANGELOG.md CHANGED
@@ -5,7 +5,29 @@ All notable changes to this project will be documented in this file.
5
5
 
6
6
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org).
7
7
 
8
- ## [v3.0.1](https://github.com/puppetlabs/pdk/tree/v3.0.1) - 2023-12-07
8
+ ## [v3.2.0](https://github.com/puppetlabs/pdk/tree/v3.2.0) - 2024-05-02
9
+
10
+ [Full Changelog](https://github.com/puppetlabs/pdk/compare/v3.1.0...v3.2.0)
11
+
12
+ ### Fixed
13
+
14
+ - (CAT-1807) Remove analytics from the PDK [#1339](https://github.com/puppetlabs/pdk/pull/1339) ([david22swan](https://github.com/david22swan))
15
+
16
+ ## [v3.1.0](https://github.com/puppetlabs/pdk/tree/v3.1.0) - 2024-04-11
17
+
18
+ [Full Changelog](https://github.com/puppetlabs/pdk/compare/v3.0.1...v3.1.0)
19
+
20
+ ### Added
21
+
22
+ - Allow `pdk convert` and `pdk update` to work in a ControlRepo context [#1310](https://github.com/puppetlabs/pdk/pull/1310) ([garrettrowell](https://github.com/garrettrowell))
23
+ - Support executable templates [#1289](https://github.com/puppetlabs/pdk/pull/1289) ([nabertrand](https://github.com/nabertrand))
24
+
25
+ ### Fixed
26
+
27
+ - (CAT-1796) Fix missing locale gem [#1337](https://github.com/puppetlabs/pdk/pull/1337) ([LukasAud](https://github.com/LukasAud))
28
+ - (CAT-1703) Convert concurrent-ruby from a pin to a pessimistic constraint [#1312](https://github.com/puppetlabs/pdk/pull/1312) ([david22swan](https://github.com/david22swan))
29
+
30
+ ## [v3.0.1](https://github.com/puppetlabs/pdk/tree/v3.0.1) - 2023-12-13
9
31
 
10
32
  [Full Changelog](https://github.com/puppetlabs/pdk/compare/v3.0.0...v3.0.1)
11
33
 
data/lib/pdk/cli/build.rb CHANGED
@@ -22,8 +22,6 @@ module PDK
22
22
  log_level: :info
23
23
  )
24
24
 
25
- PDK::CLI::Util.analytics_screen_view('build', opts)
26
-
27
25
  module_metadata = PDK::Module::Metadata.from_file('metadata.json')
28
26
 
29
27
  # TODO: Ensure forge metadata has been set, or call out to interview
@@ -23,8 +23,6 @@ module PDK
23
23
  screen_view_name << args[0] if args.size >= 1
24
24
  screen_view_name << args[1] if args.size >= 2 && args[0] == 'exec'
25
25
 
26
- PDK::CLI::Util.analytics_screen_view(screen_view_name.join('_'))
27
-
28
26
  # Ensure that the correct Ruby is activated before running command.
29
27
  puppet_env = PDK::CLI::Util.puppet_from_opts_or_env({})
30
28
  PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
@@ -34,8 +34,6 @@ module PDK
34
34
 
35
35
  PDK::CLI::Util.validate_puppet_version_opts(processed_options)
36
36
 
37
- PDK::CLI::Util.analytics_screen_view('console', args)
38
-
39
37
  # TODO: figure out if we need to remove default configs set by puppet
40
38
  # so it is scoped for the module only
41
39
  # "--environmentpath"...
@@ -18,7 +18,9 @@ module PDK
18
18
  # Write the context information to the debug log
19
19
  PDK.context.to_debug_log
20
20
 
21
- raise PDK::CLI::ExitWithError, '`pdk convert` can only be run from inside a valid module directory.' unless PDK.context.is_a?(PDK::Context::Module)
21
+ unless PDK.context.is_a?(PDK::Context::Module) || PDK.context.is_a?(PDK::Context::ControlRepo)
22
+ raise PDK::CLI::ExitWithError, '`pdk convert` can only be run from inside a valid module directory.'
23
+ end
22
24
 
23
25
  raise PDK::CLI::ExitWithError, 'You can not specify --noop and --force when converting a module' if opts[:noop] && opts[:force]
24
26
 
@@ -31,8 +33,6 @@ module PDK
31
33
 
32
34
  PDK::CLI::Util.validate_template_opts(opts)
33
35
 
34
- PDK::CLI::Util.analytics_screen_view('convert', opts)
35
-
36
36
  if opts[:'skip-interview'] && opts[:'full-interview']
37
37
  PDK.logger.info 'Ignoring --full-interview and continuing with --skip-interview.'
38
38
  opts[:'full-interview'] = false
data/lib/pdk/cli/env.rb CHANGED
@@ -17,8 +17,6 @@ module PDK
17
17
 
18
18
  PDK::CLI::Util.validate_puppet_version_opts(opts)
19
19
 
20
- PDK::CLI::Util.analytics_screen_view('env')
21
-
22
20
  # Ensure that the correct Ruby is activated before running command.
23
21
  puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
24
22
  PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
@@ -22,8 +22,6 @@ module PDK
22
22
 
23
23
  raise PDK::CLI::ExitWithError, format("'%{name}' is not a valid class name", name: class_name) unless Util::OptionValidator.valid_class_name?(class_name)
24
24
 
25
- PDK::CLI::Util.analytics_screen_view('new_class', opts)
26
-
27
25
  updates = PDK::Generate::PuppetClass.new(PDK.context, class_name, opts).run
28
26
  PDK::CLI::Util::UpdateManagerPrinter.print_summary(updates, tense: :past)
29
27
  end
@@ -20,8 +20,6 @@ module PDK
20
20
 
21
21
  raise PDK::CLI::ExitWithError, format("'%{name}' is not a valid defined type name", name: defined_type_name) unless Util::OptionValidator.valid_defined_type_name?(defined_type_name)
22
22
 
23
- PDK::CLI::Util.analytics_screen_view('new_defined_type', opts)
24
-
25
23
  require 'pdk/generate/defined_type'
26
24
 
27
25
  updates = PDK::Generate::DefinedType.new(PDK.context, defined_type_name, opts).run
@@ -17,8 +17,6 @@ module PDK
17
17
 
18
18
  raise PDK::CLI::ExitWithError, format("'%{name}' is not a valid fact name", name: fact_name) unless Util::OptionValidator.valid_fact_name?(fact_name)
19
19
 
20
- PDK::CLI::Util.analytics_screen_view('new_fact', opts)
21
-
22
20
  require 'pdk/generate/fact'
23
21
 
24
22
  updates = PDK::Generate::Fact.new(PDK.context, fact_name, opts).run
@@ -18,8 +18,6 @@ module PDK
18
18
 
19
19
  raise PDK::CLI::ExitWithError, format("'%{name}' is not a valid function name", name: function_name) unless Util::OptionValidator.valid_function_name?(function_name)
20
20
 
21
- PDK::CLI::Util.analytics_screen_view('new_function', opts)
22
-
23
21
  require 'pdk/generate/function'
24
22
  updates = PDK::Generate::Function.new(PDK.context, function_name, opts).run
25
23
  PDK::CLI::Util::UpdateManagerPrinter.print_summary(updates, tense: :past)
@@ -22,8 +22,6 @@ module PDK
22
22
 
23
23
  PDK::CLI::Util.validate_template_opts(opts)
24
24
 
25
- PDK::CLI::Util.analytics_screen_view('new_module', opts)
26
-
27
25
  if opts[:'skip-interview'] && opts[:'full-interview']
28
26
  PDK.logger.info 'Ignoring --full-interview and continuing with --skip-interview.'
29
27
  opts[:'full-interview'] = false
@@ -17,8 +17,6 @@ module PDK
17
17
 
18
18
  raise PDK::CLI::ExitWithError, format("'%{name}' is not a valid provider name", name: provider_name) unless Util::OptionValidator.valid_provider_name?(provider_name)
19
19
 
20
- PDK::CLI::Util.analytics_screen_view('new_provider', opts)
21
-
22
20
  require 'pdk/generate/provider'
23
21
 
24
22
  updates = PDK::Generate::Provider.new(PDK.context, provider_name, opts).run
@@ -24,8 +24,6 @@ module PDK
24
24
 
25
25
  raise PDK::CLI::ExitWithError, format("'%{name}' is not a valid task name", name: task_name) unless Util::OptionValidator.valid_task_name?(task_name)
26
26
 
27
- PDK::CLI::Util.analytics_screen_view('new_task', opts)
28
-
29
27
  updates = PDK::Generate::Task.new(PDK.context, task_name, opts).run
30
28
  PDK::CLI::Util::UpdateManagerPrinter.print_summary(updates, tense: :past)
31
29
  end
@@ -39,8 +39,6 @@ module PDK
39
39
  begin
40
40
  generator, obj = PDK::Util::PuppetStrings.find_object(object_name)
41
41
 
42
- PDK::CLI::Util.analytics_screen_view('new_test', opts)
43
-
44
42
  updates = generator.new(PDK.context, obj['name'], opts.merge(spec_only: true)).run
45
43
  PDK::CLI::Util::UpdateManagerPrinter.print_summary(updates, tense: :past)
46
44
  rescue PDK::Util::PuppetStrings::NoObjectError
@@ -28,8 +28,6 @@ module PDK
28
28
 
29
29
  Release.prepare_interview(opts) unless opts[:force]
30
30
 
31
- Release.send_analytics("release #{cmd.name}", opts)
32
-
33
31
  release = PDK::Module::Release.new(nil, opts)
34
32
 
35
33
  Release.module_compatibility_checks!(release, opts)
@@ -37,8 +37,6 @@ module PDK
37
37
 
38
38
  Release.prepare_publish_interview(TTY::Prompt.new(help_color: :cyan), opts) unless opts[:force]
39
39
 
40
- Release.send_analytics("release #{cmd.name}", opts)
41
-
42
40
  release = PDK::Module::Release.new(nil, opts)
43
41
 
44
42
  release.run
@@ -41,8 +41,6 @@ module PDK
41
41
 
42
42
  Release.prepare_interview(opts) unless opts[:force]
43
43
 
44
- Release.send_analytics('release', opts)
45
-
46
44
  release = PDK::Module::Release.new(nil, opts)
47
45
 
48
46
  Release.module_compatibility_checks!(release, opts)
@@ -81,12 +79,6 @@ module PDK
81
79
  end
82
80
  end
83
81
 
84
- # Send_analytics for the given command and Cri options
85
- def self.send_analytics(command, opts)
86
- # Don't pass tokens to analytics
87
- PDK::CLI::Util.analytics_screen_view(command, opts.reject { |k, _| k == :'forge-token' })
88
- end
89
-
90
82
  def self.prepare_interview(opts)
91
83
  questions = []
92
84
 
@@ -34,8 +34,6 @@ module PDK
34
34
 
35
35
  PDK::CLI::Util.module_version_check
36
36
 
37
- PDK::CLI::Util.analytics_screen_view('test_unit', opts)
38
-
39
37
  # Ensure that the bundled gems are up to date and correct Ruby is activated before running or listing tests.
40
38
  puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
41
39
  PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
@@ -14,7 +14,9 @@ module PDK
14
14
  # Write the context information to the debug log
15
15
  PDK.context.to_debug_log
16
16
 
17
- raise PDK::CLI::ExitWithError, '`pdk update` can only be run from inside a valid module directory.' unless PDK.context.is_a?(PDK::Context::Module)
17
+ unless PDK.context.is_a?(PDK::Context::Module) || PDK.context.is_a?(PDK::Context::ControlRepo)
18
+ raise PDK::CLI::ExitWithError, '`pdk update` can only be run from inside a valid module directory.'
19
+ end
18
20
 
19
21
  raise PDK::CLI::ExitWithError, 'This module does not appear to be PDK compatible. To make the module compatible with PDK, run `pdk convert`.' unless PDK::Util.module_pdk_compatible?
20
22
 
@@ -31,8 +33,6 @@ module PDK
31
33
  end
32
34
  end
33
35
 
34
- PDK::CLI::Util.analytics_screen_view('update', opts)
35
-
36
36
  updater = PDK::Module::Update.new(PDK.context.root_path, opts)
37
37
 
38
38
  if updater.pinned_to_puppetlabs_template_tag?
data/lib/pdk/cli/util.rb CHANGED
@@ -245,44 +245,6 @@ module PDK
245
245
  raise PDK::CLI::ExitWithError, '--template-url may not be used to specify paths containing #\'s.'
246
246
  end
247
247
  module_function :validate_template_opts
248
-
249
- def analytics_screen_view(screen_name, opts = {})
250
- require 'pdk/analytics'
251
-
252
- dimensions = {
253
- ruby_version: RUBY_VERSION
254
- }
255
-
256
- cmd_opts = opts.dup.reject do |_, v|
257
- v.nil? || (v.respond_to?(:empty?) && v.empty?)
258
- end
259
-
260
- if (format_args = cmd_opts.delete(:format))
261
- formats = PDK::CLI::Util::OptionNormalizer.report_formats(format_args)
262
- dimensions[:output_format] = formats.map { |r| r[:method].to_s.delete_prefix('write_') }.sort.uniq.join(',')
263
- else
264
- dimensions[:output_format] = 'default'
265
- end
266
-
267
- safe_opts = [:'puppet-version', :'pe-version']
268
- safe_bools = [true, false]
269
- redacted_opts = cmd_opts.map do |k, v|
270
- value = if safe_bools.include?(v) || safe_opts.include?(k)
271
- v
272
- else
273
- 'redacted'
274
- end
275
- "#{k}=#{value}"
276
- end
277
- dimensions[:cli_options] = redacted_opts.join(',') unless redacted_opts.empty?
278
-
279
- ignored_env_vars = ['PDK_ANALYTICS_CONFIG', 'PDK_DISABLE_ANALYTICS']
280
- env_vars = PDK::Util::Env.select { |k, _| k.start_with?('PDK_') && !ignored_env_vars.include?(k) }.map { |k, v| "#{k}=#{v}" }
281
- dimensions[:env_vars] = env_vars.join(',') unless env_vars.empty?
282
-
283
- PDK.analytics.screen_view(screen_name, **dimensions)
284
- end
285
- module_function :analytics_screen_view
286
248
  end
287
249
  end
288
250
  end
@@ -29,7 +29,6 @@ module PDK
29
29
  require 'pdk/validate'
30
30
 
31
31
  if opts[:list]
32
- PDK::CLI::Util.analytics_screen_view('validate', opts)
33
32
  PDK.logger.info(format('Available validators: %{validator_names}', validator_names: PDK::Validate.validator_names.join(', ')))
34
33
  exit 0
35
34
  end
@@ -75,12 +74,6 @@ module PDK
75
74
  end
76
75
  validators_to_run = PDK::Validate.validator_names if validators_to_run.nil?
77
76
 
78
- if validators_to_run.sort == PDK::Validate.validator_names.sort
79
- PDK::CLI::Util.analytics_screen_view('validate', opts)
80
- else
81
- PDK::CLI::Util.analytics_screen_view(['validate', validators_to_run.sort].flatten.join('_'), opts)
82
- end
83
-
84
77
  # Subsequent arguments are targets.
85
78
  targets.concat(args.to_a[1..]) if args.length > 1
86
79
 
data/lib/pdk/cli.rb CHANGED
@@ -16,7 +16,6 @@ module Cri
16
16
  class CriExitException
17
17
  def initialize(is_error:)
18
18
  @is_error = is_error
19
- PDK.analytics.event('CLI', 'invalid command', label: PDK::CLI.anonymised_args.join(' ')) if error?
20
19
  end
21
20
  end
22
21
  end
@@ -56,7 +55,6 @@ module PDK
56
55
 
57
56
  def self.run(args)
58
57
  @args = args
59
- PDK::Config.analytics_config_interview! unless PDK::Util::Env['PDK_DISABLE_ANALYTICS'] || PDK::Config.analytics_config_exist?
60
58
  @base_cmd.run(args)
61
59
  rescue PDK::CLI::ExitWithError => e
62
60
  PDK.logger.send(e.log_level, e.message)
@@ -24,7 +24,7 @@ module PDK
24
24
  # a child of (defaults to nil).
25
25
  # @option params [self] :persistent_defaults whether default values should be persisted
26
26
  # to disk when evaluated. By default they are not persisted to disk. This is typically
27
- # used for settings which a randomly generated, instead of being deterministic, e.g. analytics user-id
27
+ # used for settings which a randomly generated, instead of being deterministic, e.g. module_defaults author
28
28
  # @param block [Proc] a block that is evaluated within the new instance.
29
29
  def initialize(name = nil, file: nil, parent: nil, persistent_defaults: false, &block)
30
30
  @file = PDK::Util::Filesystem.expand_path(file) unless file.nil?
@@ -162,7 +162,7 @@ module PDK
162
162
  new_hash = {}
163
163
  settings.each_pair { |k, v| new_hash[k] = v.value }
164
164
  @mounts.each_pair { |k, mount_point| new_hash[k] = mount_point.to_h if mount_point.include_in_parent? }
165
- new_hash.delete_if { |_k, v| v.nil? } # rubocop :disable Style/CollectionCompact
165
+ new_hash.delete_if { |_k, v| v.nil? }
166
166
  new_hash
167
167
  end
168
168
 
@@ -238,7 +238,7 @@ module PDK
238
238
  # Returns true when filter is nil.
239
239
  # Returns true if the filter is exactly the same name as the setting.
240
240
  # Returns true if the name is a sub-key of the filter e.g.
241
- # Given a filter of user.module_defaults, `user.module_defaults.author` will return true, but `user.analytics.disabled` will return false.
241
+ # Given a filter of user.module_defaults, `user.module_defaults.author` will return true, but `user.pdk_feature_flags.requested` will return false.
242
242
  #
243
243
  # @param name [String] The setting name to test.
244
244
  # @param filter [String] The filter used to test on the name.
@@ -9,9 +9,9 @@ module PDK
9
9
  #
10
10
  # @example
11
11
  #
12
- # PDK::Config::Namespace.new('analytics') do
13
- # setting :disabled do
14
- # validate PDK::Config::Validator.boolean
12
+ # PDK::Config::Namespace.new('module_defaults') do
13
+ # setting :author do
14
+ # validate PDK::Config::Validator.string
15
15
  # default_to { false }
16
16
  # end
17
17
  # end
data/lib/pdk/config.rb CHANGED
@@ -19,7 +19,6 @@ module PDK
19
19
  # @option options [String] 'system.module_defaults.path' Path to the system module answers PDK configuration file
20
20
  # @option options [String] 'user.path' Path to the user PDK configuration file
21
21
  # @option options [String] 'user.module_defaults.path' Path to the user module answers PDK configuration file
22
- # @option options [String] 'user.analytics.path' Path to the user analytics PDK configuration file
23
22
  # @option options [PDK::Context::AbstractContext] 'context' The context that the configuration should be created in
24
23
  def initialize(options = nil)
25
24
  options = {} if options.nil?
@@ -28,7 +27,6 @@ module PDK
28
27
  'system.module_defaults.path' => PDK::Config.system_answers_path,
29
28
  'user.path' => PDK::Config.user_config_path,
30
29
  'user.module_defaults.path' => PDK::AnswerFile.default_answer_file_path,
31
- 'user.analytics.path' => PDK::Config.analytics_config_path,
32
30
  'context' => PDK.context
33
31
  }.merge(options)
34
32
  end
@@ -51,27 +49,6 @@ module PDK
51
49
  @user_config ||= PDK::Config::JSON.new('user', file: local_options['user.path']) do
52
50
  mount :module_defaults, PDK::Config::JSON.new(file: local_options['user.module_defaults.path'])
53
51
 
54
- # Due to the json-schema gem having issues with Windows based paths, and only supporting Draft 05 (or less) do
55
- # not use JSON validation yet. Once PDK drops support for EOL rubies, we will be able to use the json_schemer gem
56
- # Which has much more modern support
57
- # Reference - https://github.com/puppetlabs/pdk/pull/777
58
- # Reference - https://tickets.puppetlabs.com/browse/PDK-1526
59
- mount :analytics, PDK::Config::YAML.new(file: local_options['user.analytics.path'], persistent_defaults: true) do
60
- setting :disabled do
61
- validate PDK::Config::Validator.boolean
62
- default_to { PDK::Config.bolt_analytics_config.fetch('disabled', true) }
63
- end
64
-
65
- setting 'user-id' do
66
- validate PDK::Config::Validator.uuid
67
- default_to do
68
- require 'securerandom'
69
-
70
- PDK::Config.bolt_analytics_config.fetch('user-id', SecureRandom.uuid)
71
- end
72
- end
73
- end
74
-
75
52
  # Display the feature flags
76
53
  mount :pdk_feature_flags, PDK::Config::Namespace.new('pdk_feature_flags') do
77
54
  setting 'available' do
@@ -191,18 +168,6 @@ module PDK
191
168
  deep_set_object(value, options[:force], send(all_scopes[scope_name]), *names[1..])
192
169
  end
193
170
 
194
- def self.bolt_analytics_config
195
- file = PDK::Util::Filesystem.expand_path('~/.puppetlabs/bolt/analytics.yaml')
196
- PDK::Config::YAML.new(file: file)
197
- rescue PDK::Config::LoadError => e
198
- PDK.logger.debug format('Unable to load %{file}: %{message}', file: file, message: e.message)
199
- PDK::Config::YAML.new
200
- end
201
-
202
- def self.analytics_config_path
203
- PDK::Util::Env['PDK_ANALYTICS_CONFIG'] || File.join(File.dirname(PDK::Util.configdir), 'puppet', 'analytics.yml')
204
- end
205
-
206
171
  def self.user_config_path
207
172
  File.join(PDK::Util.configdir, 'user_config.json')
208
173
  end
@@ -224,51 +189,6 @@ module PDK
224
189
  File.join(json_schemas_path, "#{name}_schema.json")
225
190
  end
226
191
 
227
- def self.analytics_config_exist?
228
- PDK::Util::Filesystem.file?(analytics_config_path)
229
- end
230
-
231
- def self.analytics_config_interview!
232
- require 'pdk/cli/util'
233
-
234
- return unless PDK::CLI::Util.interactive?
235
-
236
- pre_message =
237
- format('PDK collects anonymous usage information to help us understand how ' \
238
- 'it is being used and make decisions on how to improve it. You can ' \
239
- 'find out more about what data we collect and how it is used in the ' \
240
- "PDK documentation at %{url}.\n", url: 'https://puppet.com/docs/pdk/latest/pdk_install.html')
241
- post_message =
242
- format('You can opt in or out of the usage data collection at any time by ' \
243
- 'editing the analytics configuration file at %{path} and changing ' \
244
- "the '%{key}' value.", path: PDK::Config.analytics_config_path, key: 'disabled')
245
-
246
- questions = [
247
- {
248
- name: 'enabled',
249
- question: 'Do you consent to the collection of anonymous PDK usage information?',
250
- type: :yes
251
- }
252
- ]
253
-
254
- require 'pdk/cli/util/interview'
255
-
256
- PDK.logger.info(text: pre_message, wrap: true)
257
- prompt = TTY::Prompt.new(help_color: :cyan)
258
- interview = PDK::CLI::Util::Interview.new(prompt)
259
- interview.add_questions(questions)
260
- answers = interview.run
261
-
262
- if answers.nil?
263
- PDK.logger.info 'No answer given, opting out of analytics collection.'
264
- PDK.config.set(['user', 'analytics', 'disabled'], true)
265
- else
266
- PDK.config.set(['user', 'analytics', 'disabled'], !answers['enabled'])
267
- end
268
-
269
- PDK.logger.info(text: post_message, wrap: true)
270
- end
271
-
272
192
  private
273
193
 
274
194
  # :nocov: This is a private method and is tested elsewhere
@@ -148,7 +148,7 @@ module PDK
148
148
  module_name = new_metadata.nil? ? 'new-module' : new_metadata.data['name']
149
149
  metadata_for_render = new_metadata.nil? ? {} : new_metadata.data
150
150
 
151
- template_dir.render_new_module(module_name, metadata_for_render) do |relative_file_path, file_content, file_status|
151
+ template_dir.render_new_module(module_name, metadata_for_render) do |relative_file_path, file_content, file_status, file_executable|
152
152
  absolute_file_path = File.join(module_dir, relative_file_path)
153
153
  case file_status
154
154
  when :unmanage
@@ -156,12 +156,17 @@ module PDK
156
156
  when :delete
157
157
  update_manager.remove_file(absolute_file_path)
158
158
  when :init
159
- update_manager.add_file(absolute_file_path, file_content) if convert? && !PDK::Util::Filesystem.exist?(absolute_file_path)
159
+ if convert? && !PDK::Util::Filesystem.exist?(absolute_file_path)
160
+ update_manager.add_file(absolute_file_path, file_content)
161
+ update_manager.make_file_executable(absolute_file_path) if file_executable
162
+ end
160
163
  when :manage
161
164
  if PDK::Util::Filesystem.exist?(absolute_file_path)
162
165
  update_manager.modify_file(absolute_file_path, file_content)
166
+ update_manager.make_file_executable(absolute_file_path) if file_executable && !PDK::Util::Filesystem.executable?(absolute_file_path)
163
167
  else
164
168
  update_manager.add_file(absolute_file_path, file_content)
169
+ update_manager.make_file_executable(absolute_file_path) if file_executable
165
170
  end
166
171
  end
167
172
  end
@@ -117,7 +117,7 @@ module PDK
117
117
  def to_json(*_args)
118
118
  require 'json'
119
119
 
120
- JSON.pretty_generate(@data.dup.delete_if { |_key, value| value.nil? }) # rubocop:disable Style/CollectionCompact
120
+ JSON.pretty_generate(@data.dup.delete_if { |_key, value| value.nil? })
121
121
  end
122
122
 
123
123
  def write!(path)
@@ -11,6 +11,7 @@ module PDK
11
11
  @modified_files = Set.new
12
12
  @added_files = Set.new
13
13
  @removed_files = Set.new
14
+ @executable_files = Set.new
14
15
  @diff_cache = {}
15
16
  end
16
17
 
@@ -37,6 +38,13 @@ module PDK
37
38
  @removed_files << path
38
39
  end
39
40
 
41
+ # Store a pending file execute mode change.
42
+ #
43
+ # @param path [String] The path to the file to be made executable.
44
+ def make_file_executable(path)
45
+ @executable_files << path
46
+ end
47
+
40
48
  # Generate a summary of the changes that will be applied to the module.
41
49
  #
42
50
  # @raise (see #calculate_diffs)
@@ -49,7 +57,8 @@ module PDK
49
57
  {
50
58
  added: @added_files,
51
59
  removed: @removed_files.select { |f| PDK::Util::Filesystem.exist?(f) },
52
- modified: @diff_cache.compact
60
+ modified: @diff_cache.compact,
61
+ 'made executable': @executable_files
53
62
  }
54
63
  end
55
64
 
@@ -60,7 +69,8 @@ module PDK
60
69
  def changes?
61
70
  !changes[:added].empty? ||
62
71
  !changes[:removed].empty? ||
63
- changes[:modified].any? { |_, value| !value.nil? }
72
+ changes[:modified].any? { |_, value| !value.nil? } ||
73
+ !changes[:'made executable'].empty?
64
74
  end
65
75
 
66
76
  # Check if the update manager will change the specified file upon sync.
@@ -72,13 +82,15 @@ module PDK
72
82
  def changed?(path)
73
83
  changes[:added].any? { |add| add[:path] == path } ||
74
84
  changes[:removed].include?(path) ||
75
- changes[:modified].key?(path)
85
+ changes[:modified].key?(path) ||
86
+ changes[:'made executable'].include?(path)
76
87
  end
77
88
 
78
89
  def clear!
79
90
  @modified_files.clear
80
91
  @added_files.clear
81
92
  @removed_files.clear
93
+ @executable_files.clear
82
94
  nil
83
95
  end
84
96
 
@@ -100,6 +112,10 @@ module PDK
100
112
  files_to_write.each do |file|
101
113
  write_file(file[:path], file[:content])
102
114
  end
115
+
116
+ @executable_files.each do |file|
117
+ update_execute_bits(file)
118
+ end
103
119
  end
104
120
 
105
121
  # Remove a file from disk.
@@ -215,6 +231,16 @@ module PDK
215
231
 
216
232
  output.join($INPUT_RECORD_SEPARATOR)
217
233
  end
234
+
235
+ # Set the execute bits on a file
236
+ def update_execute_bits(path)
237
+ require 'pdk/util/filesystem'
238
+
239
+ PDK.logger.debug(format("making '%{path}' executable", path: path))
240
+ PDK::Util::Filesystem.make_executable(path)
241
+ rescue Errno::EACCES
242
+ raise PDK::CLI::ExitWithError, format("You do not have permission to make '%{path}' executable", path: path)
243
+ end
218
244
  end
219
245
  end
220
246
  end
@@ -53,7 +53,7 @@ module PDK
53
53
  # @raise [ArgumentError] (see #sanitise_data)
54
54
  def initialize(data)
55
55
  sanitise_data(data).each do |key, value|
56
- instance_variable_set("@#{key}", value)
56
+ instance_variable_set(:"@#{key}", value)
57
57
  end
58
58
  end
59
59
 
@@ -43,7 +43,6 @@ module PDK
43
43
  # @api private
44
44
  def config_for(dest_path, sync_config_path = nil)
45
45
  require 'pdk/util'
46
- require 'pdk/analytics'
47
46
 
48
47
  module_root = PDK::Util.module_root
49
48
  sync_config_path ||= File.join(module_root, '.sync.yml') unless module_root.nil?
@@ -56,22 +55,20 @@ module PDK
56
55
  @config = conf_defaults
57
56
  @config.deep_merge!(@sync_config, knockout_prefix: '---') unless @sync_config.nil?
58
57
  end
59
- file_config = @config.fetch(:global, {})
58
+ file_config = @config.fetch('common', {}).clone
60
59
  file_config['module_metadata'] = @module_metadata
61
60
  file_config.merge!(@config.fetch(dest_path, {})) unless dest_path.nil?
62
61
  file_config.merge!(@config).tap do |c|
63
62
  if uri.default?
64
- file_value = if c['unmanaged']
65
- 'unmanaged'
66
- elsif c['delete']
67
- 'deleted'
68
- elsif @sync_config&.key?(dest_path)
69
- 'customized'
70
- else
71
- 'default'
72
- end
73
-
74
- PDK.analytics.event('TemplateDir', 'file', label: dest_path, value: file_value)
63
+ if c['unmanaged']
64
+ 'unmanaged'
65
+ elsif c['delete']
66
+ 'deleted'
67
+ elsif @sync_config&.key?(dest_path)
68
+ 'customized'
69
+ else
70
+ 'default'
71
+ end
75
72
  end
76
73
  end
77
74
  end
@@ -95,7 +95,9 @@ module PDK
95
95
  end
96
96
  end
97
97
 
98
- yield dest_path, dest_content, dest_status
98
+ dest_executable = config['manage_execute_permissions'] && PDK::Util::Filesystem.executable?(File.join(template_loc, template_file))
99
+
100
+ yield dest_path, dest_content, dest_status, dest_executable
99
101
  end
100
102
  end
101
103
  # :nocov:
data/lib/pdk/template.rb CHANGED
@@ -44,9 +44,6 @@ module PDK
44
44
  template_dir = TemplateDir.instance(uri, fetcher.path, context)
45
45
  template_dir.metadata = fetcher.metadata
46
46
 
47
- template_type = uri.default? ? 'default' : 'custom'
48
- PDK.analytics.event('TemplateDir', 'initialize', label: template_type)
49
-
50
47
  yield template_dir
51
48
  end
52
49
  nil
@@ -27,6 +27,11 @@ module PDK
27
27
  end
28
28
  module_function :read_file
29
29
 
30
+ def make_executable(file)
31
+ FileUtils.chmod('a+x', file)
32
+ end
33
+ module_function :make_executable
34
+
30
35
  # :nocov:
31
36
  # These methods just wrap core Ruby functionality and
32
37
  # can be ignored for code coverage
@@ -133,6 +138,11 @@ module PDK
133
138
  end
134
139
  end
135
140
  module_function :mv
141
+
142
+ def executable?(*args)
143
+ File.executable?(*args)
144
+ end
145
+ module_function :executable?
136
146
  # :nocov:
137
147
  end
138
148
  end
data/lib/pdk/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module PDK
2
- VERSION = '3.0.1'.freeze
3
- TEMPLATE_REF = '3.0.1'.freeze
2
+ VERSION = '3.2.0'.freeze
3
+ TEMPLATE_REF = '3.2.0'.freeze
4
4
  end
data/lib/pdk.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  module PDK
2
- autoload :Analytics, 'pdk/analytics'
3
2
  autoload :AnswerFile, 'pdk/answer_file'
4
3
  autoload :Bolt, 'pdk/bolt'
5
4
  autoload :Config, 'pdk/config'
@@ -58,17 +57,4 @@ module PDK
58
57
 
59
58
  requested_feature_flags.include?(flagname)
60
59
  end
61
-
62
- def self.analytics
63
- @analytics ||= PDK::Analytics.build_client(
64
- logger: PDK.logger,
65
- disabled: PDK::Util::Env['PDK_DISABLE_ANALYTICS'] || PDK.config.get_within_scopes('analytics.disabled', ['user', 'system']),
66
- user_id: PDK.config.get_within_scopes('analytics.user-id', ['user', 'system']),
67
- app_id: "UA-139917834-#{PDK::Util.development_mode? ? '2' : '1'}",
68
- client: :google_analytics,
69
- app_name: 'pdk',
70
- app_version: PDK::VERSION,
71
- app_installer: PDK::Util.package_install? ? 'package' : 'gem'
72
- )
73
- end
74
60
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-20 00:00:00.000000000 Z
11
+ date: 2024-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -204,48 +204,6 @@ dependencies:
204
204
  - - "~>"
205
205
  - !ruby/object:Gem::Version
206
206
  version: '0.5'
207
- - !ruby/object:Gem::Dependency
208
- name: concurrent-ruby
209
- requirement: !ruby/object:Gem::Requirement
210
- requirements:
211
- - - '='
212
- - !ruby/object:Gem::Version
213
- version: 1.1.10
214
- type: :runtime
215
- prerelease: false
216
- version_requirements: !ruby/object:Gem::Requirement
217
- requirements:
218
- - - '='
219
- - !ruby/object:Gem::Version
220
- version: 1.1.10
221
- - !ruby/object:Gem::Dependency
222
- name: facter
223
- requirement: !ruby/object:Gem::Requirement
224
- requirements:
225
- - - "~>"
226
- - !ruby/object:Gem::Version
227
- version: '4.0'
228
- type: :runtime
229
- prerelease: false
230
- version_requirements: !ruby/object:Gem::Requirement
231
- requirements:
232
- - - "~>"
233
- - !ruby/object:Gem::Version
234
- version: '4.0'
235
- - !ruby/object:Gem::Dependency
236
- name: httpclient
237
- requirement: !ruby/object:Gem::Requirement
238
- requirements:
239
- - - "~>"
240
- - !ruby/object:Gem::Version
241
- version: 2.8.3
242
- type: :runtime
243
- prerelease: false
244
- version_requirements: !ruby/object:Gem::Requirement
245
- requirements:
246
- - - "~>"
247
- - !ruby/object:Gem::Version
248
- version: 2.8.3
249
207
  - !ruby/object:Gem::Dependency
250
208
  name: deep_merge
251
209
  requirement: !ruby/object:Gem::Requirement
@@ -273,10 +231,6 @@ files:
273
231
  - README.md
274
232
  - exe/pdk
275
233
  - lib/pdk.rb
276
- - lib/pdk/analytics.rb
277
- - lib/pdk/analytics/client/google_analytics.rb
278
- - lib/pdk/analytics/client/noop.rb
279
- - lib/pdk/analytics/util.rb
280
234
  - lib/pdk/answer_file.rb
281
235
  - lib/pdk/bolt.rb
282
236
  - lib/pdk/cli.rb
@@ -321,7 +275,6 @@ files:
321
275
  - lib/pdk/cli/util/update_manager_printer.rb
322
276
  - lib/pdk/cli/validate.rb
323
277
  - lib/pdk/config.rb
324
- - lib/pdk/config/analytics_schema.json
325
278
  - lib/pdk/config/errors.rb
326
279
  - lib/pdk/config/ini_file.rb
327
280
  - lib/pdk/config/ini_file_setting.rb
@@ -1,141 +0,0 @@
1
- require 'pdk'
2
-
3
- module PDK
4
- module Analytics
5
- module Client
6
- class GoogleAnalytics
7
- PROTOCOL_VERSION = 1
8
- TRACKING_URL = 'https://google-analytics.com/collect'.freeze
9
- CUSTOM_DIMENSIONS = {
10
- operating_system: :cd1,
11
- output_format: :cd2,
12
- ruby_version: :cd3,
13
- cli_options: :cd4,
14
- env_vars: :cd5
15
- }.freeze
16
-
17
- attr_reader :user_id, :logger, :app_name, :app_id, :app_version, :app_installer
18
-
19
- def initialize(opts)
20
- # lazy-load expensive gem code
21
- require 'concurrent/configuration'
22
- require 'concurrent/future'
23
- require 'httpclient'
24
- require 'locale'
25
- require 'pdk/analytics/util'
26
-
27
- @http = HTTPClient.new
28
- @user_id = opts[:user_id]
29
- @executor = Concurrent.global_io_executor
30
- @os = PDK::Analytics::Util.fetch_os_async
31
- @logger = opts[:logger]
32
- @app_name = opts[:app_name]
33
- @app_id = opts[:app_id]
34
- @app_version = opts[:app_version]
35
- @app_installer = opts[:app_installer]
36
- end
37
-
38
- def screen_view(screen, **kwargs)
39
- custom_dimensions = walk_keys(kwargs) do |k|
40
- CUSTOM_DIMENSIONS[k] || raise(format("Unknown analytics key '%{key}'", key: k))
41
- end
42
-
43
- screen_view_params = {
44
- # Type
45
- t: 'screenview',
46
- # Screen Name
47
- cd: screen
48
- }.merge(custom_dimensions)
49
-
50
- submit(base_params.merge(screen_view_params))
51
- end
52
-
53
- def event(category, action, label: nil, value: nil, **kwargs)
54
- custom_dimensions = walk_keys(kwargs) do |k|
55
- CUSTOM_DIMENSIONS[k] || raise(format("Unknown analytics key '%{key}'", key: k))
56
- end
57
-
58
- event_params = {
59
- # Type
60
- t: 'event',
61
- # Event Category
62
- ec: category,
63
- # Event Action
64
- ea: action
65
- }.merge(custom_dimensions)
66
-
67
- # Event Label
68
- event_params[:el] = label if label
69
- # Event Value
70
- event_params[:ev] = value if value
71
-
72
- submit(base_params.merge(event_params))
73
- end
74
-
75
- def submit(params)
76
- # Handle analytics submission in the background to avoid blocking the
77
- # app or polluting the log with errors
78
- Concurrent::Future.execute(executor: @executor) do
79
- require 'json'
80
-
81
- logger.debug "Submitting analytics: #{JSON.pretty_generate(params)}"
82
- @http.post(TRACKING_URL, params)
83
- logger.debug 'Completed analytics submission'
84
- end
85
- end
86
-
87
- # These parameters have terrible names. See this page for complete documentation:
88
- # https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
89
- def base_params
90
- require 'locale'
91
-
92
- {
93
- v: PROTOCOL_VERSION,
94
- # Client ID
95
- cid: user_id,
96
- # Tracking ID
97
- tid: app_id,
98
- # Application Name
99
- an: app_name,
100
- # Application Version
101
- av: app_version,
102
- # Application Installer ID
103
- aiid: app_installer,
104
- # Anonymize IPs
105
- aip: true,
106
- # User locale
107
- ul: Locale.current.to_rfc,
108
- # Custom Dimension 1 (Operating System)
109
- cd1: @os.value
110
- }
111
- end
112
-
113
- # If the user is running a very fast command, there may not be time for
114
- # analytics submission to complete before the command is finished. In
115
- # that case, we give a little buffer for any stragglers to finish up.
116
- # 250ms strikes a balance between accomodating slower networks while not
117
- # introducing a noticeable "hang".
118
- def finish
119
- @executor.shutdown
120
- @executor.wait_for_termination(0.25)
121
- end
122
-
123
- private
124
-
125
- def walk_keys(data, &block)
126
- case data
127
- when Hash
128
- data.each_with_object({}) do |(k, v), acc|
129
- v = walk_keys(v, &block)
130
- acc[yield(k)] = v
131
- end
132
- when Array
133
- data.map { |v| walk_keys(v, &block) }
134
- else
135
- data
136
- end
137
- end
138
- end
139
- end
140
- end
141
- end
@@ -1,25 +0,0 @@
1
- require 'pdk'
2
-
3
- module PDK
4
- module Analytics
5
- module Client
6
- class Noop
7
- attr_reader :logger
8
-
9
- def initialize(opts)
10
- @logger = opts[:logger]
11
- end
12
-
13
- def screen_view(screen, **_kwargs)
14
- logger.debug "Skipping submission of '#{screen}' screenview because analytics is disabled"
15
- end
16
-
17
- def event(category, action, **_kwargs)
18
- logger.debug "Skipping submission of '#{category} #{action}' event because analytics is disabled"
19
- end
20
-
21
- def finish; end
22
- end
23
- end
24
- end
25
- end
@@ -1,18 +0,0 @@
1
- require 'pdk'
2
-
3
- module PDK
4
- module Analytics
5
- module Util
6
- def self.fetch_os_async
7
- require 'concurrent/configuration'
8
- require 'concurrent/future'
9
-
10
- Concurrent::Future.execute(executor: :io) do
11
- os = Facter.value('os')
12
-
13
- os.nil? ? 'unknown' : "#{os['name']} #{os.fetch('release', {}).fetch('major', '')}".strip
14
- end
15
- end
16
- end
17
- end
18
- end
data/lib/pdk/analytics.rb DELETED
@@ -1,30 +0,0 @@
1
- require 'pdk'
2
-
3
- autoload :Logger, 'logger'
4
-
5
- module PDK
6
- module Analytics
7
- autoload :Util, 'pdk/analytics/util'
8
-
9
- module Client
10
- autoload :Noop, 'pdk/analytics/client/noop'
11
- autoload :GoogleAnalytics, 'pdk/analytics/client/google_analytics'
12
- end
13
-
14
- def self.build_client(opts = {})
15
- opts[:logger] ||= ::Logger.new($stderr)
16
- opts[:client] ||= :noop
17
-
18
- if opts[:disabled]
19
- opts[:logger].debug 'Analytics opt-out is set, analytics will be disabled'
20
- opts[:client] = :noop
21
- end
22
-
23
- client_const = opts[:client].to_s.split('_').map(&:capitalize).join
24
- PDK::Analytics::Client.const_get(client_const).new(opts)
25
- rescue StandardError => e
26
- opts[:logger].debug "Failed to initialize analytics client, analytics will be disabled: #{e}"
27
- PDK::Analytics::Client::Noop.new(opts)
28
- end
29
- end
30
- end
@@ -1,26 +0,0 @@
1
- {
2
- "definitions": {},
3
- "$schema": "http://json-schema.org/draft-06/schema#",
4
- "$id": "http://puppet.com/schema/does_not_exist.json",
5
- "type": "object",
6
- "title": "The PDK Analytics YAML Schema",
7
- "properties": {
8
- "disabled": {
9
- "$id": "#/properties/disabled",
10
- "type": "boolean",
11
- "title": "Disabled property",
12
- "examples": [
13
- false
14
- ]
15
- },
16
- "user-id": {
17
- "$id": "#/properties/user-id",
18
- "type": "string",
19
- "title": "The User-id for analytics",
20
- "examples": [
21
- "cb9ed65f-37dc-48d8-9863-8bd09cbb61c7"
22
- ],
23
- "pattern": "^[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}$"
24
- }
25
- }
26
- }