pdk 1.9.0 → 3.2.0

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 (163) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +744 -711
  3. data/README.md +23 -21
  4. data/lib/pdk/answer_file.rb +3 -112
  5. data/lib/pdk/bolt.rb +20 -0
  6. data/lib/pdk/cli/build.rb +51 -54
  7. data/lib/pdk/cli/bundle.rb +33 -29
  8. data/lib/pdk/cli/console.rb +148 -0
  9. data/lib/pdk/cli/convert.rb +46 -37
  10. data/lib/pdk/cli/env.rb +51 -0
  11. data/lib/pdk/cli/errors.rb +4 -3
  12. data/lib/pdk/cli/exec/command.rb +285 -0
  13. data/lib/pdk/cli/exec/interactive_command.rb +109 -0
  14. data/lib/pdk/cli/exec.rb +32 -201
  15. data/lib/pdk/cli/exec_group.rb +79 -43
  16. data/lib/pdk/cli/get/config.rb +26 -0
  17. data/lib/pdk/cli/get.rb +22 -0
  18. data/lib/pdk/cli/new/class.rb +20 -22
  19. data/lib/pdk/cli/new/defined_type.rb +21 -21
  20. data/lib/pdk/cli/new/fact.rb +27 -0
  21. data/lib/pdk/cli/new/function.rb +27 -0
  22. data/lib/pdk/cli/new/module.rb +40 -29
  23. data/lib/pdk/cli/new/provider.rb +18 -18
  24. data/lib/pdk/cli/new/task.rb +23 -22
  25. data/lib/pdk/cli/new/test.rb +52 -0
  26. data/lib/pdk/cli/new/transport.rb +27 -0
  27. data/lib/pdk/cli/new.rb +15 -9
  28. data/lib/pdk/cli/release/prep.rb +39 -0
  29. data/lib/pdk/cli/release/publish.rb +46 -0
  30. data/lib/pdk/cli/release.rb +185 -0
  31. data/lib/pdk/cli/remove/config.rb +83 -0
  32. data/lib/pdk/cli/remove.rb +22 -0
  33. data/lib/pdk/cli/set/config.rb +121 -0
  34. data/lib/pdk/cli/set.rb +22 -0
  35. data/lib/pdk/cli/test/unit.rb +71 -69
  36. data/lib/pdk/cli/test.rb +9 -8
  37. data/lib/pdk/cli/update.rb +38 -21
  38. data/lib/pdk/cli/util/command_redirector.rb +13 -3
  39. data/lib/pdk/cli/util/interview.rb +25 -9
  40. data/lib/pdk/cli/util/option_normalizer.rb +6 -6
  41. data/lib/pdk/cli/util/option_validator.rb +19 -9
  42. data/lib/pdk/cli/util/spinner.rb +13 -0
  43. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  44. data/lib/pdk/cli/util.rb +105 -48
  45. data/lib/pdk/cli/validate.rb +96 -111
  46. data/lib/pdk/cli.rb +134 -87
  47. data/lib/pdk/config/errors.rb +5 -0
  48. data/lib/pdk/config/ini_file.rb +184 -0
  49. data/lib/pdk/config/ini_file_setting.rb +35 -0
  50. data/lib/pdk/config/json.rb +35 -0
  51. data/lib/pdk/config/json_schema_namespace.rb +137 -0
  52. data/lib/pdk/config/json_schema_setting.rb +51 -0
  53. data/lib/pdk/config/json_with_schema.rb +47 -0
  54. data/lib/pdk/config/namespace.rb +362 -0
  55. data/lib/pdk/config/setting.rb +134 -0
  56. data/lib/pdk/config/task_schema.json +116 -0
  57. data/lib/pdk/config/validator.rb +31 -0
  58. data/lib/pdk/config/yaml.rb +41 -0
  59. data/lib/pdk/config/yaml_with_schema.rb +51 -0
  60. data/lib/pdk/config.rb +304 -0
  61. data/lib/pdk/context/control_repo.rb +61 -0
  62. data/lib/pdk/context/module.rb +28 -0
  63. data/lib/pdk/context/none.rb +22 -0
  64. data/lib/pdk/context.rb +98 -0
  65. data/lib/pdk/control_repo.rb +89 -0
  66. data/lib/pdk/generate/defined_type.rb +27 -33
  67. data/lib/pdk/generate/fact.rb +26 -0
  68. data/lib/pdk/generate/function.rb +49 -0
  69. data/lib/pdk/generate/module.rb +160 -153
  70. data/lib/pdk/generate/provider.rb +16 -69
  71. data/lib/pdk/generate/puppet_class.rb +27 -32
  72. data/lib/pdk/generate/puppet_object.rb +100 -159
  73. data/lib/pdk/generate/task.rb +34 -51
  74. data/lib/pdk/generate/transport.rb +34 -0
  75. data/lib/pdk/generate.rb +21 -8
  76. data/lib/pdk/logger.rb +24 -6
  77. data/lib/pdk/module/build.rb +125 -37
  78. data/lib/pdk/module/convert.rb +146 -65
  79. data/lib/pdk/module/metadata.rb +72 -71
  80. data/lib/pdk/module/release.rb +255 -0
  81. data/lib/pdk/module/update.rb +48 -37
  82. data/lib/pdk/module/update_manager.rb +75 -39
  83. data/lib/pdk/module.rb +10 -2
  84. data/lib/pdk/monkey_patches.rb +268 -0
  85. data/lib/pdk/report/event.rb +36 -48
  86. data/lib/pdk/report.rb +35 -22
  87. data/lib/pdk/template/fetcher/git.rb +84 -0
  88. data/lib/pdk/template/fetcher/local.rb +29 -0
  89. data/lib/pdk/template/fetcher.rb +100 -0
  90. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +108 -0
  91. data/lib/pdk/template/renderer/v1/renderer.rb +131 -0
  92. data/lib/pdk/template/renderer/v1/template_file.rb +100 -0
  93. data/lib/pdk/template/renderer/v1.rb +25 -0
  94. data/lib/pdk/template/renderer.rb +97 -0
  95. data/lib/pdk/template/template_dir.rb +67 -0
  96. data/lib/pdk/template.rb +52 -0
  97. data/lib/pdk/tests/unit.rb +101 -51
  98. data/lib/pdk/util/bundler.rb +44 -42
  99. data/lib/pdk/util/changelog_generator.rb +138 -0
  100. data/lib/pdk/util/env.rb +48 -0
  101. data/lib/pdk/util/filesystem.rb +139 -2
  102. data/lib/pdk/util/git.rb +108 -8
  103. data/lib/pdk/util/json_finder.rb +86 -0
  104. data/lib/pdk/util/puppet_strings.rb +125 -0
  105. data/lib/pdk/util/puppet_version.rb +71 -87
  106. data/lib/pdk/util/ruby_version.rb +49 -25
  107. data/lib/pdk/util/template_uri.rb +283 -0
  108. data/lib/pdk/util/vendored_file.rb +34 -42
  109. data/lib/pdk/util/version.rb +11 -10
  110. data/lib/pdk/util/windows/api_types.rb +74 -44
  111. data/lib/pdk/util/windows/file.rb +31 -27
  112. data/lib/pdk/util/windows/process.rb +74 -0
  113. data/lib/pdk/util/windows/string.rb +19 -12
  114. data/lib/pdk/util/windows.rb +2 -0
  115. data/lib/pdk/util.rb +111 -124
  116. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  117. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  118. data/lib/pdk/validate/external_command_validator.rb +213 -0
  119. data/lib/pdk/validate/internal_ruby_validator.rb +101 -0
  120. data/lib/pdk/validate/invokable_validator.rb +238 -0
  121. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +84 -0
  122. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +76 -0
  123. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
  124. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +131 -0
  125. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
  126. data/lib/pdk/validate/puppet/puppet_plan_syntax_validator.rb +38 -0
  127. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +135 -0
  128. data/lib/pdk/validate/puppet/puppet_validator_group.rb +22 -0
  129. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +79 -0
  130. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
  131. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +83 -0
  132. data/lib/pdk/validate/tasks/tasks_name_validator.rb +45 -0
  133. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
  134. data/lib/pdk/validate/validator.rb +120 -0
  135. data/lib/pdk/validate/validator_group.rb +107 -0
  136. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +86 -0
  137. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
  138. data/lib/pdk/validate.rb +86 -12
  139. data/lib/pdk/version.rb +2 -2
  140. data/lib/pdk.rb +60 -10
  141. metadata +138 -100
  142. data/lib/pdk/cli/module/build.rb +0 -14
  143. data/lib/pdk/cli/module/generate.rb +0 -45
  144. data/lib/pdk/cli/module.rb +0 -14
  145. data/lib/pdk/i18n.rb +0 -4
  146. data/lib/pdk/module/templatedir.rb +0 -321
  147. data/lib/pdk/template_file.rb +0 -95
  148. data/lib/pdk/validate/base_validator.rb +0 -215
  149. data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -86
  150. data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -109
  151. data/lib/pdk/validate/metadata_validator.rb +0 -30
  152. data/lib/pdk/validate/puppet/puppet_lint.rb +0 -67
  153. data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -112
  154. data/lib/pdk/validate/puppet_validator.rb +0 -30
  155. data/lib/pdk/validate/ruby/rubocop.rb +0 -77
  156. data/lib/pdk/validate/ruby_validator.rb +0 -29
  157. data/lib/pdk/validate/tasks/metadata_lint.rb +0 -126
  158. data/lib/pdk/validate/tasks/name.rb +0 -88
  159. data/lib/pdk/validate/tasks_validator.rb +0 -33
  160. data/lib/pdk/validate/yaml/syntax.rb +0 -109
  161. data/lib/pdk/validate/yaml_validator.rb +0 -31
  162. data/locales/config.yaml +0 -21
  163. data/locales/pdk.pot +0 -1291
