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,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