pdk 1.9.0 → 3.2.0

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