puppet-check 2.2.0 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1e591abda5a49b0731073d14831000016b08d72b505ab3d22a287029fa1243f
4
- data.tar.gz: 96bceb6ef51e82582984ab0c88f96591d30c26650e174a0215133af0723c9526
3
+ metadata.gz: a8202ec2f014dfda495943251a944a05a2f02dd411d4432d4ae2fa670090147f
4
+ data.tar.gz: 79926aa5d6f7a5b4abdf5141a110d08f2dd2d678439b89a3a4193ba957b3eb36
5
5
  SHA512:
6
- metadata.gz: 805ef299109715901160e9f4c4894ff05f31140c8234ed867273434e85b525e4c91e0e5fd7e6f96fb23352a3b801afa006b31cb4a93515c76182725b510a57f8
7
- data.tar.gz: 2fc8340befd7b6c5f9662038aeea6614858ed1a2bd92f0d76c797fe42b316fed9d080e38cd8f4203d16240c365086bc1165c89102f3ee4e496dae6f1cf75b9bd
6
+ metadata.gz: 5881b391a02f1f7afd9d902e16c578fa02128511275e9c670767ec2c1ebcce263a1137f36244c1e8bb118da057719f955727df577a6df421d66966cb39d3d054
7
+ data.tar.gz: d74c947acf7b79cbc0f82ba7280617495eb2bfd7574e6e22791b59bffa8a9fa4228aec7194fd3c8c9b77e99993a10dc9886074e43c3166da69b2d0ccccd1a052
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ### 2.2.2
2
+ - Workaround Ruby passbyref issue mutating an immutable.
3
+
4
+ ### 2.2.1
5
+ - Improved output formatting for all formats.
6
+ - Update and improve Rake task interfacing.
7
+
1
8
  ### 2.2.0
2
9
  - Add Enable Pending Cops to base RuboCop configuration.
3
10
  - Support checking plans.
data/README.md CHANGED
@@ -173,18 +173,24 @@ rake puppetcheck:kitchen:* # Execute Test Kitchen acceptance tests
173
173
  You can add style, smoke, and regression checks to the `rake puppetcheck:file`, or change the output format, by adding the following after the require:
174
174
 
175
175
  ```ruby
176
- # example of modifying Puppet Check behavior
177
- PuppetCheck.settings[:style] = true
178
- PuppetCheck.settings[:fail_on_warnings] = true
179
- PuppetCheck.settings[:smoke] = true
180
- PuppetCheck.settings[:regression] = true # in progress, do not use
181
- PuppetCheck.settings[:public] = 'public.pem'
182
- PuppetCheck.settings[:private] = 'private.pem'
183
- PuppetCheck.settings[:output_format] = 'yaml'
184
- PuppetCheck.settings[:octoconfig] = '.octocatalog-diff.cfg.rb'
185
- PuppetCheck.settings[:octonodes] = %w(localhost.localdomain)
186
- PuppetCheck.settings[:puppetlint_args] = ['--puppetlint-arg-one', '--puppetlint-arg-two']
187
- PuppetCheck.settings[:rubocop_args] = ['--except', 'rubocop-arg-one,rubocop-arg-two']
176
+ # example of modifying Puppet Check behavior and creating a custom task
177
+ settings = {}
178
+ settings[:fail_on_warnings] = true # default false
179
+ settings[:style] = true # default false
180
+ settings[:smoke] = true # default false
181
+ settings[:regression] = true # in progress, do not use; default false
182
+ settings[:public] = 'public.pem' # default nil
183
+ settings[:private] = 'private.pem' # default nil
184
+ settings[:output_format] = 'yaml' # also 'json'; default 'text'
185
+ settings[:octoconfig] = '$HOME/octocatalog-diff.cfg.rb' # default '.octocatalog-diff.cfg.rb'
186
+ settings[:octonodes] = %w(server.example.com) # default: %w(localhost.localdomain)
187
+ settings[:puppetlint_args] = ['--puppetlint-arg-one', '--puppetlint-arg-two'] # default []
188
+ settings[:rubocop_args] = ['--except', 'rubocop-arg-one,rubocop-arg-two'] # default []
189
+
190
+ desc 'Execute custom Puppet-Check file checks'
191
+ task :file_custom do
192
+ Rake::Task[:'puppetcheck:file'].invoke(settings)
193
+ end
188
194
  ```
189
195
 
