puppet-check 1.5.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +39 -4
- data/README.md +35 -50
- data/lib/puppet-check.rb +63 -47
- data/lib/puppet-check/cli.rb +21 -17
- data/lib/puppet-check/data_parser.rb +55 -28
- data/lib/puppet-check/output_results.rb +5 -4
- data/lib/puppet-check/puppet_parser.rb +31 -16
- data/lib/puppet-check/rspec_puppet_support.rb +34 -11
- data/lib/puppet-check/ruby_parser.rb +6 -8
- data/lib/puppet-check/tasks.rb +17 -13
- data/spec/fixtures/manifests/eof_syntax.pp +4 -0
- data/spec/fixtures/task_metadata/task_bad.json +10 -0
- data/spec/fixtures/task_metadata/task_good.json +16 -0
- data/spec/puppet-check/cli_spec.rb +9 -43
- data/spec/puppet-check/data_parser_spec.rb +27 -11
- data/spec/puppet-check/output_results_spec.rb +9 -18
- data/spec/puppet-check/puppet_parser_spec.rb +22 -18
- data/spec/puppet-check/regression_check_spec.rb +1 -3
- data/spec/puppet-check/rspec_puppet_support_spec.rb +5 -1
- data/spec/puppet-check/ruby_parser_spec.rb +8 -4
- data/spec/puppet-check/tasks_spec.rb +13 -3
- data/spec/puppet-check_spec.rb +11 -12
- data/spec/system/system_spec.rb +8 -14
- metadata +51 -32
@@ -4,8 +4,6 @@ require_relative '../puppet-check'
|
|
4
4
|
class DataParser
|
5
5
|
# checks yaml (.yaml/.yml)
|
6
6
|
def self.yaml(files)
|
7
|
-
return if files.empty?
|
8
|
-
|
9
7
|
require 'yaml'
|
10
8
|
|
11
9
|
files.each do |file|
|
@@ -18,7 +16,7 @@ class DataParser
|
|
18
16
|
warnings = []
|
19
17
|
|
20
18
|
# perform some rudimentary hiera checks if data exists and is hieradata
|
21
|
-
warnings = hiera(parsed, file)
|
19
|
+
warnings = hiera(parsed, file) if parsed && (File.basename(file) != 'hiera.yaml')
|
22
20
|
|
23
21
|
next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
|
24
22
|
PuppetCheck.settings[:clean_files].push(file.to_s)
|
@@ -28,15 +26,19 @@ class DataParser
|
|
28
26
|
|
29
27
|
# checks eyaml (.eyaml/.eyml)
|
30
28
|
def self.eyaml(files, public, private)
|
31
|
-
return if files.empty?
|
32
|
-
|
33
29
|
require 'openssl'
|
34
30
|
|
35
31
|
# keys specified?
|
36
|
-
|
32
|
+
if public.nil? || private.nil?
|
33
|
+
PuppetCheck.settings[:ignored_files].concat(files)
|
34
|
+
return warn 'Public X509 and/or Private RSA PKCS7 certs were not specified. EYAML checks will not be executed.'
|
35
|
+
end
|
37
36
|
|
38
37
|
# keys exist?
|
39
|
-
|
38
|
+
unless File.file?(public) && File.file?(private)
|
39
|
+
PuppetCheck.settings[:ignored_files].concat(files)
|
40
|
+
return warn 'Specified Public X509 and/or Private RSA PKCS7 certs do not exist. EYAML checks will not be executed.'
|
41
|
+
end
|
40
42
|
|
41
43
|
# setup decryption
|
42
44
|
rsa = OpenSSL::PKey::RSA.new(File.read(private))
|
@@ -52,14 +54,14 @@ class DataParser
|
|
52
54
|
|
53
55
|
# check yaml syntax
|
54
56
|
begin
|
55
|
-
parsed = YAML.
|
57
|
+
parsed = YAML.load_file(decrypted)
|
56
58
|
rescue StandardError => err
|
57
59
|
PuppetCheck.settings[:error_files].push("#{file}:\n#{err.to_s.gsub("(#{file}): ", '')}")
|
58
60
|
else
|
59
61
|
warnings = []
|
60
62
|
|
61
63
|
# perform some rudimentary hiera checks if data exists and is hieradata
|
62
|
-
warnings = hiera(parsed, file)
|
64
|
+
warnings = hiera(parsed, file) if parsed
|
63
65
|
|
64
66
|
next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
|
65
67
|
PuppetCheck.settings[:clean_files].push(file.to_s)
|
@@ -69,8 +71,6 @@ class DataParser
|
|
69
71
|
|
70
72
|
# checks json (.json)
|
71
73
|
def self.json(files)
|
72
|
-
return if files.empty?
|
73
|
-
|
74
74
|
require 'json'
|
75
75
|
|
76
76
|
files.each do |file|
|
@@ -85,7 +85,7 @@ class DataParser
|
|
85
85
|
# check metadata.json
|
86
86
|
if File.basename(file) == 'metadata.json'
|
87
87
|
# metadata-json-lint has issues and is essentially no longer maintained, so here is an improved and leaner version of it
|
88
|
-
require '
|
88
|
+
require 'rubygems/util/licenses'
|
89
89
|
|
90
90
|
# check for errors
|
91
91
|
errors = []
|
@@ -97,9 +97,8 @@ class DataParser
|
|
97
97
|
|
98
98
|
# check requirements and dependencies keys
|
99
99
|
%w[requirements dependencies].each do |key|
|
100
|
-
# skip if key is missing or
|
101
|
-
next
|
102
|
-
next if parsed[key].empty?
|
100
|
+
# skip if key is missing or value is an empty string, array, or hash
|
101
|
+
next if !parsed.key?(key) || parsed[key].empty?
|
103
102
|
|
104
103
|
# check that dependencies and requirements are an array of hashes
|
105
104
|
next errors.push("Field '#{key}' is not an array of hashes.") unless (parsed[key].is_a? Array) && (parsed[key][0].is_a? Hash)
|
@@ -113,14 +112,14 @@ class DataParser
|
|
113
112
|
names << name
|
114
113
|
|
115
114
|
# warn and skip if key is missing
|
116
|
-
next warnings.push("'#{req_dep['name']}' is missing a 'version_requirement' key.") if req_dep['version_requirement'].
|
115
|
+
next warnings.push("'#{req_dep['name']}' is missing a 'version_requirement' key.") if req_dep['version_requirement'].nil?
|
117
116
|
|
118
117
|
# warn and skip if no upper bound
|
119
118
|
next warnings.push("'#{req_dep['name']}' is missing an upper bound.") unless req_dep['version_requirement'].include?('<')
|
120
119
|
|
121
120
|
# check for semantic versioning
|
122
|
-
if key == 'dependencies'
|
123
|
-
warnings.push("'#{req_dep['name']}' has non-semantic versioning in its 'version_requirement' key.")
|
121
|
+
if key == 'dependencies' && req_dep['version_requirement'] !~ /\d+\.\d+\.\d+.*\d+\.\d+\.\d+/
|
122
|
+
warnings.push("'#{req_dep['name']}' has non-semantic versioning in its 'version_requirement' key.")
|
124
123
|
end
|
125
124
|
end
|
126
125
|
end
|
@@ -161,14 +160,38 @@ class DataParser
|
|
161
160
|
warnings.push('Recommended field \'operatingsystem_support\' not found.')
|
162
161
|
end
|
163
162
|
|
164
|
-
# check for spdx license
|
165
|
-
if parsed.key?('license') && !
|
163
|
+
# check for spdx license
|
164
|
+
if parsed.key?('license') && !Gem::Licenses.match?(parsed['license']) && parsed['license'] !~ /[pP]roprietary/
|
166
165
|
warnings.push("License identifier '#{parsed['license']}' is not in the SPDX list: http://spdx.org/licenses/")
|
167
166
|
end
|
168
|
-
# assume this is
|
169
|
-
|
167
|
+
# assume this is task metadata if it has this key
|
168
|
+
elsif parsed.key?('description')
|
169
|
+
# check that description is a string
|
170
|
+
warnings.push('description value is not a String') unless parsed['description'].is_a?(String)
|
171
|
+
# check that input_method is one of three possible values
|
172
|
+
if parsed.key?('input_method')
|
173
|
+
if parsed['input_method'].is_a?(String)
|
174
|
+
warnings.push('input_method value is not one of environment, stdin, or powershell') unless %w[environment stdin powershell].include?(parsed['input_method'])
|
175
|
+
else
|
176
|
+
warnings.push('input_method value is not a String')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
# check that parameters is a hash
|
180
|
+
if parsed.key?('parameters') && !parsed['parameters'].is_a?(Hash)
|
181
|
+
warnings.push('parameters value is not a Hash')
|
182
|
+
end
|
183
|
+
# check that puppet_task_version is an integer
|
184
|
+
if parsed.key?('puppet_task_version') && !parsed['puppet_task_version'].is_a?(Integer)
|
185
|
+
warnings.push('puppet_task_version value is not an Integer')
|
186
|
+
end
|
187
|
+
# check that supports_noop is a boolean
|
188
|
+
if parsed.key?('supports_noop') && !(parsed['supports_noop'].is_a?(TrueClass) || parsed['supports_noop'].is_a?(FalseClass))
|
189
|
+
warnings.push('supports_noop value is not a Boolean')
|
190
|
+
end
|
191
|
+
# assume this is hieradata and ensure it is non-empty
|
192
|
+
elsif parsed
|
170
193
|
# perform some rudimentary hiera checks if data exists
|
171
|
-
warnings = hiera(parsed, file)
|
194
|
+
warnings = hiera(parsed, file)
|
172
195
|
end
|
173
196
|
next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
|
174
197
|
PuppetCheck.settings[:clean_files].push(file.to_s)
|
@@ -181,15 +204,19 @@ class DataParser
|
|
181
204
|
private_class_method :method
|
182
205
|
warnings = []
|
183
206
|
|
184
|
-
data
|
185
|
-
|
186
|
-
|
187
|
-
|
207
|
+
# disregard nil/undef value data check if default values (common)
|
208
|
+
unless file =~ /^common/
|
209
|
+
# unless /^common/.match?(file) TODO: use when ruby >= 2.4
|
210
|
+
data.each do |key, value|
|
211
|
+
# check for nil values in the data (nil keys are fine)
|
212
|
+
if (value.is_a?(Hash) && value.values.any?(&:nil?)) || value.nil?
|
213
|
+
warnings.push("Value(s) missing in key '#{key}'.")
|
214
|
+
end
|
188
215
|
end
|
189
216
|
end
|
190
217
|
|
191
218
|
# check that '---' does not show up more than once in the hieradata
|
192
|
-
warnings.push('The string --- appears more than once in this data and Hiera
|
219
|
+
warnings.push('The string --- appears more than once in this data and Hiera may fail to parse it correctly.') if File.read(file).scan(/---/).count >= 2
|
193
220
|
|
194
221
|
warnings
|
195
222
|
end
|
@@ -22,7 +22,7 @@ class OutputResults
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# output the results as yaml or json
|
25
|
-
def self.markup
|
25
|
+
def self.markup(settings)
|
26
26
|
# generate output hash
|
27
27
|
hash = {}
|
28
28
|
hash['errors'] = PuppetCheck.settings[:error_files] unless PuppetCheck.settings[:error_files].empty?
|
@@ -31,14 +31,15 @@ class OutputResults
|
|
31
31
|
hash['ignored'] = PuppetCheck.settings[:ignored_files] unless PuppetCheck.settings[:ignored_files].empty?
|
32
32
|
|
33
33
|
# convert hash to markup language
|
34
|
-
|
34
|
+
case settings[:output_format]
|
35
|
+
when 'yaml'
|
35
36
|
require 'yaml'
|
36
37
|
puts Psych.dump(hash, indentation: 2)
|
37
|
-
|
38
|
+
when 'json'
|
38
39
|
require 'json'
|
39
40
|
puts JSON.pretty_generate(hash)
|
40
41
|
else
|
41
|
-
raise "puppet-check: Unsupported output format '#{
|
42
|
+
raise "puppet-check: Unsupported output format '#{settings[:output_format]}' was specified."
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
@@ -4,33 +4,53 @@ require_relative '../puppet-check'
|
|
4
4
|
# executes diagnostics on puppet files
|
5
5
|
class PuppetParser
|
6
6
|
# checks puppet (.pp)
|
7
|
-
def self.manifest(files,
|
8
|
-
return if files.empty?
|
9
|
-
|
7
|
+
def self.manifest(files, style, pl_args)
|
10
8
|
require 'puppet/face'
|
11
9
|
|
12
10
|
# prepare the Puppet settings for the error checking
|
13
11
|
Puppet.initialize_settings unless Puppet.settings.app_defaults_initialized?
|
14
|
-
Puppet[:parser] = 'future' if future && (Puppet::PUPPETVERSION.to_i < 4)
|
15
12
|
|
16
13
|
files.each do |file|
|
17
|
-
# setup error logging and collection
|
14
|
+
# setup error logging and collection; warnings logged for all versions, but errors for only puppet < 6.5
|
18
15
|
errors = []
|
19
16
|
Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(errors))
|
20
17
|
|
21
18
|
# check puppet syntax
|
22
19
|
begin
|
23
|
-
|
20
|
+
# initialize message
|
21
|
+
message = ''
|
22
|
+
# in puppet >= 6.5 the return of this method is a hash with the error
|
23
|
+
new_error = Puppet::Face[:parser, :current].validate(file)
|
24
|
+
# puppet 6.5 output format is now a hash from the face api
|
25
|
+
if Gem::Version.new(Puppet::PUPPETVERSION) >= Gem::Version.new('6.5.0') && new_error != {}
|
26
|
+
message = new_error.values.map(&:to_s).join("\n").gsub(/ \(file: #{File.absolute_path(file)}(, |\))/, '').gsub(/Could not parse.*: /, '')
|
27
|
+
end
|
24
28
|
# this is the actual error that we need to rescue Puppet::Face from
|
25
29
|
rescue SystemExit
|
26
|
-
# puppet 5
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
# puppet 5.4-6.4 has a new validator output format and eof errors have fake dir env info
|
31
|
+
if Gem::Version.new(Puppet::PUPPETVERSION) >= Gem::Version.new('5.4') && Gem::Version.new(Puppet::PUPPETVERSION) < Gem::Version.new('6.5')
|
32
|
+
message = errors.map(&:to_s).join("\n").gsub(/file: #{File.absolute_path(file)}(, |\))/, '').gsub(/Could not parse.*: /, '')
|
33
|
+
# puppet 5.0-5.2 can only do one error per line and outputs fake dir env info
|
34
|
+
elsif Gem::Version.new(Puppet::PUPPETVERSION) >= Gem::Version.new('5.0') && Gem::Version.new(Puppet::PUPPETVERSION) < Gem::Version.new('5.3')
|
35
|
+
message = errors.map(&:to_s).join("\n").gsub("#{File.absolute_path(file)}:", '').gsub(/Could not parse.*: /, '')
|
36
|
+
end
|
37
|
+
# puppet < 5 and 5.3 parser output style
|
38
|
+
message = errors.map(&:to_s).join("\n").gsub("#{File.absolute_path(file)}:", '')
|
30
39
|
end
|
40
|
+
# output message
|
41
|
+
next PuppetCheck.settings[:error_files].push("#{file}:\n#{message}") unless message.empty?
|
31
42
|
|
32
43
|
# initialize warnings with output from the parser if it exists, since the output is warnings if Puppet::Face did not trigger a SystemExit
|
33
|
-
warnings =
|
44
|
+
warnings = "#{file}:"
|
45
|
+
unless errors.empty?
|
46
|
+
# puppet 5.4-5.x has a new validator output format
|
47
|
+
warnings << if Gem::Version.new(Puppet::PUPPETVERSION) >= Gem::Version.new('5.4')
|
48
|
+
"\n#{errors.map(&:to_s).join("\n").gsub("file: #{File.absolute_path(file)}, ", '')}"
|
49
|
+
# puppet <= 5.3 validator output format
|
50
|
+
else
|
51
|
+
"\n#{errors.map(&:to_s).join("\n").gsub("#{File.absolute_path(file)}:", '')}"
|
52
|
+
end
|
53
|
+
end
|
34
54
|
Puppet::Util::Log.close_all
|
35
55
|
|
36
56
|
# check puppet style
|
@@ -62,14 +82,9 @@ class PuppetParser
|
|
62
82
|
|
63
83
|
# checks puppet template (.epp)
|
64
84
|
def self.template(files)
|
65
|
-
return if files.empty?
|
66
|
-
|
67
85
|
require 'puppet/pops'
|
68
86
|
|
69
87
|
files.each do |file|
|
70
|
-
# puppet before version 4 cannot check template syntax
|
71
|
-
next PuppetCheck.settings[:ignored_files].push("#{file}: ignored due to Puppet < 4") if Puppet::PUPPETVERSION.to_i < 4
|
72
|
-
|
73
88
|
# check puppet template syntax
|
74
89
|
begin
|
75
90
|
# credits to gds-operations/puppet-syntax for the parser function call
|
@@ -3,22 +3,22 @@ class RSpecPuppetSupport
|
|
3
3
|
# code diagram:
|
4
4
|
# 'puppetcheck:spec' task invokes 'run'
|
5
5
|
# 'run' invokes 'file_setup' always and 'dependency_setup' if metadata.json exists
|
6
|
-
# 'dependency_setup' invokes 'git/forge/hg' if dependencies exist and git/forge/hg is download option
|
6
|
+
# 'dependency_setup' invokes 'git/forge/svn/hg' if dependencies exist and git/forge/svn/hg is download option
|
7
7
|
# 'git/forge/svn/hg' downloads module fixture appropriately
|
8
8
|
|
9
9
|
# prepare the spec fixtures directory for rspec-puppet testing
|
10
10
|
def self.run
|
11
11
|
# ensure this method does not do anything inside module dependencies
|
12
12
|
specdirs = Dir.glob('**/spec').reject { |dir| dir =~ /fixtures/ }
|
13
|
-
return if specdirs.
|
13
|
+
return if specdirs.empty?
|
14
14
|
|
15
15
|
# setup fixtures for rspec-puppet testing
|
16
16
|
specdirs.each do |specdir|
|
17
17
|
# skip to next specdir if it does not seem like a puppet module
|
18
|
-
next unless File.directory?(specdir
|
18
|
+
next unless File.directory?("#{specdir}/../manifests")
|
19
19
|
|
20
20
|
# change to module directory
|
21
|
-
Dir.chdir(specdir
|
21
|
+
Dir.chdir("#{specdir}/..")
|
22
22
|
|
23
23
|
# grab the module name from the directory name of the module to pass to file_setup
|
24
24
|
file_setup(File.basename(Dir.pwd))
|
@@ -40,11 +40,21 @@ class RSpecPuppetSupport
|
|
40
40
|
File.write('spec/fixtures/manifests/site.pp', '') unless File.file?('spec/fixtures/manifests/site.pp')
|
41
41
|
|
42
42
|
# symlink the module into spec/fixtures/modules
|
43
|
-
|
43
|
+
if File.exist?("spec/fixtures/modules/#{module_name}")
|
44
|
+
# check if target is a symlink
|
45
|
+
if File.symlink?("spec/fixtures/modules/#{module_name}")
|
46
|
+
# check if target is correct
|
47
|
+
warn "spec/fixtures/modules/#{module_name} is not a symlink to the correct source! Your tests may fail because of this!" unless File.readlink("spec/fixtures/modules/#{module_name}") == File.expand_path("../../../../#{module_name}")
|
48
|
+
else
|
49
|
+
warn "spec/fixtures/modules/#{module_name} is not a symlink! Your tests may fail because of this!"
|
50
|
+
end
|
51
|
+
else
|
52
|
+
File.symlink("../../../../#{module_name}", "spec/fixtures/modules/#{module_name}")
|
53
|
+
end
|
44
54
|
|
45
55
|
# create spec_helper if missing
|
46
56
|
return if File.file?('spec/spec_helper.rb')
|
47
|
-
File.open('spec/spec_helper.rb', 'w') { |file| file.puts "require 'rspec-puppet'\n
|
57
|
+
File.open('spec/spec_helper.rb', 'w') { |file| file.puts "require 'rspec-puppet/spec_helper'\n" }
|
48
58
|
end
|
49
59
|
|
50
60
|
# setup the module dependencies for rspec-puppet testing
|
@@ -56,7 +66,7 @@ class RSpecPuppetSupport
|
|
56
66
|
parsed = JSON.parse(File.read('metadata.json'))
|
57
67
|
|
58
68
|
# grab dependencies if they exist
|
59
|
-
return
|
69
|
+
return unless parsed.key?('dependencies')
|
60
70
|
parsed['dependencies'].each do |dependency_hash|
|
61
71
|
# determine how the user wants to download the module dependency
|
62
72
|
if dependency_hash.key?('git')
|
@@ -71,6 +81,7 @@ class RSpecPuppetSupport
|
|
71
81
|
warn "#{dependency_hash['name']} has an unspecified, or specified but unsupported, download method."
|
72
82
|
end
|
73
83
|
end
|
84
|
+
Process.waitall
|
74
85
|
end
|
75
86
|
|
76
87
|
# download external module dependency with git
|
@@ -79,7 +90,11 @@ class RSpecPuppetSupport
|
|
79
90
|
# establish path to clone module to
|
80
91
|
path = "spec/fixtures/modules/#{File.basename(git_url, '.git')}"
|
81
92
|
# is the module present and already cloned with git? do a pull; otherwise, do a clone
|
82
|
-
|
93
|
+
begin
|
94
|
+
File.directory?("#{path}/.git") ? spawn("git -C #{path} pull") : spawn("git clone #{args} #{git_url} #{path}")
|
95
|
+
rescue Errno::ENOENT
|
96
|
+
warn 'git is not installed and cannot be used to retrieve dependency modules'
|
97
|
+
end
|
83
98
|
end
|
84
99
|
|
85
100
|
# download external module dependency with forge
|
@@ -87,7 +102,7 @@ class RSpecPuppetSupport
|
|
87
102
|
private_class_method :method
|
88
103
|
# is the module present? do an upgrade; otherwise, do an install
|
89
104
|
subcommand = File.directory?("spec/fixtures/modules/#{forge_name}") ? 'upgrade' : 'install'
|
90
|
-
|
105
|
+
spawn("puppet module #{subcommand} --modulepath spec/fixtures/modules/ #{args} #{forge_name}")
|
91
106
|
end
|
92
107
|
|
93
108
|
# download external module dependency with svn
|
@@ -96,7 +111,11 @@ class RSpecPuppetSupport
|
|
96
111
|
# establish path to checkout module to
|
97
112
|
path = "spec/fixtures/modules/#{File.basename(svn_url)}"
|
98
113
|
# is the module present and already checked out with svn? do an update; otherwise, do a checkout
|
99
|
-
|
114
|
+
begin
|
115
|
+
File.directory?("#{path}/.svn") ? spawn("svn update #{path}") : spawn("svn co #{args} #{svn_url} #{path}")
|
116
|
+
rescue Errno::ENOENT
|
117
|
+
warn 'subversion is not installed and cannot be used to retrieve dependency modules'
|
118
|
+
end
|
100
119
|
end
|
101
120
|
|
102
121
|
# download external module dependency with hg
|
@@ -105,6 +124,10 @@ class RSpecPuppetSupport
|
|
105
124
|
# establish path to clone module to
|
106
125
|
path = "spec/fixtures/modules/#{File.basename(hg_url)}"
|
107
126
|
# is the module present and already cloned with hg? do a pull and update; otherwise do a clone
|
108
|
-
|
127
|
+
begin
|
128
|
+
File.directory?("#{path}/.hg") ? spawn("hg --cwd #{path} pull; hg --cwd #{path} update") : spawn("hg clone #{args} #{hg_url} #{path}")
|
129
|
+
rescue Errno::ENOENT
|
130
|
+
warn 'mercurial is not installed and cannot be used to retrieve dependency modules'
|
131
|
+
end
|
109
132
|
end
|
110
133
|
end
|
@@ -9,7 +9,7 @@ class RubyParser
|
|
9
9
|
# check ruby syntax
|
10
10
|
begin
|
11
11
|
# prevents ruby code from actually executing
|
12
|
-
catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}") }
|
12
|
+
catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}", file) }
|
13
13
|
rescue ScriptError, StandardError => err
|
14
14
|
PuppetCheck.settings[:error_files].push("#{file}:\n#{err}")
|
15
15
|
else
|
@@ -18,7 +18,7 @@ class RubyParser
|
|
18
18
|
require 'rubocop'
|
19
19
|
|
20
20
|
# check RuboCop and collect warnings
|
21
|
-
rubocop_warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--format', 'emacs', file]) }
|
21
|
+
rubocop_warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--require', 'rubocop-performance', '--format', 'emacs', file]) }
|
22
22
|
warnings = rubocop_warnings == '' ? '' : rubocop_warnings.split("#{File.absolute_path(file)}:").join('')
|
23
23
|
|
24
24
|
# check Reek and collect warnings
|
@@ -37,8 +37,6 @@ class RubyParser
|
|
37
37
|
|
38
38
|
# checks ruby template (.erb)
|
39
39
|
def self.template(files)
|
40
|
-
return if files.empty?
|
41
|
-
|
42
40
|
require 'erb'
|
43
41
|
|
44
42
|
files.each do |file|
|
@@ -66,22 +64,22 @@ class RubyParser
|
|
66
64
|
require 'rubocop'
|
67
65
|
# cop named differently depending upon version
|
68
66
|
filename_cop = RuboCop::Version::STRING.to_f >= 0.5 ? 'Naming/FileName' : 'Style/FileName'
|
67
|
+
# RuboCop is grumpy about non-snake_case filenames so disable the FileName check
|
68
|
+
rc_args.include?('--except') ? rc_args[rc_args.index('--except') + 1] = "#{rc_args[rc_args.index('--except') + 1]},#{filename_cop}" : rc_args.concat(['--except', filename_cop])
|
69
69
|
end
|
70
70
|
|
71
71
|
files.each do |file|
|
72
72
|
# check librarian puppet syntax
|
73
73
|
begin
|
74
74
|
# prevents ruby code from actually executing
|
75
|
-
catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}") }
|
75
|
+
catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}", file) }
|
76
76
|
rescue SyntaxError, LoadError, ArgumentError => err
|
77
77
|
PuppetCheck.settings[:error_files].push("#{file}:\n#{err}")
|
78
78
|
# check librarian puppet style
|
79
79
|
else
|
80
80
|
if style
|
81
81
|
# check Rubocop
|
82
|
-
|
83
|
-
rc_args.include?('--except') ? rc_args[rc_args.index('--except') + 1] = "#{rc_args[rc_args.index('--except') + 1]},#{filename_cop}" : rc_args.concat(['--except', filename_cop])
|
84
|
-
warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--format', 'emacs', file]) }
|
82
|
+
warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--require', 'rubocop-performance', '--format', 'emacs', file]) }
|
85
83
|
|
86
84
|
# collect style warnings
|
87
85
|
next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.split("#{File.absolute_path(file)}:").join('')}") unless warnings.empty?
|
data/lib/puppet-check/tasks.rb
CHANGED
@@ -14,10 +14,10 @@ class PuppetCheck::Tasks < ::Rake::TaskLib
|
|
14
14
|
namespace :puppetcheck do
|
15
15
|
desc 'Execute Puppet-Check file checks'
|
16
16
|
task :file do
|
17
|
-
PuppetCheck.new.run(Dir.glob('*'))
|
17
|
+
PuppetCheck.new.run(PuppetCheck.settings, Dir.glob('*'))
|
18
18
|
end
|
19
19
|
|
20
|
-
# rspec
|
20
|
+
# rspec and rspec-puppet tasks
|
21
21
|
begin
|
22
22
|
require 'rspec/core/rake_task'
|
23
23
|
require_relative 'rspec_puppet_support'
|
@@ -30,22 +30,26 @@ class PuppetCheck::Tasks < ::Rake::TaskLib
|
|
30
30
|
task.pattern = spec_dirs.empty? ? 'skip_rspec' : spec_dirs
|
31
31
|
task.rspec_opts = '-f json' if PuppetCheck.settings[:output_format] == 'json'
|
32
32
|
end
|
33
|
-
|
34
|
-
desc 'Execute Beaker acceptance tests'
|
35
|
-
RSpec::Core::RakeTask.new(:beaker) do |task|
|
36
|
-
# generate tasks for all recognized directories and ensure acceptance tests inside module dependencies are ignored
|
37
|
-
acceptance_dirs = Dir.glob('**/acceptance').reject { |dir| dir =~ /fixtures/ }
|
38
|
-
task.pattern = acceptance_dirs.empty? ? 'skip_beaker' : acceptance_dirs
|
39
|
-
task.rspec_opts = '-f json' if PuppetCheck.settings[:output_format] == 'json'
|
40
|
-
end
|
41
33
|
rescue LoadError
|
42
34
|
desc 'RSpec is not installed.'
|
43
35
|
task :spec do
|
44
|
-
puts 'RSpec is not installed. The RSpec/
|
36
|
+
puts 'RSpec is not installed. The RSpec/RSpec-Puppet tasks will not be available.'
|
45
37
|
end
|
46
|
-
|
38
|
+
end
|
39
|
+
|
40
|
+
# beaker tasks
|
41
|
+
begin
|
42
|
+
require 'beaker/tasks/quick_start'
|
43
|
+
|
44
|
+
desc 'Execute Beaker acceptance tests'
|
45
|
+
task :beaker, %i[hypervisor] do |_, args|
|
46
|
+
args[:hypervisor] = 'vagrant' if args[:hypervisor].nil?
|
47
|
+
Rake::Task["beaker_quickstart:run_test[#{args[:hypervisor]}]"].invoke
|
48
|
+
end
|
49
|
+
rescue LoadError
|
50
|
+
desc 'Beaker is not installed.'
|
47
51
|
task :beaker do
|
48
|
-
puts '
|
52
|
+
puts 'Beaker is not installed. The Beaker tasks will not be available.'
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|