pdk 1.17.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +148 -11
  3. data/README.md +1 -1
  4. data/lib/pdk.rb +1 -1
  5. data/lib/pdk/cli.rb +7 -1
  6. data/lib/pdk/cli/convert.rb +7 -9
  7. data/lib/pdk/cli/env.rb +52 -0
  8. data/lib/pdk/cli/exec/command.rb +11 -1
  9. data/lib/pdk/cli/new.rb +2 -0
  10. data/lib/pdk/cli/new/class.rb +2 -1
  11. data/lib/pdk/cli/new/defined_type.rb +2 -1
  12. data/lib/pdk/cli/new/fact.rb +29 -0
  13. data/lib/pdk/cli/new/function.rb +29 -0
  14. data/lib/pdk/cli/new/provider.rb +2 -1
  15. data/lib/pdk/cli/new/task.rb +2 -1
  16. data/lib/pdk/cli/new/test.rb +2 -1
  17. data/lib/pdk/cli/new/transport.rb +2 -1
  18. data/lib/pdk/cli/release.rb +1 -1
  19. data/lib/pdk/cli/release/publish.rb +11 -1
  20. data/lib/pdk/cli/remove.rb +20 -0
  21. data/lib/pdk/cli/remove/config.rb +80 -0
  22. data/lib/pdk/cli/set.rb +20 -0
  23. data/lib/pdk/cli/set/config.rb +119 -0
  24. data/lib/pdk/cli/update.rb +6 -8
  25. data/lib/pdk/cli/util.rb +1 -0
  26. data/lib/pdk/cli/util/option_validator.rb +6 -0
  27. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  28. data/lib/pdk/config.rb +96 -13
  29. data/lib/pdk/context.rb +8 -5
  30. data/lib/pdk/generate/defined_type.rb +25 -32
  31. data/lib/pdk/generate/fact.rb +25 -0
  32. data/lib/pdk/generate/function.rb +48 -0
  33. data/lib/pdk/generate/module.rb +11 -10
  34. data/lib/pdk/generate/provider.rb +15 -64
  35. data/lib/pdk/generate/puppet_class.rb +25 -31
  36. data/lib/pdk/generate/puppet_object.rb +83 -187
  37. data/lib/pdk/generate/task.rb +28 -46
  38. data/lib/pdk/generate/transport.rb +20 -74
  39. data/lib/pdk/module.rb +1 -1
  40. data/lib/pdk/module/convert.rb +43 -23
  41. data/lib/pdk/module/metadata.rb +6 -2
  42. data/lib/pdk/module/release.rb +8 -2
  43. data/lib/pdk/module/update.rb +7 -11
  44. data/lib/pdk/module/update_manager.rb +7 -0
  45. data/lib/pdk/report.rb +3 -3
  46. data/lib/pdk/report/event.rb +8 -2
  47. data/lib/pdk/template.rb +59 -0
  48. data/lib/pdk/template/fetcher.rb +98 -0
  49. data/lib/pdk/template/fetcher/git.rb +85 -0
  50. data/lib/pdk/template/fetcher/local.rb +28 -0
  51. data/lib/pdk/template/renderer.rb +96 -0
  52. data/lib/pdk/template/renderer/v1.rb +25 -0
  53. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -0
  54. data/lib/pdk/template/renderer/v1/renderer.rb +132 -0
  55. data/lib/pdk/template/renderer/v1/template_file.rb +102 -0
  56. data/lib/pdk/template/template_dir.rb +67 -0
  57. data/lib/pdk/tests/unit.rb +8 -1
  58. data/lib/pdk/util.rb +4 -35
  59. data/lib/pdk/util/bundler.rb +1 -1
  60. data/lib/pdk/util/changelog_generator.rb +20 -3
  61. data/lib/pdk/util/json_finder.rb +85 -0
  62. data/lib/pdk/util/puppet_strings.rb +3 -3
  63. data/lib/pdk/util/puppet_version.rb +2 -2
  64. data/lib/pdk/util/ruby_version.rb +5 -1
  65. data/lib/pdk/util/template_uri.rb +9 -11
  66. data/lib/pdk/util/vendored_file.rb +1 -2
  67. data/lib/pdk/validate.rb +17 -10
  68. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  69. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  70. data/lib/pdk/validate/invokable_validator.rb +8 -4
  71. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +1 -1
  72. data/lib/pdk/validate/validator.rb +7 -0
  73. data/lib/pdk/validate/validator_group.rb +1 -0
  74. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +2 -2
  75. data/lib/pdk/version.rb +1 -1
  76. data/locales/pdk.pot +356 -228
  77. metadata +65 -28
  78. data/lib/pdk/module/template_dir.rb +0 -115
  79. data/lib/pdk/module/template_dir/base.rb +0 -268
  80. data/lib/pdk/module/template_dir/git.rb +0 -91
  81. data/lib/pdk/module/template_dir/local.rb +0 -21
  82. data/lib/pdk/template_file.rb +0 -96