190
196
  Please note that `rspec` does not support yaml output and therefore would still use the default 'progress' formatter even if `yaml` is specified as the format option to Puppet Check.
@@ -276,7 +282,7 @@ PuppetCheck.new.run(settings, [dirs, files])
276
282
  require 'puppet-check/rspec_puppet_support'
277
283
 
278
284
  RSpecPuppetSupport.run
279
- task.pattern = Dir.glob('**/{classes,defines,facter,functions,hosts,puppet,unit,types}/**/*_spec.rb').reject { |dir| dir =~ /fixtures/ }
285
+ task.pattern = Dir.glob('**/{classes,defines,facter,functions,hosts,puppet,unit,types}/**/*_spec.rb').grep_v(/fixtures/)
280
286
  ```
281
287
 
282
288
  ### Docker
@@ -1,4 +1,3 @@
1
- require 'optparse'
2
1
  require_relative '../puppet_check'
3
2
 
4
3
  # the command line interface for PuppetCheck
@@ -7,7 +6,7 @@ class PuppetCheck::CLI
7
6
  def self.run(args)
8
7
  # gather the user arguments
9
8
  settings = parse(args)
10
- raise 'puppet-check: no paths specified; try using --help' if args.empty?
9
+ raise 'puppet-check: no file paths specified; try using --help' if args.empty?
11
10
 
12
11
  # run PuppetCheck with specified paths
13
12
  PuppetCheck.new.run(settings, args)
@@ -15,6 +14,9 @@ class PuppetCheck::CLI
15
14
 
16
15
  # parse the user arguments
17
16
  def self.parse(args)
17
+ private_class_method :method
18
+ require 'optparse'
19
+
18
20
  # show help message if no args specified
19
21
  args = %w[-h] if args.empty?
20
22
 
@@ -27,7 +29,7 @@ class PuppetCheck::CLI
27
29
 
28
30
  # base options
29
31
  opts.on('--version', 'Display the current version.') do
30
- puts 'puppet-check 2.2.0'
32
+ puts 'puppet-check 2.2.2'
31
33
  exit 0
32
34
  end
33
35
 
@@ -58,7 +60,7 @@ class PuppetCheck::CLI
58
60
  opts.on('--rubocop arg_one,arg_two', String, 'Arguments for Rubocop disabled cops') { |arg| settings[:rubocop_args] = ['--except', arg] }
59
61
  end
60
62
 
61
- # remove atched args and return settings
63
+ # remove matched args and return settings
62
64
  opt_parser.parse!(args)
63
65
  settings
64
66
  end
@@ -2,23 +2,23 @@ require_relative '../puppet_check'
2
2
 
3
3
  # executes diagnostics on data files
4
4
  class DataParser
5
+ require 'yaml'
6
+
5
7
  # checks yaml (.yaml/.yml)
6
8
  def self.yaml(files)
7
- require 'yaml'
8
-
9
9
  files.each do |file|
10
10
  # check yaml syntax
11
11
  parsed = YAML.load_file(file)
12
12
  rescue StandardError => err
13
- PuppetCheck.settings[:error_files].push("#{file}:\n#{err.to_s.gsub("(#{file}): ", '')}")
13
+ PuppetCheck.files[:errors][file] = err.to_s.gsub("(#{file}): ", '').split("\n")
14
14
  else
15
15
  warnings = []
16
16
 
17
17
  # perform some rudimentary hiera checks if data exists and is hieradata
18
18
  warnings = hiera(parsed, file) if parsed && (File.basename(file) != 'hiera.yaml')
19
19
 
20
- next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
21
- PuppetCheck.settings[:clean_files].push(file.to_s)
20
+ next PuppetCheck.files[:warnings][file] = warnings unless warnings.empty?
21
+ PuppetCheck.files[:clean].push(file.to_s)
22
22
  end
23
23
  end
24
24
 
@@ -28,13 +28,13 @@ class DataParser
28
28
 
29
29
  # keys specified?
30
30
  if public.nil? || private.nil?
31
- PuppetCheck.settings[:ignored_files].concat(files)
31
+ PuppetCheck.files[:ignored].concat(files)
32
32
  return warn 'Public X509 and/or Private RSA PKCS7 certs were not specified. EYAML checks will not be executed.'
33
33
  end
34
34
 
35
35
  # keys exist?
36
36
  unless File.file?(public) && File.file?(private)
37
- PuppetCheck.settings[:ignored_files].concat(files)
37
+ PuppetCheck.files[:ignored].concat(files)
38
38
  return warn 'Specified Public X509 and/or Private RSA PKCS7 certs do not exist. EYAML checks will not be executed.'
39
39
  end
40
40
 
@@ -54,19 +54,25 @@ class DataParser
54
54
  begin
55
55
  parsed = YAML.load_file(decrypted)
56
56
  rescue StandardError => err
57
- PuppetCheck.settings[:error_files].push("#{file}:\n#{err.to_s.gsub("(#{file}): ", '')}")
57
+ PuppetCheck.files[:errors][file] = err.to_s.gsub("(#{file}): ", '').split("\n")
58
58
  else
59
59
  warnings = []
60
60
 
61
61
  # perform some rudimentary hiera checks if data exists and is hieradata
62
62
  warnings = hiera(parsed, file) if parsed
63
63
 
64
- next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
65
- PuppetCheck.settings[:clean_files].push(file.to_s)
64
+ next PuppetCheck.files[:warnings][file] = warnings unless warnings.empty?
65
+ PuppetCheck.files[:clean].push(file.to_s)
66
66
  end
67
67
  end
68
68
  end
69
69
 
70
+ # metadata consts
71
+ REQUIRED_KEYS = %w[name version author license summary source dependencies].freeze
72
+ REQ_DEP_KEYS = %w[requirements dependencies].freeze
73
+ DEPRECATED_KEYS = %w[types checksum].freeze
74
+ TASK_INPUTS = %w[environment stdin powershell].freeze
75
+
70
76
  # checks json (.json)
71
77
  def self.json(files)
72
78
  require 'json'
@@ -76,7 +82,7 @@ class DataParser
76
82
  begin
77
83
  parsed = JSON.parse(File.read(file))
78
84
  rescue JSON::ParserError => err
79
- PuppetCheck.settings[:error_files].push("#{file}:\n#{err.to_s.lines.first.strip}")
85
+ PuppetCheck.files[:errors][file] = err.to_s.lines.first.strip.split("\n")
80
86
  else
81
87
  warnings = []
82
88
 
@@ -89,12 +95,12 @@ class DataParser
89
95
  errors = []
90
96
 
91
97
  # check for required keys
92
- %w[name version author license summary source dependencies].each do |key|
98
+ REQUIRED_KEYS.each do |key|
93
99
  errors.push("Required field '#{key}' not found.") unless parsed.key?(key)
94
100
  end
95
101
 
96
102
  # check requirements and dependencies keys
97
- %w[requirements dependencies].each do |key|
103
+ REQ_DEP_KEYS.each do |key|
98
104
  # skip if key is missing or value is an empty string, array, or hash
99
105
  next if !parsed.key?(key) || parsed[key].empty?
100
106
 
@@ -123,14 +129,14 @@ class DataParser
123
129
  end
124
130
 
125
131
  # check for deprecated fields
126
- %w[types checksum].each do |key|
132
+ DEPRECATED_KEYS.each do |key|
127
133
  errors.push("Deprecated field '#{key}' found.") if parsed.key?(key)
128
134
  end
129
135
 
130
136
  # check for summary under 144 character
131
137
  errors.push('Summary exceeds 144 characters.') if parsed.key?('summary') && parsed['summary'].size > 144
132
138
 
133
- next PuppetCheck.settings[:error_files].push("#{file}:\n#{errors.join("\n")}") unless errors.empty?
139
+ next PuppetCheck.files[:errors][file] = errors unless errors.empty?
134
140
 
135
141
  # check for warnings
136
142
  # check for operatingsystem_support hash array
@@ -169,7 +175,7 @@ class DataParser
169
175
  # check that input_method is one of three possible values
170
176
  if parsed.key?('input_method')
171
177
  if parsed['input_method'].is_a?(String)
172
- warnings.push('input_method value is not one of environment, stdin, or powershell') unless %w[environment stdin powershell].include?(parsed['input_method'])
178
+ warnings.push('input_method value is not one of environment, stdin, or powershell') unless TASK_INPUTS.include?(parsed['input_method'])
173
179
  else
174
180
  warnings.push('input_method value is not a String')
175
181
  end
@@ -191,8 +197,8 @@ class DataParser
191
197
  # perform some rudimentary hiera checks if data exists
192
198
  warnings = hiera(parsed, file)
193
199
  end
194
- next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.join("\n")}") unless warnings.empty?
195
- PuppetCheck.settings[:clean_files].push(file.to_s)
200
+ next PuppetCheck.files[:warnings][file] = warnings unless warnings.empty?
201
+ PuppetCheck.files[:clean].push(file.to_s)
196
202
  end
197
203
  end
198
204
  end
@@ -2,44 +2,50 @@ require_relative '../puppet_check'
2
2
 
3
3
  # class to handle outputting diagnostic results in desired format
4
4
  class OutputResults
5
- # output the results as text
6
- def self.text
7
- unless PuppetCheck.settings[:error_files].empty?
8
- print "\033[31mThe following files have errors:\033[0m\n-- "
9
- puts PuppetCheck.settings[:error_files].join("\n\n-- ")
10
- end
11
- unless PuppetCheck.settings[:warning_files].empty?
12
- print "\n\033[33mThe following files have warnings:\033[0m\n-- "
13
- puts PuppetCheck.settings[:warning_files].join("\n\n-- ")
14
- end
15
- unless PuppetCheck.settings[:clean_files].empty?
16
- print "\n\033[32mThe following files have no errors or warnings:\033[0m\n-- "
17
- puts PuppetCheck.settings[:clean_files].join("\n-- ")
18
- end
19
- return if PuppetCheck.settings[:ignored_files].empty?
20
- print "\n\033[36mThe following files have unrecognized formats and therefore were not processed:\033[0m\n-- "
21
- puts PuppetCheck.settings[:ignored_files].join("\n-- ")
22
- end
5
+ # output the results in various formats
6
+ def self.run(files, format)
7
+ # remove empty entries
8
+ files.delete_if { |_, sorted_files| sorted_files.empty? }
23
9
 
24
- # output the results as yaml or json
25
- def self.markup(format)
26
- # generate output hash
27
- hash = {}
28
- hash['errors'] = PuppetCheck.settings[:error_files] unless PuppetCheck.settings[:error_files].empty?
29
- hash['warnings'] = PuppetCheck.settings[:warning_files] unless PuppetCheck.settings[:warning_files].empty?
30
- hash['clean'] = PuppetCheck.settings[:clean_files] unless PuppetCheck.settings[:clean_files].empty?
31
- hash['ignored'] = PuppetCheck.settings[:ignored_files] unless PuppetCheck.settings[:ignored_files].empty?
32
-
33
- # convert hash to markup language
10
+ # output hash according to specified format
34
11
  case format
12
+ when 'text'
13
+ text(files)
35
14
  when 'yaml'
36
15
  require 'yaml'
37
- puts Psych.dump(hash, indentation: 2)
16
+ # maintain filename format consistency among output formats
17
+ files.transform_keys!(&:to_s)
18
+ puts Psych.dump(files, indentation: 2)
38
19
  when 'json'
39
20
  require 'json'
40
- puts JSON.pretty_generate(hash)
21
+ puts JSON.pretty_generate(files)
41
22
  else
42
23
  raise "puppet-check: Unsupported output format '#{format}' was specified."
43
24
  end
44
25
  end
26
+
27
+ # output the results as text
28
+ def self.text(files)
29
+ private_class_method :method
30
+
31
+ # errors
32
+ if files.key?(:errors)
33
+ puts "\033[31mThe following files have errors:\033[0m"
34
+ files[:errors].each { |file, errors| puts "-- #{file}:\n#{errors.join("\n")}" }
35
+ end
36
+ # warnings
37
+ if files.key?(:warnings)
38
+ puts "\n\033[33mThe following files have warnings:\033[0m"
39
+ files[:warnings].each { |file, warnings| puts "-- #{file}:\n#{warnings.join("\n")}" }
40
+ end
41
+ # cleans
42
+ if files.key?(:clean)
43
+ print "\n\033[32mThe following files have no errors or warnings:\033[0m\n-- "
44
+ puts files[:clean].join("\n-- ")
45
+ end
46
+ # ignores
47
+ return unless files.key?(:ignored)
48
+ print "\n\033[36mThe following files have unrecognized formats and therefore were not processed:\033[0m\n-- "
49
+ puts files[:ignored].join("\n-- ")
50
+ end
45
51
  end
@@ -18,30 +18,33 @@ class PuppetParser
18
18
  # check puppet syntax
19
19
  begin
20
20
  # initialize message
21
- message = ''
21
+ messages = []
22
22
  # specify tasks attribute for parser validation if this looks like a plan or not
23
- Puppet[:tasks] = file.match?(%r{plans/\w+\.pp$}) ? true : false
23
+ Puppet[:tasks] = file.match?(%r{plans/\w+\.pp$})
24
24
  # in puppet >= 6.5 the return of this method is a hash with the error
25
25
  new_error = Puppet::Face[:parser, :current].validate(file)
26
26
  # puppet 6.5 output format is now a hash from the face api
27
27
  if Gem::Version.new(Puppet::PUPPETVERSION) >= Gem::Version.new('6.5.0') && new_error != {}
28
- message = new_error.values.map(&:to_s).join("\n").gsub(/ \(file: #{File.absolute_path(file)}(, |\))/, '').gsub('Could not parse for environment *root*: ', '')
28
+ messages.concat(new_error.values.map(&:to_s).map { |error| error.gsub(/ \(file: #{File.absolute_path(file)}(, |\))/, '') }.map { |error| error.gsub('Could not parse for environment *root*: ', '') })
29
29
  end
30
30
  # this is the actual error that we need to rescue Puppet::Face from
31
31
  rescue SystemExit
32
32
  # puppet 5.4-6.4 has a new validator output format and eof errors have fake dir env info
33
- message = errors.map(&:to_s).join("\n").gsub(/file: #{File.absolute_path(file)}(, |\))/, '').gsub(/Could not parse.*: /, '')
33
+ messages.concat(errors.map(&:to_s).join("\n").map { |error| error.gsub(/file: #{File.absolute_path(file)}(, |\))/, '') }.map { |error| error.gsub(/Could not parse.*: /, '') })
34
34
  end
35
- # output message
36
- next PuppetCheck.settings[:error_files].push("#{file}:\n#{message}") unless message.empty?
35
+
36
+ Puppet::Util::Log.close_all
37
+
38
+ # store info and continue validating files
39
+ next PuppetCheck.files[:errors][file] = messages unless messages.empty?
37
40
 
38
41
  # initialize warnings with output from the parser if it exists, since the output is warnings if Puppet::Face did not trigger a SystemExit
39
- warnings = "#{file}:"
42
+ warnings = []
43
+ # weirdly puppet >= 6.5 still does not return warnings and logs them instead unlike errors
40
44
  unless errors.empty?
41
45
  # puppet >= 5.4 has a new validator output format
42
- warnings << "\n#{errors.map(&:to_s).join("\n").gsub("file: #{File.absolute_path(file)}, ", '')}"
46
+ warnings.concat(errors.map(&:to_s).join("\n").gsub("file: #{File.absolute_path(file)}, ", '').split("\n"))
43
47
  end
44
- Puppet::Util::Log.close_all
45
48
 
46
49
  # check puppet style
47
50
  if style
@@ -61,12 +64,11 @@ class PuppetParser
61
64
  puppet_lint.run
62
65
 
63
66
  # collect the warnings
64
- if puppet_lint.warnings?
65
- puppet_lint.problems.each { |values| warnings << "\n#{values[:line]}:#{values[:column]}: #{values[:message]}" }
66
- end
67
+ offenses = puppet_lint.problems.map { |problem| "#{problem[:line]}:#{problem[:column]} #{problem[:message]}" }
68
+ warnings.concat(offenses)
67
69
  end
68
- next PuppetCheck.settings[:warning_files].push(warnings) unless warnings == "#{file}:"
69
- PuppetCheck.settings[:clean_files].push(file.to_s)
70
+ next PuppetCheck.files[:warnings][file] = warnings unless warnings.empty?
71
+ PuppetCheck.files[:clean].push(file.to_s)
70
72
  end
71
73
  end
72
74
 
@@ -79,9 +81,9 @@ class PuppetParser
79
81
  # credits to gds-operations/puppet-syntax for the parser function call
80
82
  Puppet::Pops::Parser::EvaluatingParser::EvaluatingEppParser.new.parse_file(file)
81
83
  rescue StandardError => err
82
- PuppetCheck.settings[:error_files].push("#{file}:\n#{err.to_s.gsub("#{file}:", '')}")
84
+ PuppetCheck.files[:errors][file] = [err.to_s.gsub("file: #{file}, ", '')]
83
85
  else
84
- PuppetCheck.settings[:clean_files].push(file.to_s)
86
+ PuppetCheck.files[:clean].push(file.to_s)
85
87
  end
86
88
  end
87
89
  end
@@ -9,7 +9,7 @@ class RSpecPuppetSupport
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
- specdirs = Dir.glob('**/spec').reject { |dir| dir =~ /fixtures/ }
12
+ specdirs = Dir.glob('**/spec').reject { |dir| dir.include?('fixtures') }
13
13
  return if specdirs.empty?
14
14
 
15
15
  # setup fixtures for rspec-puppet testing
@@ -10,26 +10,31 @@ class RubyParser
10
10
  # prevents ruby code from actually executing
11
11
  catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}", file) }
12
12
  rescue ScriptError, StandardError => err
13
- PuppetCheck.settings[:error_files].push("#{file}:\n#{err}")
13
+ PuppetCheck.files[:errors][file] = err.to_s.gsub("#{file}:", '').split("\n")
14
14
  else
15
15
  # check ruby style
16
16
  if style
17
+ # check RuboCop and parse warnings' JSON output
18
+ require 'json'
17
19
  require 'rubocop'
18
20
 
19
- # check RuboCop and collect warnings
20
- rubocop_warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--enable-pending-cops', '--require', 'rubocop-performance', '--format', 'emacs', file]) }
21
- warnings = rubocop_warnings == '' ? '' : rubocop_warnings.split("#{File.absolute_path(file)}:").join('')
21
+ rubocop_warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--enable-pending-cops', '--require', 'rubocop-performance', '--format', 'json', file]) }
22
+ rubocop_offenses = JSON.parse(rubocop_warnings)['files'][0]['offenses'].map { |warning| "#{warning['location']['line']}:#{warning['location']['column']} #{warning['message']}" }
22
23
 
23
- # check Reek and collect warnings
24
+ # check Reek and parse warnings' JSON output
24
25
  require 'reek'
25
26
  require 'reek/cli/application'
26
- reek_warnings = Utils.capture_stdout { Reek::CLI::Application.new([file]).execute }
27
- warnings << reek_warnings.split("\n")[1..].map(&:strip).join("\n") unless reek_warnings == ''
27
+
28
+ reek_warnings = Utils.capture_stdout { Reek::CLI::Application.new(['-f', 'json', file]).execute }
29
+ reek_offenses = JSON.parse(reek_warnings).map { |warning| "#{warning['lines'].join(',')}: #{warning['context']} #{warning['message']}" }
30
+
31
+ # assign warnings from combined offenses
32
+ warnings = rubocop_offenses + reek_offenses
28
33
 
29
34
  # return warnings
30
- next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.strip}") unless warnings == ''
35
+ next PuppetCheck.files[:warnings][file] = warnings unless warnings.empty?
31
36
  end
32
- PuppetCheck.settings[:clean_files].push(file.to_s)
37
+ PuppetCheck.files[:clean].push(file.to_s)
33
38
  end
34
39
  end
35
40
 
@@ -43,16 +48,16 @@ class RubyParser
43
48
  # need to eventually have this associated with a different binding during each iteration
44
49
  # older usage throws extra warning and mixes with valid warnings confusingly
45
50
  warnings = Utils.capture_stderr { ERB.new(File.read(file), trim_mode: '-').result }
46
- # ERB.new(File.read(file), trim_mode: '-').result(RubyParser.new.bind)
51
+ # warnings = ERB.new(File.read(file), trim_mode: '-').result(RubyParser.new.bind)
47
52
  rescue NameError, TypeError
48
53
  # empty out warnings since it would contain an error if this pass triggers
49
54
  warnings = ''
50
55
  rescue ScriptError => err
51
- next PuppetCheck.settings[:error_files].push("#{file}:\n#{err}")
56
+ next PuppetCheck.files[:errors][file] = err.to_s.gsub('(erb):', '').split("\n")
52
57
  end
53
58
  # return warnings from the check if there were any
54
- next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.gsub('warning: ', '').split('(erb):').join('').strip}") unless warnings == ''
55
- PuppetCheck.settings[:clean_files].push(file.to_s)
59
+ next PuppetCheck.files[:warnings][file] = warnings.to_s.gsub('warning: ', '').delete("\n").split('(erb):').compact unless warnings == ''
60
+ PuppetCheck.files[:clean].push(file.to_s)
56
61
  end
57
62
  end
58
63
 
@@ -60,10 +65,8 @@ class RubyParser
60
65
  def self.librarian(files, style, rc_args)
61
66
  # efficient var assignment prior to iterator
62
67
  if style
63
- require 'rubocop'
64
-
65
68
  # RuboCop is grumpy about non-snake_case filenames so disable the FileName check
66
- rc_args.include?('--except') ? rc_args[rc_args.index('--except') + 1] = "#{rc_args[rc_args.index('--except') + 1]},Naming/FileName" : rc_args.concat(['--except', 'Naming/FileName'])
69
+ rc_args.include?('--except') ? rc_args[rc_args.index('--except') + 1] = "#{rc_args[rc_args.index('--except') + 1]},Naming/FileName" : rc_args.push('--except', 'Naming/FileName')
67
70
  end
68
71
 
69
72
  files.each do |file|
@@ -71,17 +74,21 @@ class RubyParser
71
74
  # prevents ruby code from actually executing
72
75
  catch(:good) { instance_eval("BEGIN {throw :good}; #{File.read(file)}", file) }
73
76
  rescue SyntaxError, LoadError, ArgumentError => err
74
- PuppetCheck.settings[:error_files].push("#{file}:\n#{err}")
77
+ PuppetCheck.files[:errors][file] = err.to_s.gsub("#{file}:", '').split("\n")
75
78
  # check librarian puppet style
76
79
  else
77
80
  if style
78
81
  # check Rubocop
79
- warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--enable-pending-cops', '--require', 'rubocop-performance', '--format', 'emacs', file]) }
82
+ require 'json'
83
+ require 'rubocop'
84
+
85
+ warnings = Utils.capture_stdout { RuboCop::CLI.new.run(rc_args + ['--enable-pending-cops', '--require', 'rubocop-performance', '--format', 'json', file]) }
86
+ offenses = JSON.parse(warnings)['files'][0]['offenses'].map { |warning| "#{warning['location']['line']}:#{warning['location']['column']} #{warning['message']}" }
80
87
 
81
88
  # collect style warnings
82
- next PuppetCheck.settings[:warning_files].push("#{file}:\n#{warnings.split("#{File.absolute_path(file)}:").join('')}") unless warnings.empty?
89
+ next PuppetCheck.files[:warnings][file] = offenses unless offenses.empty?
83
90
  end
84
- PuppetCheck.settings[:clean_files].push(file.to_s)
91
+ PuppetCheck.files[:clean].push(file.to_s)
85
92
  end
86
93
  end
87
94
 
@@ -6,15 +6,17 @@ end
6
6
  require_relative '../puppet_check'
7
7
 
8
8
  # the rake interface for PuppetCheck
9
- class PuppetCheck::Tasks < ::Rake::TaskLib
9
+ class PuppetCheck::Tasks < Rake::TaskLib
10
10
  def initialize
11
+ super
12
+
11
13
  desc 'Execute all Puppet-Check checks'
12
14
  task puppetcheck: %w[puppetcheck:file puppetcheck:spec puppetcheck:beaker puppetcheck:kitchen]
13
15
 
14
16
  namespace :puppetcheck do
15
17
  desc 'Execute Puppet-Check file checks'
16
- task :file do
17
- PuppetCheck.new.run(PuppetCheck.settings, Dir.glob('*'))
18
+ task :file, [:settings] do |_, wrapped_settings|
19
+ PuppetCheck.new.run(wrapped_settings[:settings], Dir.glob('*'))
18
20
  end
19
21
 
20
22
  # rspec and rspec-puppet tasks
@@ -26,9 +28,8 @@ class PuppetCheck::Tasks < ::Rake::TaskLib
26
28
  RSpec::Core::RakeTask.new(:spec) do |task|
27
29
  RSpecPuppetSupport.run
28
30
  # generate tasks for all recognized directories and ensure spec tests inside module dependencies are ignored
29
- spec_dirs = Dir.glob('**/{classes,defines,facter,functions,hosts,puppet,unit,types}/**/*_spec.rb').reject { |dir| dir =~ /fixtures/ }
31
+ spec_dirs = Dir.glob('**/{classes,defines,facter,functions,hosts,puppet,unit,types}/**/*_spec.rb').grep_v(/fixtures/)
30
32
  task.pattern = spec_dirs.empty? ? 'skip_rspec' : spec_dirs
31
- task.rspec_opts = '-f json' if PuppetCheck.settings[:output_format] == 'json'
32
33
  end
33
34
  rescue LoadError
34
35
  desc 'RSpec is not installed.'