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,28 +1,45 @@
1
1
  require 'pdk'
2
- require 'pdk/cli/exec'
3
- require 'pdk/util/bundler'
4
- require 'json'
5
2
 
6
3
  module PDK
7
4
  module Test
8
5
  class Unit
9
6
  def self.cmd(tests, opts = {})
10
- rake_args = opts.key?(:parallel) ? 'parallel_spec_standalone' : 'spec_standalone'
11
- rake_args += "[#{tests}]" unless tests.nil?
7
+ rake_args = opts[:parallel] ? 'parallel_spec_standalone' : 'spec_standalone'
8
+ rake_args += "[#{tests}]" unless tests.nil? || tests.empty?
12
9
  rake_args
13
10
  end
14
11
 
15
12
  def self.rake_bin
13
+ require 'pdk/util'
14
+
16
15
  @rake ||= File.join(PDK::Util.module_root, 'bin', 'rake')
17
16
  end
18
17
 
19
- def self.rake(task, spinner_text, environment = {})
18
+ def self.cmd_with_args(task)
19
+ require 'pdk/util/ruby_version'
20
+
20
21
  argv = [rake_bin, task]
21
22
  argv.unshift(File.join(PDK::Util::RubyVersion.bin_path, 'ruby.exe')) if Gem.win_platform?
23
+ argv
24
+ end
25
+
26
+ def self.rake(task, spinner_text, environment = {})
27
+ require 'pdk/cli/exec/command'
28
+
29
+ command = PDK::CLI::Exec::Command.new(*cmd_with_args(task)).tap do |c|
30
+ c.context = :module
31
+ c.add_spinner(spinner_text) if spinner_text
32
+ c.environment = environment
33
+ end
34
+
35
+ command.execute!
36
+ end
37
+
38
+ def self.interactive_rake(task, environment)
39
+ require 'pdk/cli/exec/interactive_command'
22
40
 
23
- command = PDK::CLI::Exec::Command.new(*argv).tap do |c|
41
+ command = PDK::CLI::Exec::InteractiveCommand.new(*cmd_with_args(task)).tap do |c|
24
42
  c.context = :module
25
- c.add_spinner(spinner_text)
26
43
  c.environment = environment
27
44
  end
28
45
 
@@ -31,64 +48,94 @@ module PDK
31
48
 
32
49
  def self.parallel_with_no_tests?(ran_in_parallel, json_result, result)
33
50
  ran_in_parallel && json_result.empty? &&
34
- ((!result[:exit_code].zero? && result[:stderr].strip =~ %r{Pass files or folders to run$}) ||
35
- result[:stderr].strip =~ %r{No files for parallel_spec to run against$})
51
+ ((!result[:exit_code].zero? && result[:stderr].strip =~ /Pass files or folders to run$/) ||
52
+ result[:stderr].strip =~ /No files for parallel_spec to run against$/)
36
53
  end
37
54
 
38
55
  def self.print_failure(result, exception)
39
56
  $stderr.puts ''
40
- result[:stdout].each_line { |line| $stderr.puts line.rstrip } unless result[:stdout].nil?
41
- result[:stderr].each_line { |line| $stderr.puts line.rstrip } unless result[:stderr].nil?
57
+ result[:stdout]&.each_line { |line| $stderr.puts line.rstrip }
58
+ result[:stderr]&.each_line { |line| $stderr.puts line.rstrip }
42
59
  $stderr.puts ''
43
60
  raise PDK::CLI::FatalError, exception
44
61
  end
45
62
 
46
63
  def self.tear_down
47
- result = rake('spec_clean', _('Cleaning up after running unit tests.'))
64
+ result = rake('spec_clean', 'Cleaning up after running unit tests.')
48
65
 
49
66
  return if result[:exit_code].zero?
50
67
 
51
- PDK.logger.error(_('The spec_clean rake task failed with the following error(s):'))
52
- print_failure(result, _('Failed to clean up after running unit tests'))
68
+ PDK.logger.error('The spec_clean rake task failed with the following error(s):')
69
+ print_failure(result, 'Failed to clean up after running unit tests')
53
70
  end