@@ -1,10 +1,4 @@
1
- require 'fileutils'
2
- require 'minitar'
3
- require 'zlib'
4
- require 'pathspec'
5
- require 'find'
6
- require 'pdk/module'
7
- require 'pdk/tests/unit'
1
+ require 'pdk'
8
2
 
9
3
  module PDK
10
4
  module Module
@@ -13,12 +7,11 @@ module PDK
13
7
  new(options).build
14
8
  end
15
9
 
16
- attr_reader :module_dir
17
- attr_reader :target_dir
10
+ attr_reader :module_dir, :target_dir
18
11
 
19
12
  def initialize(options = {})
20
- @module_dir = File.expand_path(options[:module_dir] || Dir.pwd)
21
- @target_dir = File.expand_path(options[:'target-dir'] || File.join(module_dir, 'pkg'))
13
+ @module_dir = PDK::Util::Filesystem.expand_path(options[:module_dir] || Dir.pwd)
14
+ @target_dir = PDK::Util::Filesystem.expand_path(options[:'target-dir'] || File.join(module_dir, 'pkg'))
22
15
  end
23
16
 
24
17
  # Read and parse the values from metadata.json for the module that is
@@ -26,6 +19,8 @@ module PDK
26
19
  #
27
20
  # @return [Hash{String => Object}] The hash of metadata values.
