puppet-check 2.2.0 → 2.2.1
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 +4 -0
- data/README.md +19 -13
- data/lib/puppet-check/cli.rb +6 -4
- data/lib/puppet-check/data_parser.rb +24 -18
- data/lib/puppet-check/output_results.rb +36 -30
- data/lib/puppet-check/puppet_parser.rb +18 -16
- data/lib/puppet-check/rspec_puppet_support.rb +1 -1
- data/lib/puppet-check/ruby_parser.rb +27 -20
- data/lib/puppet-check/tasks.rb +6 -5
- data/lib/puppet_check.rb +28 -23
- data/spec/puppet-check/cli_spec.rb +1 -1
- data/spec/puppet-check/data_parser_spec.rb +60 -53
- data/spec/puppet-check/output_results_spec.rb +28 -39
- data/spec/puppet-check/puppet_parser_spec.rb +52 -42
- data/spec/puppet-check/rspec_puppet_support_spec.rb +4 -4
- data/spec/puppet-check/ruby_parser_spec.rb +52 -43
- data/spec/puppet-check/tasks_spec.rb +4 -8
- data/spec/puppet_check_spec.rb +63 -25
- data/spec/system/system_spec.rb +20 -20
- metadata +13 -64
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 384ccc25e3b1a78f69e3d017131eaf9583dc24d73f1f9ef1c37c21ac706715b9
         | 
| 4 | 
            +
              data.tar.gz: 5094bc3014d74b9a5707fade543d1535d4ef12684d5adaddbb4ceb26c5a4a37e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1bfc1834fc8dc70defbfce8d330f724b834653e5ba48d4a546ff3d93b3bf94d5ac68850d84dcca6d0ac1bad1990d30c07f58c5bfbaaaf2b123fa352c408200f8
         | 
| 7 | 
            +
              data.tar.gz: e65f3c64cbc715d2e49c15378165256c17c01e440c979557908bd8a64fa5b77fdf74f8dac5fadbafec6df9b106bf05adb23443b552334759812850e3d89a872f
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    
    
        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 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 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'). | 
| 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
         | 
    
        data/lib/puppet-check/cli.rb
    CHANGED
    
    | @@ -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. | 
| 32 | 
            +
                    puts 'puppet-check 2.2.1'
         | 
| 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  | 
| 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. | 
| 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. | 
| 21 | 
            -
                  PuppetCheck. | 
| 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. | 
| 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. | 
| 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. | 
| 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. | 
| 65 | 
            -
                    PuppetCheck. | 
| 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. | 
| 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 | 
            -
                       | 
| 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 | 
            -
                       | 
| 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 | 
            -
                       | 
| 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. | 
| 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  | 
| 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. | 
| 195 | 
            -
                    PuppetCheck. | 
| 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  | 
| 6 | 
            -
              def self. | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 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 | 
            -
             | 
| 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 | 
            -
                   | 
| 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( | 
| 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 | 
            -
                     | 
| 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$}) | 
| 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 | 
            -
                       | 
| 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 | 
            -
                     | 
| 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 | 
            -
             | 
| 36 | 
            -
                   | 
| 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 =  | 
| 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 | 
| 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 | 
            -
                     | 
| 65 | 
            -
             | 
| 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. | 
| 69 | 
            -
                  PuppetCheck. | 
| 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. | 
| 84 | 
            +
                  PuppetCheck.files[:errors][file] = [err.to_s.gsub("file: #{file}, ", '')]
         | 
| 83 85 | 
             
                else
         | 
| 84 | 
            -
                  PuppetCheck. | 
| 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 | 
| 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. | 
| 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 | 
            -
                     | 
| 20 | 
            -
                     | 
| 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  | 
| 24 | 
            +
                    # check Reek and parse warnings' JSON output
         | 
| 24 25 | 
             
                    require 'reek'
         | 
| 25 26 | 
             
                    require 'reek/cli/application'
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                     | 
| 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. | 
| 35 | 
            +
                    next PuppetCheck.files[:warnings][file] = warnings unless warnings.empty?
         | 
| 31 36 | 
             
                  end
         | 
| 32 | 
            -
                  PuppetCheck. | 