54
71
 
55
72
  def self.setup
56
- result = rake('spec_prep', _('Preparing to run the unit tests.'))
73
+ result = rake('spec_prep', 'Preparing to run the unit tests.')
57
74
 
58
75
  return if result[:exit_code].zero?
59
76
 
60
77
  tear_down
61
78
 
62
- PDK.logger.error(_('The spec_prep rake task failed with the following error(s):'))
63
- print_failure(result, _('Failed to prepare to run the unit tests.'))
79
+ PDK.logger.error('The spec_prep rake task failed with the following error(s):')
80
+ print_failure(result, 'Failed to prepare to run the unit tests.')
64
81
  end
65
82
 
66
83
  def self.invoke(report, options = {})
84
+ require 'pdk/util'
85
+ require 'pdk/util/bundler'
86
+
67
87
  PDK::Util::Bundler.ensure_binstubs!('rake', 'rspec-core')
68
88
 
69
89
  setup
70
90
 
71
- tests = options.fetch(:tests)
91
+ tests = options[:tests]
92
+ # Due to how rake handles paths in the command line options, any backslashed path (Windows platforms) needs to be converted
93
+ # to forward slash. We can't use File.expand_path as the files aren't guaranteed to be on-disk
94
+ #
95
+ # Ref - https://github.com/puppetlabs/pdk/issues/828
96
+ tests = tests.tr('\\', '/') unless tests.nil?
72
97
 
73
- environment = { 'CI_SPEC_OPTIONS' => '--format j' }
98
+ environment = {}
74
99
  environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
75
- spinner_msg = options.key?(:parallel) ? _('Running unit tests in parallel.') : _('Running unit tests.')
100
+ spinner_msg = options[:parallel] ? 'Running unit tests in parallel.' : 'Running unit tests.'
101
+
102
+ if options[:interactive]
103
+ environment['CI_SPEC_OPTIONS'] = if options[:verbose]
104
+ '--format documentation'
105
+ else
106
+ '--format progress'
107
+ end
108
+ result = interactive_rake(cmd(tests, options), environment)
109
+ return result[:exit_code]
110
+ end
111
+
112
+ # Run interactive_rake for documentation output when utilising verbose option.
113
+ if (options[:verbose]) && (options[:format])
114
+ environment['CI_SPEC_OPTIONS'] = '--format documentation'
115
+ result = interactive_rake(cmd(tests, options), environment)
116
+ # Caveat: Report will not be written to format option(s) file(s) when there are event failures.
117
+ return result[:exit_code] unless (result[:exit_code]).zero?
118
+
119
+ spinner_msg = "Exporting unit tests -> #{options[:format]}"
120
+ end
121
+
122
+ environment['CI_SPEC_OPTIONS'] = '--format j'
76
123
  result = rake(cmd(tests, options), spinner_msg, environment)
77
124
 
78
- json_result = if options.key?(:parallel)
125
+ json_result = if options[:parallel]
79
126
  PDK::Util.find_all_json_in(result[:stdout])
80
127
  else
81
128
  PDK::Util.find_first_json_in(result[:stdout])
82
129
  end
83
130
 
84
- if parallel_with_no_tests?(options.key?(:parallel), json_result, result)
131
+ if parallel_with_no_tests?(options[:parallel], json_result, result)
85
132
  json_result = [{ 'messages' => ['No examples found.'] }]
86
133
  result[:exit_code] = 0
87
134
  end
88
135
 
89
- raise PDK::CLI::FatalError, _('Unit test output did not contain a valid JSON result: %{output}') % { output: result[:stdout] } if json_result.nil? || json_result.empty?
136
+ raise PDK::CLI::FatalError, format('Unit test output did not contain a valid JSON result: %{output}', output: result[:stdout]) if json_result.nil? || json_result.empty?
90
137
 
91
- json_result = merge_json_results(json_result) if options.key?(:parallel)
138
+ json_result = merge_json_results(json_result) if options[:parallel]
92
139
 