28
21
  def metadata
22
+ require 'pdk/module/metadata'
23
+
29
24
  @metadata ||= PDK::Module::Metadata.from_file(File.join(module_dir, 'metadata.json')).data
30
25
  end
31
26
 
@@ -51,7 +46,7 @@ module PDK
51
46
  # Verify if there is an existing package in the target directory and prompts
52
47
  # the user if they want to overwrite it.
53
48
  def package_already_exists?
54
- File.exist? package_file
49
+ PDK::Util::Filesystem.exist?(package_file)
55
50
  end
56
51
 
57
52
  # Check if the module is PDK Compatible. If not, then prompt the user if
@@ -73,14 +68,14 @@ module PDK
73
68
  def create_build_dir
74
69
  cleanup_build_dir
75
70
 
76
- FileUtils.mkdir_p(build_dir)
71
+ PDK::Util::Filesystem.mkdir_p(build_dir)
77
72
  end
78
73
 
79
74
  # Remove the temporary build directory and all its contents from disk.
80
75
  #
81
76
  # @return nil.
82
77
  def cleanup_build_dir
83
- FileUtils.rm_rf(build_dir, secure: true)
78
+ PDK::Util::Filesystem.rm_rf(build_dir, secure: true)
84
79
  end
85
80
 
86
81
  # Combine the module name and version into a Forge-compatible dash
@@ -90,7 +85,7 @@ module PDK
90
85
  def release_name
91
86
  @release_name ||= [
92
87
  metadata['name'],
93
- metadata['version'],
88
+ metadata['version']
94
89
  ].join('-')
95
90
  end
96
91
 
@@ -99,6 +94,8 @@ module PDK
99
94
  #
100
95
  # @return nil
101
96
  def stage_module_in_build_dir
