pdk 1.17.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
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) }