93
140
  parse_output(report, json_result, result[:duration])
94
141
 
@@ -99,38 +146,38 @@ module PDK
99
146
 
100
147
  def self.parse_output(report, json_data, duration)
101
148
  # Output messages to stderr.
102
- json_data['messages'] && json_data['messages'].each { |msg| $stderr.puts msg }
149
+ json_data['messages']&.each { |msg| $stderr.puts msg }
103
150
 
104
151
  example_results = {
105
152
  # Only possibilities are passed, failed, pending:
106
- # https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/example.rb#L548
153
+ # https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example.rb#L548
107
154
  'passed' => [],
108
155
  'failed' => [],
109
- 'pending' => [],
156
+ 'pending' => []
110
157
  }
111
158
 
112
- json_data['examples'] && json_data['examples'].each do |ex|
159
+ json_data['examples']&.each do |ex|
113
160
  example_results[ex['status']] << ex if example_results.key?(ex['status'])
114
161
  end
115
162
 
116
163
  example_results.each do |result, examples|
117
164
  # Translate rspec example results to JUnit XML testcase results
118
- state = case result
119
- when 'passed' then :passed
120
- when 'failed' then :failure
121
- when 'pending' then :skipped
122
- end
165
+ state_map = {
166
+ 'passed' => :passed,
167
+ 'failed' => :failure,
168
+ 'pending' => :skipped
169
+ }
123
170
 
124
171
  examples.each do |ex|
125
172
  report.add_event(
126
173
  source: 'rspec',
127
- state: state,
174
+ state: state_map[result],
128
175
  file: ex['file_path'],
129
176
  line: ex['line_number'],
130
177
  test: ex['full_description'],
131
178
  severity: ex['status'],
132
179
  message: ex['pending_message'] || (ex['exception'] && ex['exception']['message']) || nil,
133
- trace: (ex['exception'] && ex['exception']['backtrace']) || nil,
180
+ trace: (ex['exception'] && ex['exception']['backtrace']) || nil
134
181
  )
135
182
  end
136
183
  end
@@ -138,21 +185,20 @@ module PDK
138
185
  return unless json_data['summary']
139
186
 
140
187
  # TODO: standardize summary output
141
- $stderr.puts ' ' << _('Evaluated %{total} tests in %{duration} seconds: %{failures} failures, %{pending} pending.') % {
142
- total: json_data['summary']['example_count'],
143
- duration: duration,
144
- failures: json_data['summary']['failure_count'],
145
- pending: json_data['summary']['pending_count'],
146
- }
188
+ $stderr.puts ' ' << (format('Evaluated %{total} tests in %{duration} seconds: %{failures} failures, %{pending} pending.', total: json_data['summary']['example_count'], duration: duration,
189
+ failures: json_data['summary']['failure_count'], pending: json_data['summary']['pending_count'])) # rubocop:disable Layout/LineLength
147
190
  end
148
191
 
149
192
  def self.merge_json_results(json_data)
193
+ require 'set'
194
+
150
195
  merged_json_result = {}
151
196
 
152
197
  # Merge messages
153
198
  message_set = Set.new
154
199
  json_data.each do |json|
155
200
  next unless json['messages']
201
+
156
202
  message_set |= json['messages']
157
203
  end
158
204
  merged_json_result['messages'] = message_set.to_a
@@ -161,6 +207,7 @@ module PDK
161
207
  all_examples = []
162
208
  json_data.each do |json|
163
209
  next unless json['examples']
210
+
164
211
  all_examples.concat json['examples']
165
212
  end
166
213
  merged_json_result['examples'] = all_examples
@@ -169,10 +216,11 @@ module PDK
169
216
  summary_hash = {
170
217
  'example_count' => 0,
171
218
  'failure_count' => 0,
172
- 'pending_count' => 0,
219
+ 'pending_count' => 0
173
220
  }
174
221
  json_data.each do |json|
175
222
  next unless json['summary']
223
+
176
224
  summary_hash['example_count'] += json['summary']['example_count']
