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,5 +1,4 @@
1
- require 'rexml/document'
2
- require 'pathname'
1
+ require 'pdk'
3
2
 
4
3
  module PDK
5
4
  class Report
@@ -54,7 +53,7 @@ module PDK
54
53
  # @raise [ArgumentError] (see #sanitise_data)
55
54
  def initialize(data)
56
55
  sanitise_data(data).each do |key, value|
57
- instance_variable_set("@#{key}", value)
56
+ instance_variable_set(:"@#{key}", value)
58
57
  end
59
58
  end
60
59
 
@@ -99,7 +98,7 @@ module PDK
99
98
  # results.
100
99
  def rspec_puppet_coverage?
101
100
  @rspec_puppet_coverage_pattern ||= File.join('**', 'lib', 'rspec-puppet', 'coverage.rb')
102
- source == 'rspec' && File.fnmatch?(@rspec_puppet_coverage_pattern, File.expand_path(file))
101
+ source == 'rspec' && PDK::Util::Filesystem.fnmatch?(@rspec_puppet_coverage_pattern, PDK::Util::Filesystem.expand_path(file))
103
102
  end
104
103
 
105
104
  # Renders the event in a clang style text format.
@@ -112,8 +111,8 @@ module PDK
112
111
  location = nil if location.empty?
113
112
 
114
113
  # TODO: maybe add trace
115
- header = [severity, source, location, message].compact.join(': ')
116
114
  if source == 'rspec'
115
+ header = [severity, source, location, message].compact.join(': ')
117
116
  result = [header, " #{test}"]
118
117
  context = context_lines
119
118
  unless context.nil?
@@ -124,7 +123,13 @@ module PDK
124
123
 
125
124
  result.compact.join("\n")
126
125
  else
127
- header
126
+ output = ['pdk']
127
+ output << "(#{severity.upcase}):" unless severity.nil?
128
+ output << "#{source}:" unless source.nil?
129
+ output << message unless message.nil?
130
+ output << "(#{location})" unless location.nil?
131
+
132
+ output.join(' ')
128
133
  end
129
134
  end
130
135
 
@@ -132,6 +137,8 @@ module PDK
132
137
  #
133
138
  # @return [REXML::Element] The rendered event.
134
139
  def to_junit
140
+ require 'rexml/document'
141
+
135
142
  testcase = REXML::Element.new('testcase')
136
143
  testcase.attributes['classname'] = [source, test].compact.join('.')
137
144
  testcase.attributes['name'] = [file, line, column].compact.join(':')
@@ -187,13 +194,12 @@ module PDK
187
194
  # @raise [ArgumentError] if the value is nil, an empty String, or not
188
195
  # a String.
189
196
  def sanitise_file(value)
190
- if value.nil? || (value.is_a?(String) && value.empty?)
191
- raise ArgumentError, _('File not specified.')
192
- end
197
+ raise ArgumentError, 'File not specified.' if value.nil? || (value.is_a?(String) && value.empty?)
193
198
 
194
- unless value.is_a?(String)
195
- raise ArgumentError, _('File must be a String.')
196
- end
199
+ raise ArgumentError, 'File must be a String.' unless value.is_a?(String)
200
+
201
+ require 'pathname'
202
+ require 'pdk/util'
197
203
 
198
204
  path = Pathname.new(value)
199
205
 
@@ -224,22 +230,13 @@ module PDK
224
230
  # @raise [ArgumentError] if the value is nil, an empty String, or not
225
231
  # a String or Symbol representation of a valid state.
226
232
  def sanitise_state(value)
227
- if value.nil? || (value.is_a?(String) && value.empty?)
228
- raise ArgumentError, _('State not specified.')
229
- end
233
+ raise ArgumentError, 'State not specified.' if value.nil? || (value.is_a?(String) && value.empty?)
230
234
 
231
235
  value = value.to_sym if value.is_a?(String)
232
- unless value.is_a?(Symbol)
233
- raise ArgumentError, _('State must be a Symbol, not %{type}') % { type: value.class }
234
- end
236
+ raise ArgumentError, format('State must be a Symbol, not %{type}', type: value.class) unless value.is_a?(Symbol)
235
237
 
236
238
  valid_states = [:passed, :error, :failure, :skipped]