@@ -0,0 +1,119 @@
1
+ module PDK::CLI
2
+ module Set
3
+ module Config
4
+ ALLOWED_TYPE_NAMES = %w[array boolean number string].freeze
5
+
6
+ # :nocov:
7
+ def self.pretty_allowed_names
8
+ ALLOWED_TYPE_NAMES.map { |name| "'#{name}'" }.join(', ')
9
+ end
10
+ # :nocov:
11
+
12
+ def self.transform_value(type_name, value)
13
+ normalized_name = type_name.downcase.strip
14
+ unless ALLOWED_TYPE_NAMES.include?(normalized_name)
15
+ raise PDK::CLI::ExitWithError, _('Unknown type %{type_name}. Expected one of %{allowed}') % { type_name: type_name, allowed: pretty_allowed_names }
16
+ end
17
+
18
+ # Short circuit string conversions as it's trivial
19
+ if normalized_name == 'string'
20
+ raise PDK::CLI::ExitWithError, _('An error occured converting \'%{value}\' into a %{type_name}') % { value: value.nil? ? 'nil' : value, type_name: type_name } unless value.is_a?(String)
21
+ return value
22
+ end
23
+
24
+ begin
25
+ case normalized_name
26
+ when 'array'
27
+ convert_to_array(value)
28
+ when 'boolean'
29
+ convert_to_boolean(value)
30
+ when 'number'
31
+ convert_to_number(value)
32
+ else
33
+ value
34
+ end
35
+ rescue ArgumentError, TypeError
36
+ raise PDK::CLI::ExitWithError, _('An error occured converting \'%{value}\' into a %{type_name}') % { value: value.nil? ? 'nil' : value, type_name: type_name }
37
+ end
38
+ end
39
+
40
+ def self.convert_to_array(value)
41
+ return [] if value.nil?
42
+ value.is_a?(Array) ? value : [value]
43
+ end
44
+ private_class_method :convert_to_array
45
+
46
+ def self.convert_to_boolean(value)
47
+ string_val = value.to_s.strip.downcase
48
+
49
+ return true if %w[yes true -1 1].include?(string_val)
50
+ return false if %w[no false 0].include?(string_val)
51
+
52
+ raise ArgumentError
53
+ end
54
+ private_class_method :convert_to_boolean
55
+
56
+ def self.convert_to_number(value)
57
+ float_val = Float(value)
58
+ # Return an Integer if this is actually and Integer, otherwise return the float
59
+ (float_val.truncate == float_val) ? float_val.truncate : float_val
60
+ end
61
+ private_class_method :convert_to_number
62
+
63
+ def self.run(opts, args)
64
+ item_name = (args.count > 0) ? args[0] : nil
65
+ item_value = (args.count > 1) ? args[1] : nil
66
+
67
+ opts[:type] = opts[:as] if opts[:type].nil? && !opts[:as].nil?
68
+ force = opts[:force] || false
69
+
70
+ # Transform the value if we need to
71
+ item_value = PDK::CLI::Set::Config.transform_value(opts[:type], item_value) unless opts[:type].nil?
72
+
73
+ raise PDK::CLI::ExitWithError, _('Configuration name is required') if item_name.nil?
74
+ raise PDK::CLI::ExitWithError, _('Configuration value is required. If you wish to remove a value use \'pdk remove config\'') if item_value.nil?
75
+
76
+ current_value = PDK.config.get(item_name)
77
+ raise PDK::CLI::ExitWithError, _("The configuration item '%{name}' can not have a value set.") % { name: item_name } if current_value.is_a?(PDK::Config::Namespace)
78
+
79
+ # If we're forcing the value, don't do any munging
80
+ unless force
81
+ # Check if the setting already exists
82
+ if current_value.is_a?(Array) && current_value.include?(item_value)
83
+ PDK.logger.info(_("No changes made to '%{name}' as it already contains value '%{to}'") % { name: item_name, to: item_value })
84
+ return 0
85
+ end
86
+ end
87
+
88
+ new_value = PDK.config.set(item_name, item_value, force: opts[:force])
89
+ if current_value.nil? || force
90
+ PDK.logger.info(_("Set initial value of '%{name}' to '%{to}'") % { name: item_name, to: new_value })
91
+ elsif current_value.is_a?(Array)
92
+ # Arrays have a special output format
93
+ PDK.logger.info(_("Added new value '%{to}' to '%{name}'") % { name: item_name, to: item_value })
94
+ else
95
+ PDK.logger.info(_("Changed existing value of '%{name}' from '%{from}' to '%{to}'") % { name: item_name, from: current_value, to: new_value })
96
+ end
97
+
98
+ # Same output as `get config`
99
+ $stdout.puts _('%{name}=%{value}') % { name: item_name, value: PDK.config.get(item_name) }
100
+ 0
101
+ end
102
+ end
103
+ end
104
+
105
+ @set_config_cmd = @set_cmd.define_command do
106
+ name 'config'
107
+ usage _('config [name] [value]')
108
+ summary _('Set or update the configuration for <name>')
109
+
110
+ option :f, :force, _('Force the configuration setting to be overwitten.'), argument: :forbidden
111
+
112
+ option :t, :type, _('The type of value to set. Acceptable values: %{values}') % { values: PDK::CLI::Set::Config.pretty_allowed_names }, argument: :required
113
+ option nil, :as, _('Alias of --type'), argument: :required
114
+
115
+ run do |opts, args, _cmd|
116
+ exit PDK::CLI::Set::Config.run(opts, args)
117
+ end
118
+ end
119
+ end
@@ -10,14 +10,12 @@ module PDK::CLI
10
10
  PDK::CLI.template_ref_option(self)