177
225
  summary_hash['failure_count'] += json['summary']['failure_count']
178
226
  summary_hash['pending_count'] += json['summary']['pending_count']
@@ -183,23 +231,25 @@ module PDK
183
231
  end
184
232
 
185
233
  # @return array of { :id, :full_description }
186
- def self.list
234
+ def self.list(options = {})
235
+ require 'pdk/util'
236
+ require 'pdk/util/bundler'
237
+
187
238
  PDK::Util::Bundler.ensure_binstubs!('rake')
188
239
 
189
- command_argv = [File.join(PDK::Util.module_root, 'bin', 'rake'), 'spec_list_json']
190
- command_argv.unshift(File.join(PDK::Util::RubyVersion.bin_path, 'ruby.exe')) if Gem.win_platform?
240
+ environment = {}
241
+ environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
191
242
 
192
- list_command = PDK::CLI::Exec::Command.new(*command_argv)
193
- list_command.context = :module
194
- output = list_command.execute!
243
+ output = rake('spec_list_json', 'Finding unit tests.', environment)
195
244
 
196
245
  rspec_json = PDK::Util.find_first_json_in(output[:stdout])
197
- raise PDK::CLI::FatalError, _('Failed to find valid JSON in output from rspec: %{output}' % { output: output[:stdout] }) unless rspec_json
246
+ raise PDK::CLI::FatalError, format('Failed to find valid JSON in output from rspec: %{output}', output: output[:stdout]) unless rspec_json
247
+
198
248
  if rspec_json['examples'].empty?
199
249
  rspec_message = rspec_json['messages'][0]
200
250
  return [] if rspec_message == 'No examples found.'
201
251
 
202
- raise PDK::CLI::FatalError, _('Unable to enumerate examples. rspec reported: %{message}' % { message: rspec_message })
252
+ raise PDK::CLI::FatalError, format('Unable to enumerate examples. rspec reported: %{message}', message: rspec_message)
203
253
  else
204
254
  examples = []
205
255
  rspec_json['examples'].each do |example|
@@ -1,27 +1,23 @@
1
- require 'bundler'
2
- require 'digest'
3
- require 'fileutils'
4
- require 'pdk/util'
5
- require 'pdk/cli/exec'
1
+ require 'pdk'
6
2
 
7
3
  module PDK
8
4
  module Util
9
5
  module Bundler
10
- class BundleHelper; end
6
+ # class BundleHelper; end
11
7
 
12
- def self.ensure_bundle!(gem_overrides = nil)
8
+ def self.ensure_bundle!(gem_overrides = {})
13
9
  bundle = BundleHelper.new
14
10
 
15
11
  # This will default ensure_bundle! to re-resolving everything to latest
16
12
  gem_overrides ||= { puppet: nil, hiera: nil, facter: nil }
17
13
 
18
14
  if already_bundled?(bundle.gemfile, gem_overrides)
19
- PDK.logger.debug(_('Bundler managed gems already up to date.'))
15
+ PDK.logger.debug('Bundler managed gems already up to date.')
20
16
  return
21
17
  end
22
18
 
23
19
  unless bundle.gemfile?
24
- PDK.logger.debug(_("No Gemfile found in '%{cwd}'. Skipping bundler management.") % { cwd: Dir.pwd })
20
+ PDK.logger.debug(format("No Gemfile found in '%{cwd}'. Skipping bundler management.", cwd: Dir.pwd))
25
21
  return
26
22
  end
27
23
 
@@ -36,11 +32,11 @@ module PDK
36
32
  original_lockfile = bundle.gemfile_lock
37
33
  temp_lockfile = "#{original_lockfile}.tmp"
38
34
 
39
- FileUtils.mv(original_lockfile, temp_lockfile)
35
+ PDK::Util::Filesystem.mv(original_lockfile, temp_lockfile)
40
36
 
41
37
  all_deps_available = bundle.installed?(gem_overrides)
42
38
  ensure