| 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 | 
            -
             | 
| 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. | 
| 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. | 
| 55 | 
            -
                  PuppetCheck. | 
| 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. | 
| 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. | 
| 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 | 
            -
                     | 
| 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. | 
| 89 | 
            +
                    next PuppetCheck.files[:warnings][file] = offenses unless offenses.empty?
         | 
| 83 90 | 
             
                  end
         | 
| 84 | 
            -
                  PuppetCheck. | 
| 91 | 
            +
                  PuppetCheck.files[:clean].push(file.to_s)
         | 
| 85 92 | 
             
                end
         | 
| 86 93 | 
             
              end
         | 
| 87 94 |  | 
    
        data/lib/puppet-check/tasks.rb
    CHANGED
    
    | @@ -6,15 +6,17 @@ end | |
| 6 6 | 
             
            require_relative '../puppet_check'
         | 
| 7 7 |  | 
| 8 8 | 
             
            # the rake interface for PuppetCheck
         | 
| 9 | 
            -
            class PuppetCheck::Tasks <  | 
| 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( | 
| 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'). | 
| 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.'
         | 
    
        data/lib/puppet_check.rb
    CHANGED
    
    | @@ -5,33 +5,35 @@ require_relative 'puppet-check/output_results' | |
| 5 5 |  | 
| 6 6 | 
             
            # interfaces from CLI/tasks and to individual parsers
         | 
| 7 7 | 
             
            class PuppetCheck
         | 
| 8 | 
            -
              # initialize  | 
| 9 | 
            -
              @ | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 8 | 
            +
              # initialize files hash
         | 
| 9 | 
            +
              @files = {
         | 
| 10 | 
            +
                errors: {},
         | 
| 11 | 
            +
                warnings: {},
         | 
| 12 | 
            +
                clean: [],
         | 
| 13 | 
            +
                ignored: []
         | 
| 14 | 
            +
              }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              # allow the parser methods write to the files
         | 
| 12 17 | 
             
              class << self
         | 
| 13 | 
            -
                attr_accessor : | 
| 18 | 
            +
                attr_accessor :files
         | 
| 14 19 | 
             
              end
         | 
| 15 20 |  | 
| 16 21 | 
             
              # main runner for PuppetCheck
         | 
| 17 | 
            -
              def run(settings, paths)
         | 
| 18 | 
            -
                # establish settings
         | 
| 19 | 
            -
                self.class.settings = settings
         | 
| 20 | 
            -
             | 
| 22 | 
            +
              def run(settings = {}, paths = [])
         | 
| 21 23 | 
             
                # settings defaults
         | 
| 22 | 
            -
                self.class.defaults(settings)
         | 
| 24 | 
            +
                settings = self.class.defaults(settings)
         | 
| 23 25 |  | 
| 24 26 | 
             
                # grab all of the files to be processed
         | 
| 25 27 | 
             
                files = self.class.parse_paths(paths)
         | 
| 26 28 |  | 
| 27 29 | 
             
                # parse the files
         | 
| 28 | 
            -
                execute_parsers(files, settings)
         | 
| 30 | 
            +
                parsed_files = execute_parsers(files, settings)
         | 
| 29 31 |  | 
| 30 32 | 
             
                # output the diagnostic results
         | 
| 31 | 
            -
                 | 
| 33 | 
            +
                OutputResults.run(parsed_files, settings[:output_format])
         | 
| 32 34 |  | 
| 33 35 | 
             
                # progress to regression checks if no errors in file checks
         | 
| 34 | 
            -
                if self.class. | 
| 36 | 
            +
                if self.class.files[:errors].empty? && (!settings[:fail_on_warning] || self.class.files[:warnings].empty?)
         | 
| 35 37 | 
             
                  begin
         | 
| 36 38 | 
             
                    require_relative 'puppet-check/regression_check'
         | 
| 37 39 | 
             
                  # if octocatalog-diff is not installed then return immediately
         | 
| @@ -68,7 +70,8 @@ class PuppetCheck | |
| 68 70 | 
             
              end
         | 
| 69 71 |  | 
| 70 72 | 
             
              # establish default settings
         | 
| 71 | 
            -
              def self.defaults(settings)
         | 
| 73 | 
            +
              def self.defaults(settings = {})
         | 
| 74 | 
            +
                private_class_method :method
         | 
| 72 75 | 
             
                # initialize fail on warning,  style check, and regression check bools
         | 
| 73 76 | 
             
                settings[:fail_on_warning] ||= false
         | 
| 74 77 | 
             
                settings[:style] ||= false
         | 
| @@ -82,12 +85,6 @@ class PuppetCheck | |
| 82 85 | 
             
                # initialize output format option
         | 
| 83 86 | 
             
                settings[:output_format] ||= 'text'
         | 
| 84 87 |  | 
| 85 | 
            -
                # initialize diagnostic output arrays
         | 
| 86 | 
            -
                @settings[:error_files] = []
         | 
| 87 | 
            -
                @settings[:warning_files] = []
         | 
| 88 | 
            -
                @settings[:clean_files] = []
         | 
| 89 | 
            -
                @settings[:ignored_files] = []
         | 
| 90 | 
            -
             | 
| 91 88 | 
             
                # initialize octocatalog-diff options
         | 
| 92 89 | 
             
                settings[:octoconfig] ||= '.octocatalog-diff.cfg.rb'
         | 
| 93 90 | 
             
                settings[:octonodes] ||= %w[localhost.localdomain]
         | 
| @@ -95,10 +92,14 @@ class PuppetCheck | |
| 95 92 | 
             
                # initialize style arg arrays
         | 
| 96 93 | 
             
                settings[:puppetlint_args] ||= []
         | 
| 97 94 | 
             
                settings[:rubocop_args] ||= []
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                # return update settings
         | 
| 97 | 
            +
                settings
         | 
| 98 98 | 
             
              end
         | 
| 99 99 |  | 
| 100 100 | 
             
              # parse the paths and return the array of files
         | 
| 101 | 
            -
              def self.parse_paths(paths)
         | 
| 101 | 
            +
              def self.parse_paths(paths = [])
         | 
| 102 | 
            +
                private_class_method :method
         | 
| 102 103 | 
             
                files = []
         | 
| 103 104 |  | 
| 104 105 | 
             
                # traverse the unique paths and return all files
         | 
| @@ -111,13 +112,15 @@ class PuppetCheck | |
| 111 112 | 
             
                end
         | 
| 112 113 |  | 
| 113 114 | 
             
                # do not process fixtures, check that at least one file was found, and remove double slashes
         | 
| 114 | 
            -
                files.reject! { |file| file | 
| 115 | 
            +
                files.reject! { |file| file.include?('fixtures') }
         | 
| 115 116 | 
             
                raise "puppet-check: no files found in supplied paths '#{paths.join(', ')}'." if files.empty?
         | 
| 116 117 | 
             
                files.map! { |file| file.gsub('//', '/') }
         | 
| 117 118 |  | 
| 118 119 | 
             
                files.uniq
         | 
| 119 120 | 
             
              end
         | 
| 120 121 |  | 
| 122 | 
            +
              private
         | 
| 123 | 
            +
             | 
| 121 124 | 
             
              # categorize and pass the files out to the parsers to determine their status
         | 
| 122 125 | 
             
              def execute_parsers(files, settings)
         | 
| 123 126 | 
             
                # check manifests
         | 
| @@ -145,6 +148,8 @@ class PuppetCheck | |
| 145 148 | 
             
                librarians, files = files.partition { |file| File.basename(file) =~ /(?:Puppet|Module|Rake|Gem)file$/ }
         | 
| 146 149 | 
             
                RubyParser.librarian(librarians, settings[:style], settings[:rubocop_args]) unless librarians.empty?
         | 
| 147 150 | 
             
                # ignore everything else
         | 
| 148 | 
            -
                self.class. | 
| 151 | 
            +
                files.each { |file| self.class.files[:ignored].push(file.to_s) }
         | 
| 152 | 
            +
                # return PuppetCheck.files to mitigate singleton write accessor side effects
         | 
| 153 | 
            +
                PuppetCheck.files
         | 
| 149 154 | 
             
              end
         | 
| 150 155 | 
             
            end
         |