pdk 2.3.0 → 2.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1329 -1321
- data/LICENSE +201 -201
- data/README.md +163 -163
- data/exe/pdk +10 -10
- data/lib/pdk/analytics/client/google_analytics.rb +143 -143
- data/lib/pdk/analytics/client/noop.rb +25 -25
- data/lib/pdk/analytics/util.rb +19 -19
- data/lib/pdk/analytics.rb +30 -30
- data/lib/pdk/answer_file.rb +12 -12
- data/lib/pdk/bolt.rb +19 -19
- data/lib/pdk/cli/build.rb +82 -82
- data/lib/pdk/cli/bundle.rb +48 -48
- data/lib/pdk/cli/config/get.rb +26 -26
- data/lib/pdk/cli/config.rb +22 -22
- data/lib/pdk/cli/console.rb +148 -148
- data/lib/pdk/cli/convert.rb +52 -52
- data/lib/pdk/cli/env.rb +52 -52
- data/lib/pdk/cli/errors.rb +25 -25
- data/lib/pdk/cli/exec/command.rb +293 -293
- data/lib/pdk/cli/exec/interactive_command.rb +114 -114
- data/lib/pdk/cli/exec.rb +84 -84
- data/lib/pdk/cli/exec_group.rb +104 -104
- data/lib/pdk/cli/get/config.rb +24 -24
- data/lib/pdk/cli/get.rb +20 -20
- data/lib/pdk/cli/module/build.rb +12 -12
- data/lib/pdk/cli/module/generate.rb +47 -47
- data/lib/pdk/cli/module.rb +14 -14
- data/lib/pdk/cli/new/class.rb +32 -32
- data/lib/pdk/cli/new/defined_type.rb +32 -32
- data/lib/pdk/cli/new/fact.rb +29 -29
- data/lib/pdk/cli/new/function.rb +29 -29
- data/lib/pdk/cli/new/module.rb +53 -53
- data/lib/pdk/cli/new/provider.rb +29 -29
- data/lib/pdk/cli/new/task.rb +34 -34
- data/lib/pdk/cli/new/test.rb +52 -52
- data/lib/pdk/cli/new/transport.rb +27 -27
- data/lib/pdk/cli/new.rb +21 -21
- data/lib/pdk/cli/release/prep.rb +39 -39
- data/lib/pdk/cli/release/publish.rb +50 -50
- data/lib/pdk/cli/release.rb +194 -194
- data/lib/pdk/cli/remove/config.rb +80 -80
- data/lib/pdk/cli/remove.rb +20 -20
- data/lib/pdk/cli/set/config.rb +119 -119
- data/lib/pdk/cli/set.rb +20 -20
- data/lib/pdk/cli/test/unit.rb +90 -90
- data/lib/pdk/cli/test.rb +11 -11
- data/lib/pdk/cli/update.rb +64 -64
- data/lib/pdk/cli/util/command_redirector.rb +27 -27
- data/lib/pdk/cli/util/interview.rb +72 -72
- data/lib/pdk/cli/util/option_normalizer.rb +55 -55
- data/lib/pdk/cli/util/option_validator.rb +68 -68
- data/lib/pdk/cli/util/spinner.rb +13 -13
- data/lib/pdk/cli/util/update_manager_printer.rb +82 -82
- data/lib/pdk/cli/util.rb +305 -305
- data/lib/pdk/cli/validate.rb +116 -116
- data/lib/pdk/cli.rb +175 -175
- data/lib/pdk/config/analytics_schema.json +26 -26
- data/lib/pdk/config/errors.rb +5 -5
- data/lib/pdk/config/ini_file.rb +183 -183
- data/lib/pdk/config/ini_file_setting.rb +39 -39
- data/lib/pdk/config/json.rb +34 -34
- data/lib/pdk/config/json_schema_namespace.rb +142 -142
- data/lib/pdk/config/json_schema_setting.rb +53 -53
- data/lib/pdk/config/json_with_schema.rb +49 -49
- data/lib/pdk/config/namespace.rb +354 -354
- data/lib/pdk/config/setting.rb +135 -135
- data/lib/pdk/config/validator.rb +31 -31
- data/lib/pdk/config/yaml.rb +46 -46
- data/lib/pdk/config/yaml_with_schema.rb +59 -59
- data/lib/pdk/config.rb +390 -390
- data/lib/pdk/context/control_repo.rb +60 -60
- data/lib/pdk/context/module.rb +28 -28
- data/lib/pdk/context/none.rb +22 -22
- data/lib/pdk/context.rb +99 -99
- data/lib/pdk/control_repo.rb +90 -90
- data/lib/pdk/generate/defined_type.rb +43 -43
- data/lib/pdk/generate/fact.rb +25 -25
- data/lib/pdk/generate/function.rb +48 -48
- data/lib/pdk/generate/module.rb +352 -352
- data/lib/pdk/generate/provider.rb +28 -28
- data/lib/pdk/generate/puppet_class.rb +43 -43
- data/lib/pdk/generate/puppet_object.rb +232 -232
- data/lib/pdk/generate/task.rb +68 -68
- data/lib/pdk/generate/transport.rb +33 -33
- data/lib/pdk/generate.rb +24 -24
- data/lib/pdk/i18n.rb +4 -4
- data/lib/pdk/logger.rb +45 -45
- data/lib/pdk/module/build.rb +322 -322
- data/lib/pdk/module/convert.rb +296 -296
- data/lib/pdk/module/metadata.rb +202 -202
- data/lib/pdk/module/release.rb +260 -260
- data/lib/pdk/module/update.rb +131 -131
- data/lib/pdk/module/update_manager.rb +227 -227
- data/lib/pdk/module.rb +30 -30
- data/lib/pdk/report/event.rb +370 -370
- data/lib/pdk/report.rb +121 -121
- data/lib/pdk/template/fetcher/git.rb +85 -85
- data/lib/pdk/template/fetcher/local.rb +28 -28
- data/lib/pdk/template/fetcher.rb +98 -98
- data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -116
- data/lib/pdk/template/renderer/v1/renderer.rb +132 -132
- data/lib/pdk/template/renderer/v1/template_file.rb +102 -102
- data/lib/pdk/template/renderer/v1.rb +25 -25
- data/lib/pdk/template/renderer.rb +96 -96
- data/lib/pdk/template/template_dir.rb +67 -67
- data/lib/pdk/template.rb +59 -59
- data/lib/pdk/tests/unit.rb +252 -252
- data/lib/pdk/util/bundler.rb +259 -259
- data/lib/pdk/util/changelog_generator.rb +137 -137
- data/lib/pdk/util/env.rb +47 -47
- data/lib/pdk/util/filesystem.rb +138 -138
- data/lib/pdk/util/git.rb +179 -179
- data/lib/pdk/util/json_finder.rb +85 -85
- data/lib/pdk/util/puppet_strings.rb +125 -125
- data/lib/pdk/util/puppet_version.rb +266 -266
- data/lib/pdk/util/ruby_version.rb +179 -179
- data/lib/pdk/util/template_uri.rb +295 -295
- data/lib/pdk/util/vendored_file.rb +93 -93
- data/lib/pdk/util/version.rb +43 -43
- data/lib/pdk/util/windows/api_types.rb +82 -82
- data/lib/pdk/util/windows/file.rb +36 -36
- data/lib/pdk/util/windows/process.rb +79 -79
- data/lib/pdk/util/windows/string.rb +16 -16
- data/lib/pdk/util/windows.rb +15 -15
- data/lib/pdk/util.rb +278 -277
- data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -23
- data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -98
- data/lib/pdk/validate/external_command_validator.rb +208 -208
- data/lib/pdk/validate/internal_ruby_validator.rb +100 -100
- data/lib/pdk/validate/invokable_validator.rb +228 -228
- data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -86
- data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -78
- data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -20
- data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -133
- data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -66
- data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -137
- data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -21
- data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -80
- data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -19
- data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -88
- data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -50
- data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -20
- data/lib/pdk/validate/validator.rb +118 -118
- data/lib/pdk/validate/validator_group.rb +104 -104
- data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -95
- data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -19
- data/lib/pdk/validate.rb +94 -94
- data/lib/pdk/version.rb +4 -4
- data/lib/pdk.rb +76 -76
- data/locales/config.yaml +21 -21
- data/locales/pdk.pot +2094 -2094
- metadata +5 -6
data/lib/pdk/template.rb
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
require 'pdk'
|
|
2
|
-
|
|
3
|
-
module PDK
|
|
4
|
-
module Template
|
|
5
|
-
autoload :Fetcher, 'pdk/template/fetcher'
|
|
6
|
-
autoload :Renderer, 'pdk/template/renderer'
|
|
7
|
-
autoload :TemplateDir, 'pdk/template/template_dir'
|
|
8
|
-
|
|
9
|
-
MODULE_TEMPLATE_TYPE = :module_template
|
|
10
|
-
|
|
11
|
-
# Creates a TemplateDir object with the path or URL to the template
|
|
12
|
-
# and the block of code to run to be run while the template is available.
|
|
13
|
-
#
|
|
14
|
-
# The template directory is only guaranteed to be available on disk
|
|
15
|
-
# within the scope of the block passed to this method.
|
|
16
|
-
#
|
|
17
|
-
# @param uri [PDK::Util::TemplateURI] The path to a directory to use as the
|
|
18
|
-
# template or a URI to a git repository.
|
|
19
|
-
#
|
|
20
|
-
# @param context [PDK::Context::AbstractContext] The context in which the template will render to
|
|
21
|
-
#
|
|
22
|
-
# @yieldparam self [PDK::Template::TemplateDir] The initialised object with
|
|
23
|
-
# the template available on disk.
|
|
24
|
-
#
|
|
25
|
-
# @example Using a git repository as a template
|
|
26
|
-
# PDK::Template.with('https://github.com/puppetlabs/pdk-templates') do |t|
|
|
27
|
-
# t.render_module('module, PDK.context) do |filename, content, status|
|
|
28
|
-
# File.open(filename, 'w') do |file|
|
|
29
|
-
# ...
|
|
30
|
-
# end
|
|
31
|
-
# end
|
|
32
|
-
# end
|
|
33
|
-
#
|
|
34
|
-
# @raise [ArgumentError] If no block is given to this method.
|
|
35
|
-
# @raise [PDK::CLI::FatalError]
|
|
36
|
-
# @raise [ArgumentError]
|
|
37
|
-
#
|
|
38
|
-
# @api public
|
|
39
|
-
def self.with(uri, context)
|
|
40
|
-
unless block_given?
|
|
41
|
-
raise ArgumentError, _('%{class_name}.with must be passed a block.') % { class_name: name }
|
|
42
|
-
end
|
|
43
|
-
unless uri.is_a? PDK::Util::TemplateURI
|
|
44
|
-
raise ArgumentError, _('%{class_name}.with must be passed a PDK::Util::TemplateURI, got a %{uri_type}') % { uri_type: uri.class, class_name: name }
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
Fetcher.with(uri) do |fetcher|
|
|
48
|
-
template_dir = TemplateDir.instance(uri, fetcher.path, context)
|
|
49
|
-
template_dir.metadata = fetcher.metadata
|
|
50
|
-
|
|
51
|
-
template_type = uri.default? ? 'default' : 'custom'
|
|
52
|
-
PDK.analytics.event('TemplateDir', 'initialize', label: template_type)
|
|
53
|
-
|
|
54
|
-
yield template_dir
|
|
55
|
-
end
|
|
56
|
-
nil
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
1
|
+
require 'pdk'
|
|
2
|
+
|
|
3
|
+
module PDK
|
|
4
|
+
module Template
|
|
5
|
+
autoload :Fetcher, 'pdk/template/fetcher'
|
|
6
|
+
autoload :Renderer, 'pdk/template/renderer'
|
|
7
|
+
autoload :TemplateDir, 'pdk/template/template_dir'
|
|
8
|
+
|
|
9
|
+
MODULE_TEMPLATE_TYPE = :module_template
|
|
10
|
+
|
|
11
|
+
# Creates a TemplateDir object with the path or URL to the template
|
|
12
|
+
# and the block of code to run to be run while the template is available.
|
|
13
|
+
#
|
|
14
|
+
# The template directory is only guaranteed to be available on disk
|
|
15
|
+
# within the scope of the block passed to this method.
|
|
16
|
+
#
|
|
17
|
+
# @param uri [PDK::Util::TemplateURI] The path to a directory to use as the
|
|
18
|
+
# template or a URI to a git repository.
|
|
19
|
+
#
|
|
20
|
+
# @param context [PDK::Context::AbstractContext] The context in which the template will render to
|
|
21
|
+
#
|
|
22
|
+
# @yieldparam self [PDK::Template::TemplateDir] The initialised object with
|
|
23
|
+
# the template available on disk.
|
|
24
|
+
#
|
|
25
|
+
# @example Using a git repository as a template
|
|
26
|
+
# PDK::Template.with('https://github.com/puppetlabs/pdk-templates') do |t|
|
|
27
|
+
# t.render_module('module, PDK.context) do |filename, content, status|
|
|
28
|
+
# File.open(filename, 'w') do |file|
|
|
29
|
+
# ...
|
|
30
|
+
# end
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# @raise [ArgumentError] If no block is given to this method.
|
|
35
|
+
# @raise [PDK::CLI::FatalError]
|
|
36
|
+
# @raise [ArgumentError]
|
|
37
|
+
#
|
|
38
|
+
# @api public
|
|
39
|
+
def self.with(uri, context)
|
|
40
|
+
unless block_given?
|
|
41
|
+
raise ArgumentError, _('%{class_name}.with must be passed a block.') % { class_name: name }
|
|
42
|
+
end
|
|
43
|
+
unless uri.is_a? PDK::Util::TemplateURI
|
|
44
|
+
raise ArgumentError, _('%{class_name}.with must be passed a PDK::Util::TemplateURI, got a %{uri_type}') % { uri_type: uri.class, class_name: name }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
Fetcher.with(uri) do |fetcher|
|
|
48
|
+
template_dir = TemplateDir.instance(uri, fetcher.path, context)
|
|
49
|
+
template_dir.metadata = fetcher.metadata
|
|
50
|
+
|
|
51
|
+
template_type = uri.default? ? 'default' : 'custom'
|
|
52
|
+
PDK.analytics.event('TemplateDir', 'initialize', label: template_type)
|
|
53
|
+
|
|
54
|
+
yield template_dir
|
|
55
|
+
end
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/pdk/tests/unit.rb
CHANGED
|
@@ -1,252 +1,252 @@
|
|
|
1
|
-
require 'pdk'
|
|
2
|
-
|
|
3
|
-
module PDK
|
|
4
|
-
module Test
|
|
5
|
-
class Unit
|
|
6
|
-
def self.cmd(tests, opts = {})
|
|
7
|
-
rake_args = opts[:parallel] ? 'parallel_spec_standalone' : 'spec_standalone'
|
|
8
|
-
rake_args += "[#{tests}]" unless tests.nil? || tests.empty?
|
|
9
|
-
rake_args
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def self.rake_bin
|
|
13
|
-
require 'pdk/util'
|
|
14
|
-
|
|
15
|
-
@rake ||= File.join(PDK::Util.module_root, 'bin', 'rake')
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def self.cmd_with_args(task)
|
|
19
|
-
require 'pdk/util/ruby_version'
|
|
20
|
-
|
|
21
|
-
argv = [rake_bin, task]
|
|
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'
|
|
40
|
-
|
|
41
|
-
command = PDK::CLI::Exec::InteractiveCommand.new(*cmd_with_args(task)).tap do |c|
|
|
42
|
-
c.context = :module
|
|
43
|
-
c.environment = environment
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
command.execute!
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def self.parallel_with_no_tests?(ran_in_parallel, json_result, result)
|
|
50
|
-
ran_in_parallel && json_result.empty? &&
|
|
51
|
-
((!result[:exit_code].zero? && result[:stderr].strip =~ %r{Pass files or folders to run$}) ||
|
|
52
|
-
result[:stderr].strip =~ %r{No files for parallel_spec to run against$})
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def self.print_failure(result, exception)
|
|
56
|
-
$stderr.puts ''
|
|
57
|
-
result[:stdout].each_line { |line| $stderr.puts line.rstrip } unless result[:stdout].nil?
|
|
58
|
-
result[:stderr].each_line { |line| $stderr.puts line.rstrip } unless result[:stderr].nil?
|
|
59
|
-
$stderr.puts ''
|
|
60
|
-
raise PDK::CLI::FatalError, exception
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def self.tear_down
|
|
64
|
-
result = rake('spec_clean', _('Cleaning up after running unit tests.'))
|
|
65
|
-
|
|
66
|
-
return if result[:exit_code].zero?
|
|
67
|
-
|
|
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'))
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def self.setup
|
|
73
|
-
result = rake('spec_prep', _('Preparing to run the unit tests.'))
|
|
74
|
-
|
|
75
|
-
return if result[:exit_code].zero?
|
|
76
|
-
|
|
77
|
-
tear_down
|
|
78
|
-
|
|
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.'))
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def self.invoke(report, options = {})
|
|
84
|
-
require 'pdk/util'
|
|
85
|
-
require 'pdk/util/bundler'
|
|
86
|
-
|
|
87
|
-
PDK::Util::Bundler.ensure_binstubs!('rake', 'rspec-core')
|
|
88
|
-
|
|
89
|
-
setup
|
|
90
|
-
|
|
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?
|
|
97
|
-
|
|
98
|
-
environment = { 'CI_SPEC_OPTIONS' => '--format j' }
|
|
99
|
-
environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
|
|
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
|
-
result = rake(cmd(tests, options), spinner_msg, environment)
|
|
113
|
-
|
|
114
|
-
json_result = if options[:parallel]
|
|
115
|
-
PDK::Util.find_all_json_in(result[:stdout])
|
|
116
|
-
else
|
|
117
|
-
PDK::Util.find_first_json_in(result[:stdout])
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
if parallel_with_no_tests?(options[:parallel], json_result, result)
|
|
121
|
-
json_result = [{ 'messages' => ['No examples found.'] }]
|
|
122
|
-
result[:exit_code] = 0
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
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?
|
|
126
|
-
|
|
127
|
-
json_result = merge_json_results(json_result) if options[:parallel]
|
|
128
|
-
|
|
129
|
-
parse_output(report, json_result, result[:duration])
|
|
130
|
-
|
|
131
|
-
result[:exit_code]
|
|
132
|
-
ensure
|
|
133
|
-
tear_down if options[:'clean-fixtures']
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def self.parse_output(report, json_data, duration)
|
|
137
|
-
# Output messages to stderr.
|
|
138
|
-
json_data['messages'] && json_data['messages'].each { |msg| $stderr.puts msg }
|
|
139
|
-
|
|
140
|
-
example_results = {
|
|
141
|
-
# Only possibilities are passed, failed, pending:
|
|
142
|
-
# https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example.rb#L548
|
|
143
|
-
'passed' => [],
|
|
144
|
-
'failed' => [],
|
|
145
|
-
'pending' => [],
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
json_data['examples'] && json_data['examples'].each do |ex|
|
|
149
|
-
example_results[ex['status']] << ex if example_results.key?(ex['status'])
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
example_results.each do |result, examples|
|
|
153
|
-
# Translate rspec example results to JUnit XML testcase results
|
|
154
|
-
state = case result
|
|
155
|
-
when 'passed' then :passed
|
|
156
|
-
when 'failed' then :failure
|
|
157
|
-
when 'pending' then :skipped
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
examples.each do |ex|
|
|
161
|
-
report.add_event(
|
|
162
|
-
source: 'rspec',
|
|
163
|
-
state: state,
|
|
164
|
-
file: ex['file_path'],
|
|
165
|
-
line: ex['line_number'],
|
|
166
|
-
test: ex['full_description'],
|
|
167
|
-
severity: ex['status'],
|
|
168
|
-
message: ex['pending_message'] || (ex['exception'] && ex['exception']['message']) || nil,
|
|
169
|
-
trace: (ex['exception'] && ex['exception']['backtrace']) || nil,
|
|
170
|
-
)
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
return unless json_data['summary']
|
|
175
|
-
|
|
176
|
-
# TODO: standardize summary output
|
|
177
|
-
$stderr.puts ' ' << _('Evaluated %{total} tests in %{duration} seconds: %{failures} failures, %{pending} pending.') % {
|
|
178
|
-
total: json_data['summary']['example_count'],
|
|
179
|
-
duration: duration,
|
|
180
|
-
failures: json_data['summary']['failure_count'],
|
|
181
|
-
pending: json_data['summary']['pending_count'],
|
|
182
|
-
}
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def self.merge_json_results(json_data)
|
|
186
|
-
require 'set'
|
|
187
|
-
|
|
188
|
-
merged_json_result = {}
|
|
189
|
-
|
|
190
|
-
# Merge messages
|
|
191
|
-
message_set = Set.new
|
|
192
|
-
json_data.each do |json|
|
|
193
|
-
next unless json['messages']
|
|
194
|
-
message_set |= json['messages']
|
|
195
|
-
end
|
|
196
|
-
merged_json_result['messages'] = message_set.to_a
|
|
197
|
-
|
|
198
|
-
# Merge examples
|
|
199
|
-
all_examples = []
|
|
200
|
-
json_data.each do |json|
|
|
201
|
-
next unless json['examples']
|
|
202
|
-
all_examples.concat json['examples']
|
|
203
|
-
end
|
|
204
|
-
merged_json_result['examples'] = all_examples
|
|
205
|
-
|
|
206
|
-
# Merge summaries
|
|
207
|
-
summary_hash = {
|
|
208
|
-
'example_count' => 0,
|
|
209
|
-
'failure_count' => 0,
|
|
210
|
-
'pending_count' => 0,
|
|
211
|
-
}
|
|
212
|
-
json_data.each do |json|
|
|
213
|
-
next unless json['summary']
|
|
214
|
-
summary_hash['example_count'] += json['summary']['example_count']
|
|
215
|
-
summary_hash['failure_count'] += json['summary']['failure_count']
|
|
216
|
-
summary_hash['pending_count'] += json['summary']['pending_count']
|
|
217
|
-
end
|
|
218
|
-
merged_json_result['summary'] = summary_hash
|
|
219
|
-
|
|
220
|
-
merged_json_result
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# @return array of { :id, :full_description }
|
|
224
|
-
def self.list(options = {})
|
|
225
|
-
require 'pdk/util'
|
|
226
|
-
require 'pdk/util/bundler'
|
|
227
|
-
|
|
228
|
-
PDK::Util::Bundler.ensure_binstubs!('rake')
|
|
229
|
-
|
|
230
|
-
environment = {}
|
|
231
|
-
environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
|
|
232
|
-
|
|
233
|
-
output = rake('spec_list_json', _('Finding unit tests.'), environment)
|
|
234
|
-
|
|
235
|
-
rspec_json = PDK::Util.find_first_json_in(output[:stdout])
|
|
236
|
-
raise PDK::CLI::FatalError, _('Failed to find valid JSON in output from rspec: %{output}' % { output: output[:stdout] }) unless rspec_json
|
|
237
|
-
if rspec_json['examples'].empty?
|
|
238
|
-
rspec_message = rspec_json['messages'][0]
|
|
239
|
-
return [] if rspec_message == 'No examples found.'
|
|
240
|
-
|
|
241
|
-
raise PDK::CLI::FatalError, _('Unable to enumerate examples. rspec reported: %{message}' % { message: rspec_message })
|
|
242
|
-
else
|
|
243
|
-
examples = []
|
|
244
|
-
rspec_json['examples'].each do |example|
|
|
245
|
-
examples << { file_path: example['file_path'], id: example['id'], full_description: example['full_description'] }
|
|
246
|
-
end
|
|
247
|
-
examples
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
end
|
|
1
|
+
require 'pdk'
|
|
2
|
+
|
|
3
|
+
module PDK
|
|
4
|
+
module Test
|
|
5
|
+
class Unit
|
|
6
|
+
def self.cmd(tests, opts = {})
|
|
7
|
+
rake_args = opts[:parallel] ? 'parallel_spec_standalone' : 'spec_standalone'
|
|
8
|
+
rake_args += "[#{tests}]" unless tests.nil? || tests.empty?
|
|
9
|
+
rake_args
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.rake_bin
|
|
13
|
+
require 'pdk/util'
|
|
14
|
+
|
|
15
|
+
@rake ||= File.join(PDK::Util.module_root, 'bin', 'rake')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.cmd_with_args(task)
|
|
19
|
+
require 'pdk/util/ruby_version'
|
|
20
|
+
|
|
21
|
+
argv = [rake_bin, task]
|
|
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'
|
|
40
|
+
|
|
41
|
+
command = PDK::CLI::Exec::InteractiveCommand.new(*cmd_with_args(task)).tap do |c|
|
|
42
|
+
c.context = :module
|
|
43
|
+
c.environment = environment
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
command.execute!
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.parallel_with_no_tests?(ran_in_parallel, json_result, result)
|
|
50
|
+
ran_in_parallel && json_result.empty? &&
|
|
51
|
+
((!result[:exit_code].zero? && result[:stderr].strip =~ %r{Pass files or folders to run$}) ||
|
|
52
|
+
result[:stderr].strip =~ %r{No files for parallel_spec to run against$})
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.print_failure(result, exception)
|
|
56
|
+
$stderr.puts ''
|
|
57
|
+
result[:stdout].each_line { |line| $stderr.puts line.rstrip } unless result[:stdout].nil?
|
|
58
|
+
result[:stderr].each_line { |line| $stderr.puts line.rstrip } unless result[:stderr].nil?
|
|
59
|
+
$stderr.puts ''
|
|
60
|
+
raise PDK::CLI::FatalError, exception
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.tear_down
|
|
64
|
+
result = rake('spec_clean', _('Cleaning up after running unit tests.'))
|
|
65
|
+
|
|
66
|
+
return if result[:exit_code].zero?
|
|
67
|
+
|
|
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'))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.setup
|
|
73
|
+
result = rake('spec_prep', _('Preparing to run the unit tests.'))
|
|
74
|
+
|
|
75
|
+
return if result[:exit_code].zero?
|
|
76
|
+
|
|
77
|
+
tear_down
|
|
78
|
+
|
|
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.'))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.invoke(report, options = {})
|
|
84
|
+
require 'pdk/util'
|
|
85
|
+
require 'pdk/util/bundler'
|
|
86
|
+
|
|
87
|
+
PDK::Util::Bundler.ensure_binstubs!('rake', 'rspec-core')
|
|
88
|
+
|
|
89
|
+
setup
|
|
90
|
+
|
|
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?
|
|
97
|
+
|
|
98
|
+
environment = { 'CI_SPEC_OPTIONS' => '--format j' }
|
|
99
|
+
environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
|
|
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
|
+
result = rake(cmd(tests, options), spinner_msg, environment)
|
|
113
|
+
|
|
114
|
+
json_result = if options[:parallel]
|
|
115
|
+
PDK::Util.find_all_json_in(result[:stdout])
|
|
116
|
+
else
|
|
117
|
+
PDK::Util.find_first_json_in(result[:stdout])
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
if parallel_with_no_tests?(options[:parallel], json_result, result)
|
|
121
|
+
json_result = [{ 'messages' => ['No examples found.'] }]
|
|
122
|
+
result[:exit_code] = 0
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
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?
|
|
126
|
+
|
|
127
|
+
json_result = merge_json_results(json_result) if options[:parallel]
|
|
128
|
+
|
|
129
|
+
parse_output(report, json_result, result[:duration])
|
|
130
|
+
|
|
131
|
+
result[:exit_code]
|
|
132
|
+
ensure
|
|
133
|
+
tear_down if options[:'clean-fixtures']
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def self.parse_output(report, json_data, duration)
|
|
137
|
+
# Output messages to stderr.
|
|
138
|
+
json_data['messages'] && json_data['messages'].each { |msg| $stderr.puts msg }
|
|
139
|
+
|
|
140
|
+
example_results = {
|
|
141
|
+
# Only possibilities are passed, failed, pending:
|
|
142
|
+
# https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/example.rb#L548
|
|
143
|
+
'passed' => [],
|
|
144
|
+
'failed' => [],
|
|
145
|
+
'pending' => [],
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
json_data['examples'] && json_data['examples'].each do |ex|
|
|
149
|
+
example_results[ex['status']] << ex if example_results.key?(ex['status'])
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
example_results.each do |result, examples|
|
|
153
|
+
# Translate rspec example results to JUnit XML testcase results
|
|
154
|
+
state = case result
|
|
155
|
+
when 'passed' then :passed
|
|
156
|
+
when 'failed' then :failure
|
|
157
|
+
when 'pending' then :skipped
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
examples.each do |ex|
|
|
161
|
+
report.add_event(
|
|
162
|
+
source: 'rspec',
|
|
163
|
+
state: state,
|
|
164
|
+
file: ex['file_path'],
|
|
165
|
+
line: ex['line_number'],
|
|
166
|
+
test: ex['full_description'],
|
|
167
|
+
severity: ex['status'],
|
|
168
|
+
message: ex['pending_message'] || (ex['exception'] && ex['exception']['message']) || nil,
|
|
169
|
+
trace: (ex['exception'] && ex['exception']['backtrace']) || nil,
|
|
170
|
+
)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
return unless json_data['summary']
|
|
175
|
+
|
|
176
|
+
# TODO: standardize summary output
|
|
177
|
+
$stderr.puts ' ' << _('Evaluated %{total} tests in %{duration} seconds: %{failures} failures, %{pending} pending.') % {
|
|
178
|
+
total: json_data['summary']['example_count'],
|
|
179
|
+
duration: duration,
|
|
180
|
+
failures: json_data['summary']['failure_count'],
|
|
181
|
+
pending: json_data['summary']['pending_count'],
|
|
182
|
+
}
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def self.merge_json_results(json_data)
|
|
186
|
+
require 'set'
|
|
187
|
+
|
|
188
|
+
merged_json_result = {}
|
|
189
|
+
|
|
190
|
+
# Merge messages
|
|
191
|
+
message_set = Set.new
|
|
192
|
+
json_data.each do |json|
|
|
193
|
+
next unless json['messages']
|
|
194
|
+
message_set |= json['messages']
|
|
195
|
+
end
|
|
196
|
+
merged_json_result['messages'] = message_set.to_a
|
|
197
|
+
|
|
198
|
+
# Merge examples
|
|
199
|
+
all_examples = []
|
|
200
|
+
json_data.each do |json|
|
|
201
|
+
next unless json['examples']
|
|
202
|
+
all_examples.concat json['examples']
|
|
203
|
+
end
|
|
204
|
+
merged_json_result['examples'] = all_examples
|
|
205
|
+
|
|
206
|
+
# Merge summaries
|
|
207
|
+
summary_hash = {
|
|
208
|
+
'example_count' => 0,
|
|
209
|
+
'failure_count' => 0,
|
|
210
|
+
'pending_count' => 0,
|
|
211
|
+
}
|
|
212
|
+
json_data.each do |json|
|
|
213
|
+
next unless json['summary']
|
|
214
|
+
summary_hash['example_count'] += json['summary']['example_count']
|
|
215
|
+
summary_hash['failure_count'] += json['summary']['failure_count']
|
|
216
|
+
summary_hash['pending_count'] += json['summary']['pending_count']
|
|
217
|
+
end
|
|
218
|
+
merged_json_result['summary'] = summary_hash
|
|
219
|
+
|
|
220
|
+
merged_json_result
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# @return array of { :id, :full_description }
|
|
224
|
+
def self.list(options = {})
|
|
225
|
+
require 'pdk/util'
|
|
226
|
+
require 'pdk/util/bundler'
|
|
227
|
+
|
|
228
|
+
PDK::Util::Bundler.ensure_binstubs!('rake')
|
|
229
|
+
|
|
230
|
+
environment = {}
|
|
231
|
+
environment['PUPPET_GEM_VERSION'] = options[:puppet] if options[:puppet]
|
|
232
|
+
|
|
233
|
+
output = rake('spec_list_json', _('Finding unit tests.'), environment)
|
|
234
|
+
|
|
235
|
+
rspec_json = PDK::Util.find_first_json_in(output[:stdout])
|
|
236
|
+
raise PDK::CLI::FatalError, _('Failed to find valid JSON in output from rspec: %{output}' % { output: output[:stdout] }) unless rspec_json
|
|
237
|
+
if rspec_json['examples'].empty?
|
|
238
|
+
rspec_message = rspec_json['messages'][0]
|
|
239
|
+
return [] if rspec_message == 'No examples found.'
|
|
240
|
+
|
|
241
|
+
raise PDK::CLI::FatalError, _('Unable to enumerate examples. rspec reported: %{message}' % { message: rspec_message })
|
|
242
|
+
else
|
|
243
|
+
examples = []
|
|
244
|
+
rspec_json['examples'].each do |example|
|
|
245
|
+
examples << { file_path: example['file_path'], id: example['id'], full_description: example['full_description'] }
|
|
246
|
+
end
|
|
247
|
+
examples
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|