237
- unless valid_states.include?(value)
238
- raise ArgumentError, _('Invalid state %{state}. Valid states are: %{valid}.') % {
239
- state: value.inspect,
240
- valid: valid_states.map(&:inspect).join(', '),
241
- }
242
- end
239
+ raise ArgumentError, format('Invalid state %{state}. Valid states are: %{valid}.', state: value.inspect, valid: valid_states.map(&:inspect).join(', ')) unless valid_states.include?(value)
243
240
 
244
241
  value
245
242
  end
@@ -253,9 +250,7 @@ module PDK
253
250
  #
254
251
  # @raise [ArgumentError] if the value is nil or an empty String.
255
252
  def sanitise_source(value)
256
- if value.nil? || (value.is_a?(String) && value.empty?)
257
- raise ArgumentError, _('Source not specified.')
258
- end
253
+ raise ArgumentError, 'Source not specified.' if value.nil? || (value.is_a?(String) && value.empty?)
259
254
 
260
255
  value.to_s
261
256
  end
@@ -267,20 +262,16 @@ module PDK
267
262
  # @return [Integer] the provided value, converted into an Integer if
268
263
  # necessary.
269
264
  def sanitise_line(value)
270
- return nil if value.nil?
265
+ return if value.nil?
271
266
 
272
267
  valid_types = [String, Integer]
273
268
  if RUBY_VERSION.split('.')[0..1].join('.').to_f < 2.4
274
269
  valid_types << Fixnum # rubocop:disable Lint/UnifiedInteger
275
270
  end
276
271
 
277
- unless valid_types.include?(value.class)
278
- raise ArgumentError, _('Line must be an Integer or a String representation of an Integer.')
279
- end
272
+ raise ArgumentError, 'Line must be an Integer or a String representation of an Integer.' unless valid_types.include?(value.class)
280
273
 
281
- if value.is_a?(String) && value !~ %r{\A[0-9]+\Z}
282
- raise ArgumentError, _('The line number can contain only the digits 0-9.')
283
- end
274
+ raise ArgumentError, 'The line number can contain only the digits 0-9.' if value.is_a?(String) && value !~ /\A[0-9]+\Z/
284
275
 
285
276
  value.to_i
286
277
  end
@@ -292,20 +283,16 @@ module PDK
292
283
  # @return [Integer] the provided value, converted into an Integer if
293
284
  # necessary.
294
285
  def sanitise_column(value)
295
- return nil if value.nil?
286
+ return if value.nil?
296
287
 
297
288
  valid_types = [String, Integer]
298
289
  if RUBY_VERSION.split('.')[0..1].join('.').to_f < 2.4
299
290
  valid_types << Fixnum # rubocop:disable Lint/UnifiedInteger
300
291
  end
301
292
 
302
- unless valid_types.include?(value.class)
303
- raise ArgumentError, _('Column must be an Integer or a String representation of an Integer.')
304
- end
293
+ raise ArgumentError, 'Column must be an Integer or a String representation of an Integer.' unless valid_types.include?(value.class)
305
294
 
306
- if value.is_a?(String) && value !~ %r{\A[0-9]+\Z}
307
- raise ArgumentError, _('The column number can contain only the digits 0-9.')
308
- end
295
+ raise ArgumentError, 'The column number can contain only the digits 0-9.' if value.is_a?(String) && value !~ /\A[0-9]+\Z/
309
296
 
310
297
  value.to_i
311
298
  end
@@ -317,18 +304,16 @@ module PDK
317
304
  #
318
305
  # @return [Array] Array of stack trace lines with less relevant lines excluded
319
306
  def sanitise_trace(value)
320
- return nil if value.nil?
307
+ return if value.nil?
321
308
 
322
309
  valid_types = [Array]
323
310
 
324
- unless valid_types.include?(value.class)
325
- raise ArgumentError, _('Trace must be an Array of stack trace lines.')
326
- end
311
+ raise ArgumentError, 'Trace must be an Array of stack trace lines.' unless valid_types.include?(value.class)
327
312
 
328
313
  # Drop any stacktrace lines that include '/gems/' in the path or
329
314
  # are the original rspec binstub lines
330
315
  value.reject do |line|
331
- (line =~ %r{/gems/}) || (line =~ %r{bin/rspec:})
316
+ line.include?('/gems/') || line.include?('bin/rspec:')
332
317
  end
333
318
  end
334
319
 
@@ -342,10 +327,13 @@ module PDK
342
327
  def context_lines(max_num_lines = 5)
