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,132 @@
1
+ require 'pdk'
2
+ require 'pdk/template/renderer'
3
+
4
+ module PDK
5
+ module Template
6
+ module Renderer
7
+ module V1
8
+ class Renderer < PDK::Template::Renderer::AbstractRenderer
9
+ # @see PDK::Template::Renderer::AbstractRenderer.render
10
+ def render(template_type, _name, options = {})
11
+ render_module(options) { |*args| yield(*args) } if template_type == PDK::Template::MODULE_TEMPLATE_TYPE
12
+ end
13
+
14
+ # @see PDK::Template::Renderer::AbstractRenderer.has_single_item?
15
+ def has_single_item?(item_path) # rubocop:disable Naming/PredicateName
16
+ PDK::Util::Filesystem.exist?(single_item_path(item_path))
17
+ end
18
+
19
+ # @see PDK::Template::Renderer::AbstractRenderer.render_single_item
20
+ def render_single_item(relative_file_path, template_data_hash)
21
+ template_file = single_item_path(relative_file_path)
22
+ return nil unless PDK::Util::Filesystem.file?(template_file) && PDK::Util::Filesystem.readable?(template_file)
23
+
24
+ PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
25
+ new_template_file(template_file, template_data_hash).render
26
+ end
27
+
28
+ # Returns the full path for a single item
29
+ #
30
+ # @param item_path [String] The path of the single item to render
31
+ # @return [String]
32
+ # @api private
33
+ #:nocov:
34
+ def single_item_path(item_path)
35
+ File.join(template_root, 'object_templates', item_path)
36
+ end
37
+ #:nocov:
38
+
39
+ # Helper method used during testing
40
+ #:nocov:
41
+ # @api private
42
+ def new_template_file(template_file, template_data_hash)
43
+ TemplateFile.new(template_file, template_data_hash)
44
+ end
45
+ #:nocov:
46
+
47
+ # Helper method used during testing
48
+ #:nocov:
49
+ # @api private
50
+ def new_legacy_template_dir(context, uri, path, module_metadata = {})
51
+ LegacyTemplateDir.new(context, uri, path, module_metadata)
52
+ end
53
+ #:nocov:
54
+
55
+ # Renders a new module
56
+ #
57
+ # @param options [Hash{Object => Object}] A list of options to pass through to the renderer. See PDK::Template::TemplateDir helper methods for other options
58
+ # @see #render
59
+ # @api private
60
+ #:nocov: This is tested in acceptance and packaging tests
61
+ def render_module(options = {})
62
+ require 'pdk/template/renderer/v1/template_file'
63
+
64
+ moduleroot_dir = File.join(template_root, 'moduleroot')
65
+ moduleroot_init = File.join(template_root, 'moduleroot_init')
66
+
67
+ dirs = [moduleroot_dir]
68
+ dirs << moduleroot_init if options[:include_first_time]
69
+
70
+ legacy_template_dir = new_legacy_template_dir(context, template_uri, template_root, options[:module_metadata] || {})
71
+
72
+ files_in_template(dirs).each do |template_file, template_loc|
73
+ template_file = template_file.to_s
74
+ PDK.logger.debug(_("Rendering '%{template}'...") % { template: template_file })
75
+ dest_path = template_file.sub(%r{\.erb\Z}, '')
76
+ config = legacy_template_dir.config_for(dest_path)
77
+
78
+ dest_status = if template_loc.start_with?(moduleroot_init)
79
+ :init
80
+ else
81
+ :manage
82
+ end
83
+
84
+ if config['unmanaged']
85
+ dest_status = :unmanage
86
+ elsif config['delete']
87
+ dest_status = :delete
88
+ else
89
+ begin
90
+ dest_content = new_template_file(File.join(template_loc, template_file), configs: config, template_dir: legacy_template_dir).render
91
+ rescue => error
92
+ error_msg = _(
93
+ "Failed to render template '%{template}'\n" \
94
+ '%{exception}: %{message}',
95
+ ) % { template: template_file, exception: error.class, message: error.message }
96
+ raise PDK::CLI::FatalError, error_msg
97
+ end
98
+ end
99
+
100
+ yield dest_path, dest_content, dest_status
101
+ end
102
+ end
103
+ #:nocov:
104
+
105
+ # Returns all files in the given template directories
106
+ #
107
+ # @param dirs [Array[String]] Directories to search in
108
+ # @param glob_suffix [Array[String]] File glob to use when searching for files. Defaults to ['**', '*']
109
+ #
110
+ # @return [Hash{String => String}] Key is the template file relative path and the value is the absolute path to the template directory
111
+ # @api private
112
+ def files_in_template(dirs, glob_suffix = ['**', '*'])
113
+ temp_paths = []
114
+ dirlocs = []
115
+ dirs.each do |dir|
116
+ raise ArgumentError, _("The directory '%{dir}' doesn't exist") % { dir: dir } unless PDK::Util::Filesystem.directory?(dir)
117
+ temp_paths += PDK::Util::Filesystem.glob(File.join(dir, *glob_suffix), File::FNM_DOTMATCH).select do |template_path|
118
+ if PDK::Util::Filesystem.file?(template_path) && !PDK::Util::Filesystem.symlink?(template_path)
119
+ dirlocs << dir
120
+ end
121
+ end
122
+ temp_paths.map do |template_path|
123
+ template_path.sub!(%r{\A#{Regexp.escape(dir)}#{Regexp.escape(File::SEPARATOR)}}, '')
124
+ end
125
+ end
126
+ Hash[temp_paths.zip dirlocs]
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,102 @@
1
+ require 'pdk'
2
+ require 'ostruct'
3
+
4
+ module PDK
5
+ module Template
6
+ module Renderer
7
+ module V1
8
+ class TemplateFile < OpenStruct
9
+ # Initialises the TemplateFile object with the path to the template file
10
+ # and the data to be used when rendering the template.
11
+ #
12
+ # @param template_file [String] The path on disk to the template file.
13
+ # @param data [Hash{Symbol => Object}] The data that should be provided to
14
+ # the template when rendering.
15
+ # @option data [Object] :configs The value of this key will be provided to
16
+ # the template as an instance variable `@configs` in order to maintain
17
+ # compatibility with modulesync.
18
+ #
19
+ # @api public
20
+ def initialize(template_file, data = {})
21
+ @template_file = template_file
22
+
23
+ if data.key?(:configs)
24
+ @configs = data[:configs]
25
+ end
26
+
27
+ super(data)
28
+ end
29
+
30
+ # Renders the template by calling the appropriate engine based on the file
31
+ # extension.
32
+ #
33
+ # If the template has an `.erb` extension, the content of the template
34
+ # file will be treated as an ERB template. All other extensions are treated
35
+ # as plain text.
36
+ #
37
+ # @return [String] The rendered template
38
+ #
39
+ # @raise (see #template_content)
40
+ #
41
+ # @api public
42
+ def render
43
+ case File.extname(@template_file)
44
+ when '.erb'
45
+ render_erb
46
+ else
47
+ render_plain
48
+ end
49
+ end
50
+
51
+ def config_for(path)
52
+ return unless respond_to?(:template_dir)
53
+
54
+ template_dir.config_for(path)
55
+ end
56
+
57
+ private
58
+
59
+ # Reads the content of the template file into memory.
60
+ #
61
+ # @return [String] The content of the template file.
62
+ #
63
+ # @raise [ArgumentError] If the template file does not exist or can not be
64
+ # read.
65
+ #
66
+ # @api private
67
+ def template_content
68
+ if PDK::Util::Filesystem.file?(@template_file) && PDK::Util::Filesystem.readable?(@template_file)
69
+ return PDK::Util::Filesystem.read_file(@template_file)
70
+ end
71
+
72
+ raise ArgumentError, _("'%{template}' is not a readable file") % { template: @template_file }
73
+ end
74
+
75
+ # Renders the content of the template file as an ERB template.
76
+ #
77
+ # @return [String] The rendered template.
78
+ #
79
+ # @raise (see #template_content)
80
+ #
81
+ # @api private
82
+ def render_erb
83
+ renderer = ERB.new(template_content, nil, '-')
84
+ renderer.filename = @template_file
85
+ renderer.result(binding)
86
+ end
87
+
88
+ # Renders the content of the template file as plain text.
89
+ #
90
+ # @return [String] The rendered template.
91
+ #
92
+ # @raise (see #template_content)
93
+ #
94
+ # @api private
95
+ def render_plain
96
+ template_content
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,67 @@
1
+ require 'pdk'
2
+ require 'forwardable'
3
+
4
+ module PDK
5
+ module Template
6
+ # A helper class representing an already fetched template on disk, with an appropriate renderer instance.
7
+ # @see PDK::Template.with
8
+ class TemplateDir
9
+ # Creates an instance of TemplateDir object
10
+ # @see TemplateDir.new
11
+ def self.instance(uri, path, context, renderer = nil)
12
+ new(uri, path, context, renderer)
13
+ end
14
+
15
+ extend Forwardable
16
+
17
+ # Helper methods for rendering
18
+ def_delegators :@renderer, :render, :render_single_item, :has_single_item?
19
+
20
+ # @return [PDK::Util::TemplateURI] The URI which points to the source location of the Template
21
+ attr_accessor :uri
22
+
23
+ # @return [String] The path to where the template exists on disk
24
+ attr_accessor :path
25
+
26
+ # @return [Hash{String => String}] A hash of information about the template
27
+ attr_accessor :metadata
28
+
29
+ # @param template_uri [PDK::Util::TemplateUri] A URI which points to the source location of the Template
30
+ # @param path [String] The path to where the template exists on disk
31
+ # @param context [PDK::Context] The context in which the redering will occur in
32
+ # @param renderer [PDK::Template::Renderer::AbstractRenderer] The an instance of a rendering class. If nil, a renderer will be created that's appropriate for the template and context
33
+ def initialize(uri, path, context, renderer = nil)
34
+ @uri = uri
35
+ @path = path
36
+ @metadata = {}
37
+
38
+ @renderer = renderer.nil? ? Renderer.instance(uri, path, context) : renderer
39
+ raise _('Could not find a compatible template renderer for %{path}') % { path: path } if @renderer.nil?
40
+ end
41
+
42
+ # Later additions may include Control Repo rendering, for example
43
+ #
44
+ # def render_control_repo(name, options = {})
45
+ # render(CONTROL_REPO_TEMPLATE_TYPE, name, options.merge(include_first_time: false)) { |*args| yield(*args) }
46
+ # end
47
+ #
48
+ # def render_new_control_repo(name, repo_metadata = {}, options = {})
49
+ # render(CONTROL_REPO_TEMPLATE_TYPE, name, options.merge(include_first_time: true, control_repo_metadata: repo_metadata)) { |*args| yield(*args) }
50
+ # end
51
+ #:nocov: These are just helper methods and are tested elsewhere.
52
+
53
+ # Render an existing module
54
+ # @see PDK::Template::Renderer::AbstractRenderer.render
55
+ def render_module(module_name, options = {})
56
+ @renderer.render(MODULE_TEMPLATE_TYPE, module_name, options.merge(include_first_time: false)) { |*args| yield(*args) }
57
+ end
58
+
59
+ # Render a new module
60
+ # @see PDK::Template::Renderer::AbstractRenderer.render
61
+ def render_new_module(module_name, module_metadata = {}, options = {})
62
+ @renderer.render(MODULE_TEMPLATE_TYPE, module_name, options.merge(include_first_time: true, module_metadata: module_metadata)) { |*args| yield(*args) }
63
+ end
64
+ #:nocov:
65
+ end
66
+ end
67
+ end
@@ -89,6 +89,11 @@ module PDK
89
89
  setup
90
90
 
91
91
  tests = options[:tests]
92
+ # Due to how rake handles paths in the command line options, any backslashed path (Windows platforms) needs to be converted
93
+ # to forward slash. We can't use File.expand_path as the files aren't guaranteed to be on-disk
94
+ #
95
+ # Ref - https://github.com/puppetlabs/pdk/issues/828
96
+ tests = tests.tr('\\', '/') unless tests.nil?
92
97
 
93
98
  environment = { 'CI_SPEC_OPTIONS' => '--format j' }
94
99
  environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
@@ -134,7 +139,7 @@ module PDK
134
139
 
135
140
  example_results = {
136
141
  # Only possibilities are passed, failed, pending:
137
- # https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/example.rb#L548
142
+ # https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example.rb#L548
138
143
  'passed' => [],
139
144
  'failed' => [],
140
145
  'pending' => [],
@@ -178,6 +183,8 @@ module PDK
178
183
  end
179
184
 
180
185
  def self.merge_json_results(json_data)
186
+ require 'set'
187
+
181
188
  merged_json_result = {}
182
189
 
183
190
  # Merge messages
data/lib/pdk/util.rb CHANGED
@@ -14,6 +14,7 @@ module PDK
14
14
  autoload :Env, 'pdk/util/env'
15
15
  autoload :Filesystem, 'pdk/util/filesystem'
16
16
  autoload :Git, 'pdk/util/git'
17
+ autoload :JSONFinder, 'pdk/util/json_finder'
17
18
  autoload :PuppetStrings, 'pdk/util/puppet_strings'
18
19
  autoload :PuppetVersion, 'pdk/util/puppet_version'
19
20
  autoload :RubyVersion, 'pdk/util/ruby_version'
@@ -148,7 +149,7 @@ module PDK
148
149
 
149
150
  def system_configdir
150
151
  return @system_configdir unless @system_configdir.nil?
151
- return @system_configdir = File.join('opt', 'puppetlabs', 'pdk', 'config') unless Gem.win_platform?
152
+ return @system_configdir = File.join(File::SEPARATOR, 'opt', 'puppetlabs', 'pdk', 'config') unless Gem.win_platform?
152
153
 
153
154
  return @system_configdir = File.join(PDK::Util::Env['ProgramData'], 'PuppetLabs', 'PDK') unless PDK::Util::Env['ProgramData'].nil?
154
155
  @system_configdir = File.join(PDK::Util::Env['AllUsersProfile'], 'PuppetLabs', 'PDK')
@@ -196,7 +197,7 @@ module PDK
196
197
  # @return [Hash, nil] subset of text as Hash of first valid JSON found, or nil if no valid
197
198
  # JSON found in the text
198
199
  def find_first_json_in(text)
199
- find_valid_json_in(text)
200
+ find_all_json_in(text).first
200
201
  end
201
202
  module_function :find_first_json_in
202
203
 
@@ -206,42 +207,10 @@ module PDK
206
207
  # @return [Array<Hash>] subset of text as Array of all JSON object found, empty Array if none are found
207
208
  # JSON found in the text
208
209
  def find_all_json_in(text)
209
- find_valid_json_in(text, break_on_first: false)
210
+ PDK::Util::JSONFinder.new(text).objects
210
211
  end
211
212
  module_function :find_all_json_in
212
213
 
213
- # Iterate through possible JSON documents until we find one that is valid.
214
- #
215
- # @param [String] text the text in which to find a JSON document
216
- # @param [Hash] opts options
217
- # @option opts [Boolean] :break_on_first Whether or not to break after valid JSON is found, defaults to true
218
- #
219
- # @return [Hash, Array<Hash>, nil] subset of text as Hash of first valid JSON found, array of all valid JSON found, or nil if no valid
220
- # JSON found in the text
221
- #
222
- # @private
223
- def find_valid_json_in(text, opts = {})
224
- break_on_first = opts.key?(:break_on_first) ? opts[:break_on_first] : true
225
-
226
- json_result = break_on_first ? nil : []
227
-
228
- text.scan(%r{\{(?:[^{}]|(?:\g<0>))*\}}x) do |str|
229
- begin
230
- if break_on_first
231
- json_result = JSON.parse(str)
232
- break
233
- else
234
- json_result.push(JSON.parse(str))
235
- end
236
- rescue JSON::ParserError
237
- next
238
- end
239
- end
240
-
241
- json_result
242
- end
243
- module_function :find_valid_json_in
244
-
245
214
  # Returns the targets' paths relative to the working directory
246
215
  #
247
216
  # @return [Array<String>] The absolute or path to the target
@@ -44,7 +44,7 @@ module PDK
44
44
  # If there are missing dependencies after updating the lockfile, let `bundle install`
45
45
  # go out and get them. If the specified puppet gem version points to a remote location
46
46
  # or local filepath, then run bundle install as well.
47
- if !bundle.installed? || (gem_overrides[:puppet] && gem_overrides[:puppet].start_with?('file://', 'git://', 'https://'))
47
+ if !bundle.installed?(gem_overrides) || (gem_overrides[:puppet] && gem_overrides[:puppet].start_with?('file://', 'git://', 'https://'))
48
48
  bundle.install!(gem_overrides)
49
49
  end
50
50
 
@@ -9,11 +9,15 @@ module PDK
9
9
 
10
10
  # Raises if the github_changelog_generator is not available
11
11
  def self.github_changelog_generator_available!
12
- require 'bundler'
13
- return if ::Bundler.rubygems.find_name(GEM).any?
12
+ check_command = PDK::CLI::Exec::InteractiveCommand.new(PDK::CLI::Exec.bundle_bin, 'show', 'github_changelog_generator')
13
+ check_command.context = :module
14
+
15
+ result = check_command.execute!
16
+
17
+ return if result[:exit_code].zero?
14
18
 
15
19
  raise PDK::CLI::ExitWithError, _(
16
- 'Unable to generate the changelog as the %{gem} gem is not installed',
20
+ 'Unable to generate the changelog as the %{gem} gem is not included in this module\'s Gemfile',
17
21
  ) % { gem: GEM }
18
22
  end
19
23
 
@@ -106,6 +110,19 @@ module PDK
106
110
  version.join('.')
107
111
  end
108
112
 
113
+ # Returns the top most version from the CHANGELOG file
114
+ def self.latest_version
115
+ latest = nil
116
+ changelog_content.each_line do |line|
117
+ line.strip!
118
+ if line.start_with?('## [')
119
+ latest = line[line.index('[') + 1..line.index(']') - 1].delete('v')
120
+ break # stops after the top version is extracted
121
+ end
122
+ end
123
+ latest
124
+ end
125
+
109
126
  def self.changelog_file
110
127
  # Default Changelog file is CHANGELOG.md, but also search for the .MD prefix as well.
111
128
  @changelog_file ||= ['CHANGELOG.md', 'CHANGELOG.MD'].map { |file| PDK::Util::Filesystem.expand_path(file) }.find { |path| PDK::Util::Filesystem.file?(path) }