97
+ require 'find'
98
+
102
99
  Find.find(module_dir) do |path|
103
100
  next if path == module_dir
104
101
 
@@ -112,16 +109,24 @@ module PDK
112
109
  #
113
110
  # @return nil.
114
111
  def stage_path(path)
112
+ require 'pathname'
113
+
115
114
  relative_path = Pathname.new(path).relative_path_from(Pathname.new(module_dir))
116
115
  dest_path = File.join(build_dir, relative_path)
117
116
 
118
- if File.directory?(path)
119
- FileUtils.mkdir_p(dest_path, mode: File.stat(path).mode)
120
- elsif File.symlink?(path)
117
+ validate_path_encoding!(relative_path.to_path)
118
+
119
+ if PDK::Util::Filesystem.directory?(path)
120
+ PDK::Util::Filesystem.mkdir_p(dest_path, mode: PDK::Util::Filesystem.stat(path).mode)
121
+ elsif PDK::Util::Filesystem.symlink?(path)
121
122
  warn_symlink(path)
122
123
  else
123
- FileUtils.cp(path, dest_path, preserve: true)
124
+ validate_ustar_path!(relative_path.to_path)
125
+ PDK::Util::Filesystem.cp(path, dest_path, preserve: true)
124
126
  end
127
+ rescue ArgumentError => e
128
+ raise PDK::CLI::ExitWithError, format('%{message} Rename the file or exclude it from the package ' \
129
+ 'by adding it to the .pdkignore file in your module.', message: e.message)
125
130
  end
126
131
 
127
132
  # Check if the given path matches one of the patterns listed in the
@@ -131,7 +136,7 @@ module PDK
131
136
  #
132
137
  # @return [Boolean] true if the path matches and should be ignored.
133
138
  def ignored_path?(path)
134
- path = path.to_s + '/' if File.directory?(path)
139
+ path = "#{path}/" if PDK::Util::Filesystem.directory?(path)
135
140
 
136
141
  !ignored_files.match_paths([path], module_dir).empty?
137
142
  end
@@ -143,13 +148,80 @@ module PDK
143
148
  #
144
149
  # @return nil.
145
150
  def warn_symlink(path)
151
+ require 'pathname'
152
+
146
153
  symlink_path = Pathname.new(path)
147
154
  module_path = Pathname.new(module_dir)
148
155
 
149
- PDK.logger.warn _('Symlinks in modules are not supported and will not be included in the package. Please investigate symlink %{from} -> %{to}.') % {
150
- from: symlink_path.relative_path_from(module_path),
151
- to: symlink_path.realpath.relative_path_from(module_path),
152
- }
156
+ PDK.logger.warn format('Symlinks in modules are not supported and will not be included in the package. Please investigate symlink %{from} -> %{to}.',
157
+ from: symlink_path.relative_path_from(module_path), to: symlink_path.realpath.relative_path_from(module_path))
158
+ end
159
+
160
+ # Checks if the path length will fit into the POSIX.1-1998 (ustar) tar
161
+ # header format.
162
+ #
163
+ # POSIX.1-2001 (which allows paths of infinite length) was adopted by GNU
164
+ # tar in 2004 and is supported by minitar 0.7 and above. Unfortunately
165
+ # much of the Puppet ecosystem still uses minitar 0.6.1.
166
+ #
167
+ # POSIX.1-1998 tar format does not allow for paths greater than 256 bytes,
168
+ # or paths that can't be split into a prefix of 155 bytes (max) and
169
+ # a suffix of 100 bytes (max).
170
+ #
171
+ # This logic was pretty much copied from the private method
172
+ # {Archive::Tar::Minitar::Writer#split_name}.
173
+ #
174
+ # @param path [String] the relative path to be added to the tar file.
175
+ #
176
+ # @raise [ArgumentError] if the path is too long or could not be split.
177
+ #
178
+ # @return [nil]
179
+ def validate_ustar_path!(path)
180
+ raise ArgumentError, format("The path '%{path}' is longer than 256 bytes.", path: path) if path.bytesize > 256
181
+
182
+ if path.bytesize <= 100
183
+ prefix = ''
184
+ else
185
+ parts = path.split(File::SEPARATOR)
186
+ newpath = parts.pop
187
+ nxt = ''
188
+
189
+ loop do
190
+ nxt = parts.pop || ''
191
+ break if newpath.bytesize + 1 + nxt.bytesize >= 100
192
+
193
+ newpath = File.join(nxt, newpath)
194
+ end
195
+
196
+ prefix = File.join(*parts, nxt)
197
+ path = newpath
198
+ end
199
+
200
+ return unless path.bytesize > 100 || prefix.bytesize > 155
201
+
202
+ raise ArgumentError,
203
+ format("'%{path}' could not be split at a directory separator into two " \
204
+ 'parts, the first having a maximum length of 155 bytes and the ' \
205
+ 'second having a maximum length of 100 bytes.', path: path)
206
+ end
207
+
208
+ # Checks if the path contains any non-ASCII characters.
209
+ #
210
+ # Java will throw an error when it encounters a path containing
211
+ # characters that are not supported by the hosts locale. In order to
212
+ # maximise compatibility we limit the paths to contain only ASCII
213
+ # characters, which should be part of any locale character set.
214
+ #
215
+ # @param path [String] the relative path to be added to the tar file.
216
+ #
217
+ # @raise [ArgumentError] if the path contains non-ASCII characters.
218
+ #
219
+ # @return [nil]
220
+ def validate_path_encoding!(path)
221
+ return unless /[^\x00-\x7F]/.match?(path)
222
+
223
+ raise ArgumentError, format("'%{path}' can only include ASCII characters in its path or " \
224
+ 'filename in order to be compatible with a wide range of hosts.', path: path)
153
225
  end