43
- FileUtils.mv(temp_lockfile, original_lockfile, force: true)
39
+ PDK::Util::Filesystem.mv(temp_lockfile, original_lockfile, force: true)
44
40
  end
45
41
 
46
42
  bundle.update_lock!(with: gem_overrides, local: all_deps_available)
@@ -48,9 +44,7 @@ module PDK
48
44
  # If there are missing dependencies after updating the lockfile, let `bundle install`
49
45
  # go out and get them. If the specified puppet gem version points to a remote location
50
46
  # or local filepath, then run bundle install as well.
51
- if !bundle.installed? || (gem_overrides[:puppet] && gem_overrides[:puppet].start_with?('file://', 'git://', 'https://'))
52
- bundle.install!(gem_overrides)
53
- end
47
+ bundle.install!(gem_overrides) if !bundle.installed?(gem_overrides) || gem_overrides[:puppet]&.start_with?('file://', 'git://', 'https://')
54
48
 
55
49
  mark_as_bundled!(bundle.gemfile, gem_overrides)
56
50
  end
@@ -70,6 +64,8 @@ module PDK
70
64
  end
71
65
 
72
66
  def self.bundle_cache_key(gemfile, gem_overrides)
67
+ require 'digest'
68
+
73
69
  override_sig = (gem_overrides || {}).sort_by { |gem, _| gem.to_s }.to_s
74
70
  Digest::MD5.hexdigest(gemfile.to_s + override_sig)
75
71
  end
@@ -77,11 +73,13 @@ module PDK
77
73
 
78
74
  class BundleHelper
79
75
  def gemfile
76
+ require 'pdk/util'
80
77
  @gemfile ||= PDK::Util.find_upwards('Gemfile')
81
78
  end
82
79
 
83
80
  def gemfile_lock
84
- return nil if gemfile.nil?
81
+ return if gemfile.nil?
82
+
85
83
  @gemfile_lock ||= File.join(File.dirname(gemfile), 'Gemfile.lock')
86
84
  end
87
85
 
@@ -90,11 +88,11 @@ module PDK
90
88
  end
91
89
 
92
90
  def locked?
93
- !gemfile_lock.nil? && File.file?(gemfile_lock)
91
+ !gemfile_lock.nil? && PDK::Util::Filesystem.file?(gemfile_lock)
94
92
  end
95
93
 
96
94
  def installed?(gem_overrides = {})
97
- PDK.logger.debug(_('Checking for missing Gemfile dependencies.'))
95
+ PDK.logger.debug('Checking for missing Gemfile dependencies.')
98
96
 
99
97
  argv = ['check', "--gemfile=#{gemfile}", '--dry-run']
100
98
 
@@ -104,44 +102,41 @@ module PDK
104
102
 
105
103
  result = cmd.execute!
106
104
 
107
- unless result[:exit_code].zero?
108
- PDK.logger.debug(result.values_at(:stdout, :stderr).join("\n"))
109
- end
110
-
111
105
  result[:exit_code].zero?
112
106
  end
113
107
 
114
108
  def lock!
109
+ require 'pdk/util'
110
+ require 'pdk/util/ruby_version'
111
+
115
112
  if PDK::Util.package_install?
116
113
  # In packaged installs, use vendored Gemfile.lock as a starting point.
117
114
  # Subsequent 'bundle install' will still pick up any new dependencies.
118
115
  vendored_lockfiles = [
119
116
  File.join(PDK::Util.package_cachedir, "Gemfile-#{PDK::Util::RubyVersion.active_ruby_version}.lock"),
120
- File.join(PDK::Util.package_cachedir, 'Gemfile.lock'),
117
+ File.join(PDK::Util.package_cachedir, 'Gemfile.lock')
121
118
  ]
122
119
 
123
- vendored_gemfile_lock = vendored_lockfiles.find { |lockfile| File.exist?(lockfile) }
124
-
125
- unless vendored_gemfile_lock
126
- raise PDK::CLI::FatalError, _('Vendored Gemfile.lock (%{source}) not found.') % {
127
- source: vendored_gemfile_lock,
128
- }
120
+ vendored_gemfile_lock = vendored_lockfiles.find do |lockfile|
121
+ PDK::Util::Filesystem.exist?(lockfile)
129
122
  end