11
11
 
12
12
  run do |opts, _args, _cmd|
13
- require 'pdk/cli/util'
14
- require 'pdk/util'
15
- require 'pdk/module/update'
13
+ # Write the context information to the debug log
14
+ PDK.context.to_debug_log
16
15
 
17
- PDK::CLI::Util.ensure_in_module!(
18
- message: _('`pdk update` can only be run from inside a valid module directory.'),
19
- log_level: :info,
20
- )
16
+ unless PDK.context.is_a?(PDK::Context::Module)
17
+ raise PDK::CLI::ExitWithError, _('`pdk update` can only be run from inside a valid module directory.')
18
+ end
21
19
 
22
20
  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?
23
21
 
@@ -46,7 +44,7 @@ module PDK::CLI
46
44
 
47
45
  PDK::CLI::Util.analytics_screen_view('update', opts)
48
46
 
49
- updater = PDK::Module::Update.new(PDK::Util.module_root, opts)
47
+ updater = PDK::Module::Update.new(PDK.context.root_path, opts)
50
48
 
51
49
  if updater.pinned_to_puppetlabs_template_tag?
52
50
  PDK.logger.info _(
data/lib/pdk/cli/util.rb CHANGED
@@ -8,6 +8,7 @@ module PDK
8
8
  autoload :OptionValidator, 'pdk/cli/util/option_validator'
9
9
  autoload :Interview, 'pdk/cli/util/interview'
10
10
  autoload :Spinner, 'pdk/cli/util/spinner'
11
+ autoload :UpdateManagerPrinter, 'pdk/cli/util/update_manager_printer'
11
12
 
12
13
  # Ensures the calling code is being run from inside a module directory.
13
14
  #
@@ -8,6 +8,11 @@ module PDK
8
8
  (list =~ %r{^[\w\-]+(?:,[\w\-]+)+$}) ? true : false
9
9
  end
10
10
 
11
+ # @return [Boolean] true if the fact name is valid
12
+ def self.valid_fact_name?(name)
13
+ name.length > 1
14
+ end
15
+
11
16
  def self.enum(val, valid_entries, _options = {})
12
17
  vals = val.is_a?(Array) ? val : [val]
13
18
  invalid_entries = vals.reject { |e| valid_entries.include?(e) }
@@ -41,6 +46,7 @@ module PDK
41
46
 
42
47
  !(string =~ %r{\A([a-z][a-z0-9_]*)(::[a-z][a-z0-9_]*)*\Z}).nil?
43
48
  end
49
+ singleton_class.send(:alias_method, :valid_function_name?, :valid_namespace?)
44
50
 
45
51
  singleton_class.send(:alias_method, :valid_class_name?, :valid_namespace?)
46
52
  singleton_class.send(:alias_method, :valid_defined_type_name?, :valid_namespace?)
@@ -0,0 +1,82 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module CLI
5
+ module Util
6
+ module UpdateManagerPrinter
7
+ # Prints the summary for a PDK::Module::UpdateManager Object
8
+ # @param update_manager [PDK::Module::UpdateManager] The object to print a summary of
9
+ # @param options [Hash{Object => Object}] A list of options when printing
10
+ # @option options [Boolean] :tense Whether to use future (:future) or past (:past) tense when printing the summary ("Files to be added" versus "Files added"). Default is :future
11
+ #
12
+ # @return [void]
13
+ def self.print_summary(update_manager, options = {})
14
+ require 'pdk/report'
15
+
16
+ options = {
17
+ tense: :future,
18
+ }.merge(options)
19
+
20
+ footer = false
21
+
22
+ summary(update_manager).each do |category, files|
23
+ next if files.empty?
24
+
25
+ PDK::Report.default_target.puts('')
26
+ PDK::Report.default_target.puts(generate_banner("Files #{(options[:tense] == :future) ? 'to be ' : ''}#{category}", 40))
27
+ PDK::Report.default_target.puts(files.map(&:to_s).join("\n"))
28
+ footer = true
29
+ end
30
+
31
+ if footer # rubocop:disable Style/GuardClause No.
32
+ PDK::Report.default_target.puts('')
33
+ PDK::Report.default_target.puts(generate_banner('', 40))
34
+ end
35
+ end
36
+
37
+ #:nocov: Tested as part of the public methods
38
+ # Returns a hash, summarizing the contents of the Update Manager object
39
+ # @param update_manager [PDK::Module::UpdateManager] The object to create a summary of
40
+ #
41
+ # @return [Hash{Symbol => Array[String]}] A hash of each category and the file paths in each category
42
+ def self.summary(update_manager)
43
+ summary = {}
44
+ update_manager.changes.each do |category, update_category|
45
+ if update_category.respond_to?(:keys)
46
+ updated_files = update_category.keys
47
+ else
48
+ begin
49
+ updated_files = update_category.map { |file| file[:path] }
50
+ rescue TypeError
51
+ updated_files = update_category.to_a
52
+ end
53
+ end
54
+
55
+ summary[category] = updated_files
56
+ end
57
+
58
+ summary
59
+ end
60
+ private_class_method :summary
61
+
62
+ # Creates a line of text, with `text` centered in the middle
63
+ # @param text [String] The text to put in the middle of the banner
64
+ # @param width [Integer] The width of the banner in characters. Default is 80
65
+ # @return [String] The generated banner
66
+ def self.generate_banner(text, width = 80)
67
+ padding = width - text.length
68
+ banner = ''
69
+ padding_char = '-'
70
+
71
+ (padding / 2.0).ceil.times { banner << padding_char }
72
+ banner << text
73
+ (padding / 2.0).floor.times { banner << padding_char }
74
+
75
+ banner
76
+ end
77
+ private_class_method :generate_banner
78
+ #:nocov:
79
+ end
80
+ end
81
+ end
82
+ end
data/lib/pdk/config.rb CHANGED
@@ -33,20 +33,12 @@ module PDK
33
33
  }.merge(options)