343
328
  return if file.nil? || line.nil?
344
329
 
345
- file_path = [file, File.join(PDK::Util.module_root, file)].find { |r| File.file?(r) }
330
+ file_path = [file, File.join(PDK::Util.module_root, file)].find do |path|
331
+ PDK::Util::Filesystem.file?(path)
332
+ end
333
+
346
334
  return if file_path.nil?
347
335
 
348
- file_content = File.read(file_path).split("\n")
336
+ file_content = PDK::Util::Filesystem.read_file(file_path).split("\n")
349
337
  delta = (max_num_lines - 1) / 2
350
338
  min = [0, (line - 1) - delta].max
351
339
  max = [(line - 1) + delta, file_content.length].min
data/lib/pdk/report.rb CHANGED
@@ -1,13 +1,12 @@
1
- require 'rexml/document'
2
- require 'time'
3
- require 'pdk/report/event'
4
- require 'socket'
1
+ require 'pdk'
5
2
 
6
3
  module PDK
7
4
  class Report
5
+ autoload :Event, 'pdk/report/event'
6
+
8
7
  # @return [Array<String>] the list of supported report formats.
9
8
  def self.formats
10
- @report_formats ||= %w[junit text].freeze
9
+ @report_formats ||= ['junit', 'text'].freeze
11
10
  end
12
11
 
13
12
  # @return [Symbol] the method name of the default report format.
@@ -48,8 +47,9 @@ module PDK
48
47
  # @param target [#write] an IO object that the report will be written to.
49
48
  # Defaults to PDK::Report.default_target.
50
49
  def write_junit(target = self.class.default_target)
51
- # Open a File Object for IO if target is a string containing a filename or path
52
- target = File.open(target, 'w') if target.is_a? String
50
+ require 'rexml/document'
51
+ require 'time'
52
+ require 'socket'
53
53
 
54
54
  document = REXML::Document.new
55
55
  document << REXML::XMLDecl.new
@@ -60,9 +60,9 @@ module PDK
60
60
  testsuite = REXML::Element.new('testsuite')
61
61
  testsuite.attributes['name'] = testsuite_name
62
62
  testsuite.attributes['tests'] = testcases.length
63
- testsuite.attributes['errors'] = testcases.select(&:error?).length
64
- testsuite.attributes['failures'] = testcases.select(&:failure?).length
65
- testsuite.attributes['skipped'] = testcases.select(&:skipped?).length
63
+ testsuite.attributes['errors'] = testcases.count(&:error?)
64
+ testsuite.attributes['failures'] = testcases.count(&:failure?)
65
+ testsuite.attributes['skipped'] = testcases.count(&:skipped?)
66
66
  testsuite.attributes['time'] = 0
67
67
  testsuite.attributes['timestamp'] = Time.now.strftime('%Y-%m-%dT%H:%M:%S')
68
68
  testsuite.attributes['hostname'] = Socket.gethostname
@@ -78,9 +78,14 @@ module PDK
78
78
  end
79
79
 
80
80
  document.elements << testsuites
81
- document.write(target, 2)
82
- ensure
83
- target.close if target.is_a? File
81
+ report = ''
82
+ document.write(report, 2)
83
+
84
+ if target.is_a?(String)
85
+ PDK::Util::Filesystem.write_file(target, report)
86
+ else
87
+ target << report
88
+ end
84
89
  end
85
90
 
86
91
  # Renders the report as plain text.
@@ -88,25 +93,33 @@ module PDK
88
93
  # This report is designed for interactive use by a human and so excludes
89
94
  # all passing events in order to be consise.
90
95
  #
91
- # @param target [#write] an IO object that the report will be written to.
92
- # Defaults to PDK::Report.default_target.
96
+ # @param target [String, IO] The IO target to write the report to.
97
+ # If a String is provided, the report will be written to a file with the given path.
98
+ # If an IO object is provided, the report will be written to the IO object.
99
+ # If no target is provided, the default target PDK::Report.default_target will be used.
100
+ #
101
+ # @return [void]
93
102
  def write_text(target = self.class.default_target)
94
- # Open a File Object for IO if target is a string containing a filename or path
95
- target = File.open(target, 'w') if target.is_a? String
96
103
  coverage_report = nil
104
+ report = []
97
105
 
98
- events.each do |_tool, tool_events|
106
+ events.each_value do |tool_events|
99
107
  tool_events.each do |event|