154
226
 
155
227
  # Creates a gzip compressed tarball of the build directory.
@@ -159,12 +231,31 @@ module PDK
159
231
  #
160
232
  # @return nil.
161
233
  def build_package
162
- FileUtils.rm_f(package_file)
234
+ require 'zlib'
235
+ require 'minitar'
236
+ require 'find'
237
+
238
+ PDK::Util::Filesystem.rm_f(package_file)
163
239
 
164
240
  Dir.chdir(target_dir) do
165
- Zlib::GzipWriter.open(package_file) do |package_fd|
166
- Minitar.pack(release_name, package_fd)
241
+ gz = Zlib::GzipWriter.new(File.open(package_file, 'wb')) # rubocop:disable PDK/FileOpen
242
+ tar = Minitar::Output.new(gz)
243
+ Find.find(release_name) do |entry|
244
+ entry_meta = {
245
+ name: entry
246
+ }
247
+
248
+ orig_mode = PDK::Util::Filesystem.stat(entry).mode
249
+ min_mode = Minitar.dir?(entry) ? 0o755 : 0o644
250
+
251
+ entry_meta[:mode] = orig_mode | min_mode
252
+
253
+ PDK.logger.debug(format('Updated permissions of packaged \'%{entry}\' to %{new_mode}', entry: entry, new_mode: (entry_meta[:mode] & 0o7777).to_s(8))) if entry_meta[:mode] != orig_mode
254
+
255
+ Minitar.pack_file(entry_meta, tar)
167
256
  end
257
+ ensure
258
+ tar.close
168
259
  end
169
260
  end
170
261
 
@@ -179,8 +270,8 @@ module PDK
179
270
  @ignore_file ||= [
180
271
  File.join(module_dir, '.pdkignore'),
181
272
  File.join(module_dir, '.pmtignore'),
182
- File.join(module_dir, '.gitignore'),
183
- ].find { |file| File.file?(file) && File.readable?(file) }
273
+ File.join(module_dir, '.gitignore')
274
+ ].find { |file| PDK::Util::Filesystem.file?(file) && PDK::Util::Filesystem.readable?(file) }
184
275
  end
185
276
 
186
277
  # Instantiate a new PathSpec class and populate it with the pattern(s) of
@@ -188,21 +279,18 @@ module PDK
188
279
  #
189
280
  # @return [PathSpec] The populated ignore path matcher.
190
281
  def ignored_files
282
+ require 'pdk/module'
283
+ require 'pathspec'
284
+
191
285
  @ignored_files ||=
192
286
  begin
193
287
  ignored = if ignore_file.nil?
194
288
  PathSpec.new
195
289
  else
196
- fd = File.open(ignore_file, 'rb:UTF-8')
197
- data = fd.read
198
- fd.close
199
-
200
- PathSpec.new(data)
290
+ PathSpec.new(PDK::Util::Filesystem.read_file(ignore_file, open_args: 'rb:UTF-8'))
201
291
  end
202
292
 