34
34
  end
35
35
 
36
- # The user configuration settings.
37
- # @deprecated This method is only provided as a courtesy until the `pdk set config` CLI and associated changes in this class, are completed.
38
- # Any read-only operations should be using `.get` or `.get_within_scopes`
39
- # @return [PDK::Config::Namespace]
40
- def user
41
- user_config
42
- end
43
-
44
36
  # The system level configuration settings.
45
37
  # @return [PDK::Config::Namespace]
46
38
  # @api private
47
39
  def system_config
48
40
  local_options = @config_options
49
- @system ||= PDK::Config::JSON.new('system', file: local_options['system.path']) do
41
+ @system_config ||= PDK::Config::JSON.new('system', file: local_options['system.path']) do
50
42
  mount :module_defaults, PDK::Config::JSON.new(file: local_options['system.module_defaults.path'])
51
43
  end
52
44
  end
@@ -56,7 +48,7 @@ module PDK
56
48
  # @api private
57
49
  def user_config
58
50
  local_options = @config_options
59
- @user ||= PDK::Config::JSON.new('user', file: local_options['user.path']) do
51
+ @user_config ||= PDK::Config::JSON.new('user', file: local_options['user.path']) do
60
52
  mount :module_defaults, PDK::Config::JSON.new(file: local_options['user.module_defaults.path'])