130
123
 
131
- PDK.logger.debug(_('Using vendored Gemfile.lock from %{source}.') % { source: vendored_gemfile_lock })
132
- FileUtils.cp(vendored_gemfile_lock, File.join(PDK::Util.module_root, 'Gemfile.lock'))
124
+ raise PDK::CLI::FatalError, format('Vendored Gemfile.lock (%{source}) not found.', source: vendored_gemfile_lock) unless vendored_gemfile_lock
125
+
126
+ PDK.logger.debug(format('Using vendored Gemfile.lock from %{source}.', source: vendored_gemfile_lock))
127
+ PDK::Util::Filesystem.cp(vendored_gemfile_lock, File.join(PDK::Util.module_root, 'Gemfile.lock'))
133
128
  else
134
129
  argv = ['lock']
135
130
 
136
131
  cmd = bundle_command(*argv).tap do |c|
137
- c.add_spinner(_('Resolving default Gemfile dependencies.'))
132
+ c.add_spinner('Resolving default Gemfile dependencies.')
138
133
  end
139
134
 
140
135
  result = cmd.execute!
141
136
 
142
137
  unless result[:exit_code].zero?
143
- PDK.logger.fatal(result.values_at(:stdout, :stderr).join("\n"))
144
- raise PDK::CLI::FatalError, _('Unable to resolve default Gemfile dependencies.')
138
+ PDK.logger.fatal(result.values_at(:stdout, :stderr).join("\n")) unless PDK.logger.debug?
139
+ raise PDK::CLI::FatalError, 'Unable to resolve default Gemfile dependencies.'
145
140
  end
146
141
 
147
142
  # After initial lockfile generation, re-resolve json gem to built-in
@@ -154,7 +149,7 @@ module PDK
154
149
  end
155
150
 
156
151
  def update_lock!(options = {})
157
- PDK.logger.debug(_('Updating Gemfile dependencies.'))
152
+ PDK.logger.debug('Updating Gemfile dependencies.')
158
153
 
159
154
  argv = ['lock', "--lockfile=#{gemfile_lock}", '--update']
160
155
 
@@ -181,42 +176,46 @@ module PDK
181
176
  result = cmd.execute!
182
177
 
183
178
  unless result[:exit_code].zero?
184
- PDK.logger.fatal(result.values_at(:stdout, :stderr).join("\n"))
185
- raise PDK::CLI::FatalError, _('Unable to resolve Gemfile dependencies.')
179
+ PDK.logger.fatal(result.values_at(:stdout, :stderr).join("\n")) unless PDK.logger.debug?
180
+ raise PDK::CLI::FatalError, 'Unable to resolve Gemfile dependencies.'
186
181
  end
187
182
 
188
183
  true
189
184
  end
190
185
 
191
186
  def install!(gem_overrides = {})
187
+ require 'pdk/util/ruby_version'
188
+
192
189
  argv = ['install', "--gemfile=#{gemfile}"]
193
190
  argv << '-j4' unless Gem.win_platform? && Gem::Version.new(PDK::Util::RubyVersion.active_ruby_version) < Gem::Version.new('2.3.5')
194
191
 
195
192
  cmd = bundle_command(*argv).tap do |c|
196
- c.add_spinner(_('Installing missing Gemfile dependencies.'))
193
+ c.add_spinner('Installing missing Gemfile dependencies.')
197
194
  c.update_environment(gemfile_env(gem_overrides)) unless gem_overrides.empty?
198
195
  end
199
196
 
200
197
  result = cmd.execute!
201
198
 
202
199
  unless result[:exit_code].zero?
203
- PDK.logger.fatal(result.values_at(:stdout, :stderr).join("\n"))
204
- raise PDK::CLI::FatalError, _('Unable to install missing Gemfile dependencies.')
200
+ PDK.logger.fatal(result.values_at(:stdout, :stderr).join("\n")) unless PDK.logger.debug?
201
+ raise PDK::CLI::FatalError, 'Unable to install missing Gemfile dependencies.'
205
202
  end