203
- if File.realdirpath(target_dir).start_with?(File.realdirpath(module_dir))
204
- ignored = ignored.add("\/#{File.basename(target_dir)}\/")
205
- end
293
+ ignored = ignored.add("/#{File.basename(target_dir)}/") if File.realdirpath(target_dir).start_with?(File.realdirpath(module_dir))
206
294
 
207
295
  PDK::Module::DEFAULT_IGNORED.each { |r| ignored.add(r) }
208
296
 
@@ -1,26 +1,36 @@
1
- require 'pdk/generate/module'
2
- require 'pdk/module/update_manager'
3
- require 'pdk/util'
4
- require 'pdk/report'
1
+ require 'pdk'
5
2
 
6
3
  module PDK
7
4
  module Module
8
5
  class Convert
9
- def self.invoke(options)
10
- new(options).run
6
+ def self.invoke(module_dir, options)
7
+ new(module_dir, options).run
11
8
  end
12
9
 
13
- attr_reader :options
10
+ attr_reader :module_dir, :options
14
11
 
15
- def initialize(options = {})
12
+ def initialize(module_dir, options = {})
13
+ @module_dir = module_dir
16
14
  @options = options
17
15
  end
18
16
 
17
+ def convert?
18
+ instance_of?(PDK::Module::Convert)
19
+ end
20
+
19
21
  def run
20
22
  stage_changes!
21
23
 
22
24
  unless update_manager.changes?
23
- PDK::Report.default_target.puts(_('No changes required.'))
25
+ if adding_tests?
26
+ add_tests!
27
+ print_result 'Convert completed'
28
+ else
29
+ require 'pdk/report'
30
+
31
+ PDK::Report.default_target.puts('No changes required.')
32
+ end
33
+
24
34
  return
25
35
  end
26
36
 
@@ -31,24 +41,26 @@ module PDK
31
41
  return if noop?
32
42
 
33
43
  unless force?
34
- PDK.logger.info _(
35
- 'Module conversion is a potentially destructive action. ' \
36
- 'Ensure that you have committed your module to a version control ' \
37
- 'system or have a backup, and review the changes above before continuing.',
38
- )
39
- continue = PDK::CLI::Util.prompt_for_yes(_('Do you want to continue and make these changes to your module?'))
44
+ require 'pdk/cli/util'
45
+
46
+ PDK.logger.info 'Module conversion is a potentially destructive action. ' \
47
+ 'Ensure that you have committed your module to a version control ' \
48
+ 'system or have a backup, and review the changes above before continuing.'
49
+ continue = PDK::CLI::Util.prompt_for_yes('Do you want to continue and make these changes to your module?')
40
50
  return unless continue
41
51
  end
42
52
 
43
- # Remove these files straight away as these changes are not something that the user needs to review.
44
- if needs_bundle_update?
45
- update_manager.unlink_file('Gemfile.lock')
46
- update_manager.unlink_file(File.join('.bundle', 'config'))
47
- end
53
+ # Remove these files straight away as these changes are not something
54
+ # that the user needs to review.
55
+ update_manager.unlink_file('Gemfile.lock')
56
+ update_manager.unlink_file(File.join('.bundle', 'config'))
48
57
 
49
58
  update_manager.sync_changes!
50
59
 
51
- PDK::Util::Bundler.ensure_bundle! if needs_bundle_update?
60
+ require 'pdk/util/bundler'
61
+ PDK::Util::Bundler.ensure_bundle!
62
+
63
+ add_tests! if adding_tests?
52
64
 
53
65
  print_result 'Convert completed'
54
66
  end
@@ -61,35 +73,100 @@ module PDK
61
73
  options[:force]
62
74
  end
63
75
 
64
- def needs_bundle_update?
65
- update_manager.changed?('Gemfile')
76
+ def add_tests?
77
+ options[:'add-tests']
78
+ end
79
+
80
+ def adding_tests?
81
+ add_tests? && missing_tests?
66
82
  end
67
83
 
68
- def stage_changes!
69
- metadata_path = 'metadata.json'
84
+ def missing_tests?
85
+ !available_test_generators.empty?
86
+ end
87
+
88
+ def available_test_generators
89
+ # Only select generators which can run and have no pre-existing files
90
+ test_generators.select do |gen|
91
+ if gen.can_run?
92
+ gen.template_files.none? { |_, dst_path| PDK::Util::Filesystem.exist?(File.join(gen.context.root_path, dst_path)) }
93
+ else
94
+ false
95
+ end
96
+ end
97
+ end
70
98
 