61
53
 
62
54
  # Due to the json-schema gem having issues with Windows based paths, and only supporting Draft 05 (or less) do
@@ -119,6 +111,8 @@ module PDK
119
111
  # - PDK.config.get('user.a.b.c')
120
112
  # - PDK.config.get(['user', 'a', 'b', 'c'])
121
113
  # - PDK.config.get('user', 'a', 'b', 'c')
114
+ # @param root [Array[String], String] The root setting name or the entire setting name as a single string
115
+ # @param keys [String] The child names of the setting
122
116
  # @return [PDK::Config::Namespace, Object, nil] The value of the configuration setting. Returns nil if it does no exist
123
117
  def get(root, *keys)
124
118
  return nil if root.nil? || root.empty?
@@ -169,6 +163,26 @@ module PDK
169
163
  yield value unless value.nil?
170
164
  end
171
165
 
166
+ # Sets a configuration setting by name. This name can either be a String or an Array
167
+ # - PDK.config.set('user.a.b.c', ...)
168
+ # - PDK.config.set(['user', 'a', 'b', 'c'], ...)
169
+ # @param key [String, Array[String]] The name of the configuration key to change
170
+ # @param value [Object] The value to set the configuration setting to
171
+ # @param options [Hash] Changes the behaviour of the setting process
172
+ # @option options [Boolean] :force Disables any munging or array processing, and sets the value as it is. Default is false
173
+ # @return [Object] The new value of the configuration setting
174
+ def set(key, value, options = {})
175
+ options = {
176
+ force: false,
177
+ }.merge(options)
178
+
179
+ names = key.is_a?(String) ? split_key_string(key) : key
180
+ raise ArgumentError, _('Invalid configuration names') if names.nil? || !names.is_a?(Array) || names.empty?
181
+ scope_name = names[0]
182
+ raise ArgumentError, _("Unknown configuration root '%{name}'") % { name: scope_name } if all_scopes[scope_name].nil?
183
+ deep_set_object(value, options[:force], send(all_scopes[scope_name]), *names[1..-1])
184
+ end
185
+
172
186
  def self.bolt_analytics_config
173
187
  file = PDK::Util::Filesystem.expand_path('~/.puppetlabs/bolt/analytics.yaml')
174
188
  PDK::Config::YAML.new(file: file)
@@ -247,9 +261,9 @@ module PDK
247
261
 
248
262
  if answers.nil?
249
263
  PDK.logger.info _('No answer given, opting out of analytics collection.')
250
- PDK.config.user['analytics']['disabled'] = true
264
+ PDK.config.set(%w[user analytics disabled], true)
251
265
  else
252
- PDK.config.user['analytics']['disabled'] = !answers['enabled']
266
+ PDK.config.set(%w[user analytics disabled], !answers['enabled'])
253
267
  end
254
268
 
255
269
  PDK.logger.info(text: post_message, wrap: true)
@@ -260,7 +274,12 @@ module PDK
260
274
  #:nocov: This is a private method and is tested elsewhere
261
275
  def traverse_object(object, *names)
262
276
  return nil if object.nil? || !object.respond_to?(:[])
263
- return nil if names.nil? || names.empty?
277
+ return nil if names.nil?
278
+ # It's possible to pass in empty names at the root traversal layer
279
+ # but this should _only_ happen at the root namespace level
280
+ if names.empty?
281
+ return (object.is_a?(PDK::Config::Namespace) ? object : nil)
282
+ end
264
283
 
265
284
  name = names.shift
266
285
  value = object[name]
@@ -296,6 +315,70 @@ module PDK
296
315
  'system' => :system_config,
297
316
  }.freeze
298
317
  end