206
203
 
207
204
  true
208
205
  end
209
206
 
210
207
  def binstubs!(gems)
208
+ raise PDK::CLI::FatalError, 'Unable to install requested binstubs as the Gemfile is missing' if gemfile.nil?
209
+
211
210
  binstub_dir = File.join(File.dirname(gemfile), 'bin')
212
- return true if gems.all? { |gem| File.file?(File.join(binstub_dir, gem)) }
211
+ return true if gems.all? { |gem| PDK::Util::Filesystem.file?(File.join(binstub_dir, gem)) }
213
212
 
214
213
  cmd = bundle_command('binstubs', *gems, '--force')
215
214
  result = cmd.execute!
216
215
 
217
216
  unless result[:exit_code].zero?
218
- PDK.logger.fatal(_("Failed to generate binstubs for '%{gems}':\n%{output}") % { gems: gems.join(' '), output: result.values_at(:stdout, :stderr).join("\n") })
219
- raise PDK::CLI::FatalError, _('Unable to install requested binstubs.')
217
+ PDK.logger.fatal(format("Failed to generate binstubs for '%{gems}':\n%{output}", gems: gems.join(' '), output: result.values_at(:stdout, :stderr).join("\n"))) unless PDK.logger.debug?
218
+ raise PDK::CLI::FatalError, 'Unable to install requested binstubs.'
220
219
  end
221
220
 
222
221
  true
@@ -243,6 +242,9 @@ module PDK
243
242
  end
244
243
 
245
244
  def bundle_command(*args)
245
+ require 'pdk/cli/exec'
246
+ require 'pdk/cli/exec/command'
247
+
246
248
  PDK::CLI::Exec::Command.new(PDK::CLI::Exec.bundle_bin, *args).tap do |c|
247
249
  c.context = :module
248
250
  end