100
108
  if event.rspec_puppet_coverage?
101
109
  coverage_report = event.to_text
102
110
  else
103
- target.puts(event.to_text) unless event.pass?
111
+ report << event.to_text unless event.pass? || event.skipped?
104
112
  end
105
113
  end
106
114
  end
107
- ensure
108
- target.puts "\n#{coverage_report}" if coverage_report
109
- target.close if target.is_a? File
115
+
116
+ report << "\n#{coverage_report}" if coverage_report
117
+
118
+ if target.is_a?(String)
119
+ PDK::Util::Filesystem.write_file(target, report.join("\n"))
120
+ elsif !report.empty?
121
+ target << report.join("\n") << "\n"
122
+ end
110
123
  end
111
124
  end
112
125
  end
@@ -0,0 +1,84 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Fetcher
6
+ class Git < PDK::Template::Fetcher::AbstractFetcher
7
+ # Whether the passed uri is fetchable by Git.
8
+ # @see PDK::Template::Fetcher.instance
9
+ # @return [Boolean]
10
+ def self.fetchable?(uri, _options = {})
11
+ PDK::Util::Git.repo?(uri.bare_uri)
12
+ end
13
+
14
+ # @see PDK::Template::Fetcher::AbstractTemplateFetcher.fetch!
15
+ def fetch!
16
+ return if fetched
17
+
18
+ super
19
+
20
+ # Default metadata for all git fetching methods
21
+ @metadata['template-url'] = uri.metadata_format
22
+
23
+ # We don't do a checkout of local-path repos. There are lots of edge
24
+ # cases or user un-expectations.
25
+ if PDK::Util::Git.work_tree?(uri.shell_path)
26
+ PDK.logger.warn format("Repository '%{repo}' has a work-tree; skipping git reset.", repo: uri.shell_path)
27
+ @path = uri.shell_path
28
+ @temporary = false
29
+ @metadata['template-ref'] = describe_path_and_ref(@path)
30
+ return
31
+ end
32
+
33
+ # This is either a bare local repo or a remote. either way it needs cloning.
34
+ # A "remote" can also be git repo on the local filsystem.
35
+ # @todo When switching this over to using rugged, cache the cloned
36
+ # template repo in `%AppData%` or `$XDG_CACHE_DIR` and update before
37
+ # use.
38
+ require 'pdk/util'
39
+ require 'pdk/util/git'
40
+
41
+ temp_dir = PDK::Util.make_tmpdir_name('pdk-templates')
42
+ @temporary = true
43
+ origin_repo = uri.bare_uri
44
+ git_ref = uri.uri_fragment
45
+
46
+ # Clone the repository
47
+ clone_result = PDK::Util::Git.git('clone', origin_repo, temp_dir)
48
+ unless clone_result[:exit_code].zero?
49
+ PDK.logger.error clone_result[:stdout]
50
+ PDK.logger.error clone_result[:stderr]
51
+ raise PDK::CLI::FatalError, format("Unable to clone git repository at '%{repo}' into '%{dest}'.", repo: origin_repo, dest: temp_dir)
52
+ end
53
+ @path = PDK::Util.canonical_path(temp_dir)
54
+
55
+ # Checkout the git reference
56
+ if PDK::Util::Git.work_dir_clean?(temp_dir)
57
+ Dir.chdir(temp_dir) do
58
+ full_ref = PDK::Util::Git.ls_remote(temp_dir, git_ref)
59
+ @metadata['template-ref'] = describe_path_and_ref(temp_dir, full_ref)
60
+ reset_result = PDK::Util::Git.git('reset', '--hard', full_ref)
61
+ return if reset_result[:exit_code].zero?
62
+
63
+ PDK.logger.error reset_result[:stdout]
64
+ PDK.logger.error reset_result[:stderr]
65
+ raise PDK::CLI::FatalError, format("Unable to checkout '%{ref}' of git repository at '%{path}'.", ref: git_ref, path: temp_dir)
66
+ end
67
+ else
68
+ PDK.logger.warn format("Uncommitted changes found when attempting to checkout '%{ref}' of git repository at '%{path}'; skipping git reset.", ref: git_ref, path: temp_dir)
69
+ @metadata['template-ref'] = describe_path_and_ref(temp_dir)
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ # :nocov: This is a just a wrapper for another method
76
+ def describe_path_and_ref(path, ref = nil)
77
+ require 'pdk/util/git'
78
+ PDK::Util::Git.describe(File.join(path, '.git'), ref)
79
+ end
80
+ # :nocov:
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,29 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Fetcher
6
+ class Local < PDK::Template::Fetcher::AbstractFetcher
7
+ # Whether the passed uri is fetchable. This is a catch-all and all URIs
8
+ # are considered on-disk already.
9
+ #
10
+ # @see PDK::Template::Fetcher.instance
11
+ # @return [Boolean]
12
+ def self.fetchable?(_uri, _options = {})
13
+ true
14
+ end
15
+
16
+ # @see PDK::Template::Fetcher::AbstractTemplateFetcher.fetch!
17
+ def fetch!
18
+ return if fetched
19
+
20
+ super
21
+
22
+ @path = uri.shell_path
23
+ @temporary = false
24
+ @metadata['template-url'] = uri.bare_uri
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,100 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Fetcher
6
+ autoload :Git, 'pdk/template/fetcher/git'
7
+ autoload :Local, 'pdk/template/fetcher/local'
8
+
9
+ # Returns a Template Fetcher implementation for the given Template URI
10
+ # @param uri [PDK::Util::TemplateURI] The URI of the template to fetch
11
+ # @param options [Hash{Object => Object}] A list of options to pass through to the fetcher.
12
+ #
13
+ # @return [PDK::Template::Fetcher::AbstractTemplateFetcher] An instance of a class which implements the AbstractFetcher class
14
+ def self.instance(uri, options = {})
15
+ return Git.new(uri, options) if Git.fetchable?(uri, options)
16
+
17
+ Local.new(uri, options)
18
+ end
19
+
20
+ # Creates an instance of a PDK::Template::Fetcher::AbstractTemplateFetcher object with the path or URL to the template
21
+ # and the block of code to run to be run while the template is fetched.
22
+ #
23
+ # The fetched directory is only guaranteed to be available on disk
24
+ # within the scope of the block passed to this method.
25
+ #
26
+ # @param uri [PDK::Util::TemplateURI] The URI of the template to fetch.
27
+ # @param options [Hash{Object => Object}] A list of options to pass through to the fetcher.
28
+ #
29
+ # @yieldparam fetcher [PDK::Template::Fetcher::AbstractTemplateFetcher] The initialised fetcher with
30
+ # the template already fetched
31
+ #
32
+ # @example Using a git repository as a template
33
+ # PDK::Template::Fetcher.with('https://github.com/puppetlabs/pdk-templates') do |fetcher|
34
+ # end
35
+ #
36
+ # @raise [ArgumentError] If no block is given to this method.
37
+ # @return [void]
38
+ def self.with(uri, options = {})
39
+ raise ArgumentError, format('%{class_name}.with must be passed a block.', class_name: name) unless block_given?
40
+
41
+ fetcher = instance(uri, options)
42
+
43
+ begin
44
+ fetcher.fetch!
45
+ yield fetcher
46
+ ensure
47
+ # If the the path is temporary, clean it up
48
+ PDK::Util::Filesystem.rm_rf(fetcher.path) if fetcher.temporary
49
+ end
50
+ nil
51
+ end
52
+
53
+ # An abstract class which all Template Fetchers should subclass. This class is responsible for
54
+ # downloading or copying a Template Directory that is pointed to by a Template URI
55
+ #
56
+ # @api private
57
+ # @abstract
58
+ class AbstractFetcher
59
+ # @return [PDK::Util::TemplateURI] The URI of the template that is to be fetched
60
+ attr_reader :uri
61
+
62
+ # @return [String] The local filesystem path of the fetched template
63
+ attr_reader :path
64
+
65
+ # @return [Boolean] Whether the fetched path should be considered temporary and be deleted after use
66
+ attr_reader :temporary
67
+
68
+ # @return [Boolean] Whether the template has been fetched yet
69
+ attr_reader :fetched
70
+
71
+ # @return [Hash] The metadata hash for this template.
72
+ attr_reader :metadata
73
+
74
+ # @param uri [PDK::Util::TemplateURI] The URI of the template to fetch
75
+ # @param options [Hash{Object => Object}] A list of options to pass through to the fetcher.
76
+ def initialize(uri, options)
77
+ @uri = uri
78
+ # Defaults
79
+ @path = nil
80
+ @metadata = {
81
+ 'pdk-version' => PDK::Util::Version.version_string,
82
+ 'template-url' => nil,
83
+ 'template-ref' => nil
84
+ }
85
+ @fetched = false
86
+ @temporary = false
87
+ @options = options
88
+ end
89
+
90
+ # Fetches the template directory and populates the path property
91
+ #
92
+ # @return [void]
93
+ # @abstract
94
+ def fetch!
95
+ @fetched = true
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,108 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Renderer
6
+ module V1
7
+ # The old templating code in the PDK passed through a TemplateDir object. This class mimics the methods
8
+ # of that old class so that existing custom templates will still function with the newer refactor templating code.
9
+ # Methods which have no use in custom templates exist but do no nothing, for example `def render; end`
10
+ #
11
+ # @see https://raw.githubusercontent.com/puppetlabs/pdk/4ffd58062c77ad1e54d2fe16b16015f7207bcee8/lib/pdk/module/template_dir/base.rb
12
+ # :nocov: This class is tested in the packaging and acceptance testing suites
13
+ class LegacyTemplateDir
14
+ attr_accessor :module_metadata
15
+ attr_reader :uri
16
+
17
+ def initialize(context, uri, path, module_metadata = {})
18
+ @uri = uri
19
+ @module_metadata = module_metadata
20
+ @context = context
21
+ @path = path
22
+ end
23
+
24
+ def metadata; end
25
+
26
+ def render; end
27
+
28
+ def object_template_for; end
29
+
30
+ def object_config
31
+ config_for(nil)
32
+ end
33
+
34
+ # Generate a hash of data to be used when rendering the specified
35
+ # template.
36
+ #
37
+ # @param dest_path [String] The destination path of the file that the
38
+ # data is for, relative to the root of the module.
39
+ #
40
+ # @return [Hash] The data that will be available to the template via the
41
+ # `@configs` instance variable.
42
+ #
43
+ # @api private
44
+ def config_for(dest_path, sync_config_path = nil)
45
+ require 'pdk/util'
46
+
47
+ module_root = PDK::Util.module_root
48
+ sync_config_path ||= File.join(module_root, '.sync.yml') unless module_root.nil?
49
+ config_path = File.join(@path, 'config_defaults.yml')
50
+
51
+ if @config.nil?
52
+ require 'deep_merge'
53
+ conf_defaults = read_config(config_path)
54
+ @sync_config = read_config(sync_config_path) unless sync_config_path.nil?
55
+ @config = conf_defaults
56
+ @config.deep_merge!(@sync_config, knockout_prefix: '---') unless @sync_config.nil?
57
+ end
58
+ file_config = @config.fetch('common', {}).clone
59
+ file_config['module_metadata'] = @module_metadata
60
+ file_config.merge!(@config.fetch(dest_path, {})) unless dest_path.nil?
61
+ file_config.merge!(@config).tap do |c|
62
+ if uri.default?
63
+ if c['unmanaged']
64
+ 'unmanaged'
65
+ elsif c['delete']
66
+ 'deleted'
67
+ elsif @sync_config&.key?(dest_path)
68
+ 'customized'
69
+ else
70
+ 'default'
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ # Generates a hash of data from a given yaml file location.
77
+ #
78
+ # @param loc [String] The path of the yaml config file.
79
+ #
80
+ # @warn If the specified path is not a valid yaml file. Returns an empty Hash
81
+ # if so.
82
+ #
83
+ # @return [Hash] The data that has been read in from the given yaml file.
84
+ #
85
+ # @api private
86
+ def read_config(loc)
87
+ if PDK::Util::Filesystem.file?(loc) && PDK::Util::Filesystem.readable?(loc)
88
+ require 'yaml'
89
+
90
+ begin
91
+ YAML.safe_load(PDK::Util::Filesystem.read_file(loc), permitted_classes: [], permitted_symbols: [], aliases: true)
92
+ rescue Psych::SyntaxError => e
93
+ PDK.logger.warn format("'%{file}' is not a valid YAML file: %{problem} %{context} at line %{line} column %{column}", file: loc, problem: e.problem, context: e.context, line: e.line,
94
+ column: e.column)
95
+ {}
96
+ end
97
+ else
98
+ {}
99
+ end
100
+ end
101
+
102
+ def template_path(_uri); end
103
+ end
104
+ # :nocov:
105
+ end
106
+ end
107
+ end
108
+ end