318
+
319
+ #:nocov: This is a private method and is tested elsewhere
320
+ # Deeply traverses an object tree via `[]` and sets the last
321
+ # element to the value specified.
322
+ #
323
+ # Creating any missing parent hashes during the traversal
324
+ def deep_set_object(value, force, namespace, *names)
325
+ raise ArgumentError, _('Missing or invalid namespace') unless namespace.is_a?(PDK::Config::Namespace)
326
+ raise ArgumentError, _('Missing a name to set') if names.nil? || names.empty?
327
+
328
+ name = names.shift
329
+ current_value = namespace[name]
330
+
331
+ # If the next thing in the traversal chain is another namespace, set the value using that child namespace.
332
+ if current_value.is_a?(PDK::Config::Namespace)
333
+ return deep_set_object(value, force, current_value, *names)
334
+ end
335
+
336
+ # We're at the end of the name traversal
337
+ if names.empty?
338
+ if force || !current_value.is_a?(Array)
339
+ namespace[name] = value
340
+ return value
341
+ end
342
+
343
+ # Arrays are a special case if we're not forcing the value
344
+ namespace[name] = current_value << value unless current_value.include?(value)
345
+ return value
346
+ end
347
+
348
+ # Need to generate a deep hash using the current remaining names
349
+ # So given an origin *names of ['a', 'b', 'c', 'd'] and a value 'foo',
350
+ # we eventually want a hash of `{"b"=>{"c"=>{"d"=>"foo"}}}`
351
+ #
352
+ # The code above has already shifted the first element so we currently have
353
+ # name : 'a'
354
+ # names: ['b', 'c', 'd']
355
+ #
356
+ #
357
+ # First we need to pop off the last element ('d') in this case as we need to set that in the `reduce` call below
358
+ # So now we have:
359
+ # name : 'a'
360
+ # names: ['b', 'c']
361
+ # last_name : 'd'
362
+ last_name = names.pop
363
+ # Using reduce and an accumulator, we create the nested hash from the deepest value first. In this case the deepest value
364
+ # is the last_name, so the starting condition is {"d"=>"foo"}
365
+ # After the first iteration ('c'), the accumulator has {"c"=>{"d"=>"foo"}}}
366
+ # After the last iteration ('b'), the accumulator has {"b"=>{"c"=>{"d"=>"foo"}}}
367
+ hash_value = names.reverse.reduce(last_name => value) { |accumulator, item| { item => accumulator } }
368
+
369
+ # If the current value is nil, then it can't be a namespace or an existing value
370
+ # or
371
+ # If the current value is not a Hash and are forcing the change.
372
+ if current_value.nil? || (force && !current_value.is_a?(Hash))
373
+ namespace[name] = hash_value
374
+ return value
375
+ end
376
+
377
+ raise ArgumentError, _("Unable to set '%{key}' to '%{value}' as it is not a Hash") % { key: namespace.name + '.' + name, value: hash_value } unless current_value.is_a?(Hash)
378
+
379
+ namespace[name] = current_value.merge(hash_value)
380
+ value
381
+ end
299
382
  #:nocov:
300
383
  end
301
384
  end
data/lib/pdk/context.rb CHANGED
@@ -33,13 +33,15 @@ module PDK
33
33
  # Abstract class which all PDK Contexts will subclass from.
34
34
  # @abstract
35
35
  class AbstractContext
36
- # The root of this context, for example the module root when inside a module. This is different from context_path
36
+ # The root of this context, for example the module root when inside a module. This can be different from context_path
37
37
  # For example a Module context_path could be /path/to/module/manifests/ but the root_path will be /path/to/module as
38
- # that is the root of the Module context
39
- # @return [String, Nil]
40
- attr_reader :root_path
38
+ # that is the root of the Module context. Defaults to the context_path if not set.
39
+ # @return [String]
40
+ def root_path
41
+ @root_path || @context_path
42
+ end
41
43
 
42
- # The path used to create this context, for example the current working directory. This is different from root_path
44
+ # The path used to create this context, for example the current working directory. This can be different from root_path
43
45
  # For example a Module context_path could be /path/to/module/manifests/ but the root_path will be /path/to/module as
44
46
  # that is the root of the Module context
45
47
  # @return [String]
@@ -48,6 +50,7 @@ module PDK
48
50
  # @param context_path [String] The path where this context was created from e.g. Dir.pwd
49
51
  def initialize(context_path)
50
52
  @context_path = context_path
53
+ @root_path = nil
51
54
  end
52
55
 
53
56
  # Whether the current context is compatible with the PDK e.g. in a Module context, whether it has the correct metadata.json content