@@ -0,0 +1,138 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Util
5
+ module ChangelogGenerator
6
+ # Taken from the version regex in https://forgeapi.puppet.com/schemas/module.json
7
+ VERSION_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(-(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\+[0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*)?$/.freeze
8
+ GEM = 'github_changelog_generator'.freeze
9
+
10
+ # Raises if the github_changelog_generator is not available
11
+ def self.github_changelog_generator_available!
12
+ check_command = PDK::CLI::Exec::InteractiveCommand.new(PDK::CLI::Exec.bundle_bin, 'info', 'github_changelog_generator')
13
+ check_command.context = :module
14
+
15
+ result = check_command.execute!
16
+
17
+ return if result[:exit_code].zero?
18
+
19
+ raise PDK::CLI::ExitWithError, format('Unable to generate the changelog as the %{gem} gem is not included in this module\'s Gemfile', gem: GEM)
20
+ end
21
+
22
+ # Runs the Changelog Generator gem (in the module's context) to automatically create a CHANGLELOG.MD file
23
+ #
24
+ # @returns [String] The content of the new Changelog
25
+ def self.generate_changelog
26
+ github_changelog_generator_available!
27
+
28
+ changelog_command = PDK::CLI::Exec::InteractiveCommand.new(PDK::CLI::Exec.bundle_bin, 'exec', 'rake', 'changelog')
29
+ changelog_command.context = :module
30
+
31
+ result = changelog_command.execute!
32
+ raise PDK::CLI::ExitWithError, format('Error generating changelog: %{stdout}', stdout: result[:stdout]) unless result[:exit_code].zero?
33
+
34
+ output = changelog_content
35
+
36
+ raise PDK::CLI::ExitWithError, format('The generated changelog contains uncategorized Pull Requests. Please label them and try again. See %{changelog_file} for more details', changelog_file: changelog_file) if output.include?('UNCATEGORIZED PRS; GO LABEL THEM') # rubocop:disable Layout/LineLength
37
+
38
+ output
39
+ end
40
+
41
+ # Computes the next version, based on the content of a changelog
42
+ #
43
+ # @param current_version [String, Gem::Version] The current version of the module
44
+ # @return [String] The new version. May be the same as the current version if there are no notable changes
45
+ def self.compute_next_version(current_version)
46
+ raise PDK::CLI::ExitWithError, format('Invalid version string %{version}', version: current_version) unless VERSION_REGEX.match?(current_version)
47
+
48
+ version = Gem::Version.create(current_version).segments
49
+ PDK.logger.info format('Determing the target version from \'%{file}\'', file: changelog_file)
50
+
51
+ # Grab all lines that start with ## between from the latest changes
52
+ # For example given the changelog below
53
+
54
+ # ```
55
+ # # Change log
56
+ #
57
+ # All notable changes to this project will be documented in this file.
58
+ #
59
+ # ## [v4.0.0](https://github.com/puppetlabs/puppetlabs-inifile/tree/v4.
60
+ #
61
+ # [Full Changelog](https://github.com/puppetlabs/puppetlabs-inifile/com --+
62
+ # |
63
+ # ### Changed |
64
+ # |
65
+ # - pdksync - FM-8499 - remove ubuntu14 support [\#363](https://github. | It's this piece of text we are interested in
66
+ # |
67
+ # ### Added |
68
+ # |
69
+ # - FM-8402 add debian 10 support [\#352](https://github.com/puppetlabs |
70
+ # |
71
+ # ## [v3.1.0](https://github.com/puppetlabs/puppetlabs-inifile/tree/v3. |
72
+ # --+
73
+ # [Full Changelog](https://github.com/puppetlabs/puppetlabs-inifile/com
74
+ #
75
+ # ### Added
76
+ #
77
+ # - FM-8222 - Port Module inifile to Litmus [\#344](https://github.com/
78
+ # - \(FM-8154\) Add Windows Server 2019 support [\#340](https://github.
79
+ # - \(FM-8041\) Add RedHat 8 support [\#339](https://github.com/puppetl
80
+ # ````
81
+ data = ''
82
+ in_changelog_entry = false
83
+ changelog_content.each_line do |line|
84
+ line.strip!
85
+ if line.start_with?('[')
86
+ # We're leaving the latest changes so we can break
87
+ break if in_changelog_entry
88
+
89
+ in_changelog_entry = true
90
+ end
91
+ data += line if in_changelog_entry && line.start_with?('##')
92
+ end
93
+
94
+ # Check for meta headers in first two header line matches
95
+ case data
96
+ when /^### Changed/
97
+ # Major Version bump
98
+ version[0] += 1
99
+ version[1] = 0
100
+ version[2] = 0
101
+ when /^### Added/
102
+ # Minor Version bump
103
+ version[1] += 1
104
+ version[2] = 0
105
+ when /^### Fixed/
106
+ # Patch Version bump
107
+ version[2] += 1
108
+ end
109
+
110
+ version.join('.')
111
+ end
112
+
113
+ # Returns the top most version from the CHANGELOG file
114
+ def self.latest_version
115
+ latest = nil
116
+ changelog_content.each_line do |line|
117
+ line.strip!
118
+ if line.start_with?('## [')
119
+ latest = line[line.index('[') + 1..line.index(']') - 1].delete('v')
120
+ break # stops after the top version is extracted
121
+ end
122
+ end
123
+ latest
124
+ end
125
+
126
+ def self.changelog_file
127
+ # Default Changelog file is CHANGELOG.md, but also search for the .MD prefix as well.
128
+ @changelog_file ||= ['CHANGELOG.md', 'CHANGELOG.MD'].map { |file| PDK::Util::Filesystem.expand_path(file) }.find { |path| PDK::Util::Filesystem.file?(path) }
129
+ end
130
+
131
+ def self.changelog_content
132
+ return '' if changelog_file.nil?
133
+
134
+ PDK::Util::Filesystem.read_file(changelog_file, open_args: 'rb:utf-8')
135
+ end
136
+ end
137
+ end
138
+ end