71
- PDK::Module::TemplateDir.new(template_url, nil, false) do |templates|
72
- new_metadata = update_metadata(metadata_path, templates.metadata)
73
- templates.module_metadata = new_metadata.data unless new_metadata.nil?
99
+ def test_generators(context = PDK.context)
100
+ return @test_generators unless @test_generators.nil?
74
101
 
102
+ require 'pdk/util/puppet_strings'
103
+
104
+ test_gens = PDK::Util::PuppetStrings.all_objects.map do |generator, objects|
105
+ (objects || []).map do |obj|
106
+ generator.new(context, obj['name'], spec_only: true)
107
+ end
108
+ end
109
+
110
+ @test_generators = test_gens.flatten
111
+ end
112
+
113
+ def stage_tests!(manager)
114
+ available_test_generators.each do |gen|
115
+ gen.stage_changes(manager)
116
+ end
117
+ manager
118
+ end
119
+
120
+ def add_tests!
121
+ update_manager.clear!
122
+ stage_tests!(update_manager)
123
+
124
+ if update_manager.changes?
125
+ update_manager.sync_changes!
126
+ print_summary
127
+ else
128
+ PDK::Report.default_target.puts('No test changes required.')
129
+ end
130
+ end
131
+
132
+ def stage_changes!(context = PDK.context)
133
+ require 'pdk/util/filesystem'
134
+
135
+ metadata_path = File.join(module_dir, 'metadata.json')
136
+
137
+ PDK::Template.with(template_uri, context) do |template_dir|
138
+ new_metadata = update_metadata(metadata_path, template_dir.metadata)
75
139
  if options[:noop] && new_metadata.nil?
76
140
  update_manager.add_file(metadata_path, '')
77
- elsif File.file?(metadata_path)
141
+ elsif PDK::Util::Filesystem.file?(metadata_path)
78
142
  update_manager.modify_file(metadata_path, new_metadata.to_json)
79
143
  else
80
144
  update_manager.add_file(metadata_path, new_metadata.to_json)
81
145
  end
82
146
 
83
- templates.render do |file_path, file_content, file_status|
84
- if file_status == :unmanage
85
- PDK.logger.debug(_("skipping '%{path}'") % { path: file_path })
86
- elsif file_status == :delete
87
- update_manager.remove_file(file_path)
88
- elsif file_status == :manage
89
- if File.exist? file_path
90
- update_manager.modify_file(file_path, file_content)
147
+ # new_metadata == nil when creating a new module but with --noop@
148
+ module_name = new_metadata.nil? ? 'new-module' : new_metadata.data['name']
149
+ metadata_for_render = new_metadata.nil? ? {} : new_metadata.data
150
+
151
+ template_dir.render_new_module(module_name, metadata_for_render) do |relative_file_path, file_content, file_status, file_executable|
152
+ absolute_file_path = File.join(module_dir, relative_file_path)
153
+ case file_status
154
+ when :unmanage
155
+ PDK.logger.debug(format("skipping '%{path}'", path: absolute_file_path))
156
+ when :delete
157
+ update_manager.remove_file(absolute_file_path)
158
+ when :init
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
163
+ when :manage
164
+ if PDK::Util::Filesystem.exist?(absolute_file_path)
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)
91
167
  else
92
- update_manager.add_file(file_path, file_content)
168
+ update_manager.add_file(absolute_file_path, file_content)
169
+ update_manager.make_file_executable(absolute_file_path) if file_executable
93
170
  end
94
171
  end
95
172
  end
@@ -99,20 +176,24 @@ module PDK
99
176
  end
100
177
 
101
178
  def update_manager
179
+ require 'pdk/module/update_manager'
180
+
102
181
  @update_manager ||= PDK::Module::UpdateManager.new
103
182
  end
104
183
 
105
- def template_url
106
- @template_url ||= options.fetch(:'template-url', PDK::Util.default_template_url)
184
+ def template_uri
185
+ require 'pdk/util/template_uri'
186
+
187
+ @template_uri ||= PDK::Util::TemplateURI.new(options)
107
188
  end
108
189
 
109
190
  def update_metadata(metadata_path, template_metadata)
110
- if File.file?(metadata_path)
111
- unless File.readable?(metadata_path)
112
- raise PDK::CLI::ExitWithError, _('Unable to update module metadata; %{path} exists but it is not readable.') % {
113
- path: metadata_path,
114
- }
115
- end
191
+ require 'pdk/generate/module'
192
+ require 'pdk/util/filesystem'
193
+ require 'pdk/module/metadata'
194
+
195
+ if PDK::Util::Filesystem.file?(metadata_path)
196
+ raise PDK::CLI::ExitWithError, format('Unable to update module metadata; %{path} exists but it is not readable.', path: metadata_path) unless PDK::Util::Filesystem.readable?(metadata_path)
116
197
 
117
198
  begin
118
199
  metadata = PDK::Module::Metadata.from_file(metadata_path)
@@ -124,12 +205,10 @@ module PDK
124
205
  rescue ArgumentError
125
206
  metadata = PDK::Generate::Module.prepare_metadata(options) unless options[:noop]
126
207
  end
127
- elsif File.exist?(metadata_path)
128
- raise PDK::CLI::ExitWithError, _('Unable to update module metadata; %{path} exists but it is not a file.') % {
129
- path: metadata_path,
130
- }
208
+ elsif PDK::Util::Filesystem.exist?(metadata_path)
209
+ raise PDK::CLI::ExitWithError, format('Unable to update module metadata; %{path} exists but it is not a file.', path: metadata_path)
131
210
  else
132
- return nil if options[:noop]
211
+ return if options[:noop]
133
212
 
134
213
  project_dir = File.basename(Dir.pwd)
135
214
  options[:module_name] = project_dir.split('-', 2).compact[-1]
@@ -163,34 +242,36 @@ module PDK
163
242
  end
164
243
 
165
244
  def print_summary
245
+ require 'pdk/report'
246
+
166
247
  footer = false
167
248
 
168
- summary.keys.each do |category|
249
+ summary.each_key do |category|
169
250
  next if summary[category].empty?
170
251
 
171
- PDK::Report.default_target.puts(_("\n%{banner}") % { banner: generate_banner("Files to be #{category}", 40) })
252
+ PDK::Report.default_target.puts(format("\n%{banner}", banner: generate_banner("Files to be #{category}", 40)))
172
253
  PDK::Report.default_target.puts(summary[category])
173
254
  footer = true
174
255
  end
175
256
 
176
- PDK::Report.default_target.puts(_("\n%{banner}") % { banner: generate_banner('', 40) }) if footer
257
+ PDK::Report.default_target.puts(format("\n%{banner}", banner: generate_banner('', 40))) if footer
177
258
  end
178
259
 
179
260
  def print_result(banner_text)
180
- PDK::Report.default_target.puts(_("\n%{banner}") % { banner: generate_banner(banner_text, 40) })
181
- summary_to_print = summary.map { |k, v| "#{v.length} files #{k}" unless v.empty? }.compact
182
- PDK::Report.default_target.puts(_("\n%{summary}\n\n") % { summary: "#{summary_to_print.join(', ')}." })
261
+ require 'pdk/report'
262
+
263
+ PDK::Report.default_target.puts(format("\n%{banner}", banner: generate_banner(banner_text, 40)))
264
+ summary_to_print = summary.filter_map { |k, v| "#{v.length} files #{k}" unless v.empty? }
265
+ PDK::Report.default_target.puts(format("\n%{summary}\n\n", summary: "#{summary_to_print.join(', ')}."))
183
266
  end
184
267
 
185
268
  def full_report(path)
186
- File.open(path, 'w') do |f|
187
- f.write("/* Report generated by PDK at #{Time.now} */")
188
- update_manager.changes[:modified].each do |_, diff|
189
- f.write("\n\n\n" + diff)
190
- end
191
- f.write("\n")
192
- end
193
- PDK::Report.default_target.puts(_("\nYou can find a report of differences in %{path}.\n\n") % { path: path })
269
+ require 'pdk/report'
270
+
271
+ report = ["/* Report generated by PDK at #{Time.now} */"]
272
+ report.concat(update_manager.changes[:modified].map { |_, diff| "\n\n\n#{diff}" })
273
+ PDK::Util::Filesystem.write_file(path, report.join)
274
+ PDK::Report.default_target.puts(format("\nYou can find a report of differences in %{path}.\n\n", path: path))
194
275
  end
195
276
 
196
277
  def generate_banner(text, width = 80)