codeclimate/codeclimate

View on GitHub
lib/cc/config/validation/file_validator.rb

Summary

Maintainability
A
35 mins
Test Coverage
A
98%
module CC
  class Config
    module Validation
      class FileValidator
        include HashValidations

        attr_reader :errors, :path, :warnings

        def initialize(path, registry)
          @path = path
          @registry = registry

          @errors = []
          @warnings = []

          validate
        end

        def valid?
          errors.none?
        end

        private

        attr_reader :data, :registry

        def validate
          raise NotImplementedError, "use a subclass"
        end

        def denormalize_subvalidator(validator, prefix)
          validator.errors.each do |msg|
            errors << "#{prefix}: #{msg}"
          end
          validator.warnings.each do |msg|
            warnings << "#{prefix}: #{msg}"
          end
        end

        def validate_prepare
          return unless validate_key_type("prepare", Hash)

          validator = PrepareValidator.new(data.fetch("prepare", {}))
          denormalize_subvalidator(validator, "prepare section")
        end

        def validate_engines(key, legacy: false)
          return unless validate_key_type(key, Hash)

          data.fetch(key, {}).each do |engine_name, engine_data|
            engine_validator = EngineValidator.new(engine_data, legacy: legacy)
            denormalize_subvalidator(engine_validator, "engine #{engine_name}")

            if engine_validator.valid?
              validate_engine_existence(engine_name, engine_data)
            end
          end
        end

        def validate_engine_existence(engine_name, engine_data)
          if [true, false].include?(engine_data)
            engine_data = {
              "enabled" => true,
              "channel" => Engine::DEFAULT_CHANNEL,
            }
          end

          engine = Engine.new(
            engine_name,
            enabled: engine_data.fetch("enabled", true),
            channel: engine_data["channel"],
            config: engine_data["config"],
          )
          unless engine_exists?(engine)
            warnings << "unknown engine or channel <#{engine.name}:#{engine.channel}>"
          end
        end

        def engine_exists?(engine)
          !registry.fetch_engine_details(engine).nil?
        rescue CC::EngineRegistry::EngineDetailsNotFoundError
          false
        end

        def validate_checks
          return unless validate_key_type("checks", Hash)

          data.fetch("checks", {}).each do |check_name, check_data|
            validator = CheckValidator.new(check_data)
            denormalize_subvalidator(validator, "check #{check_name}")
          end
        end

        def validate_exclude_pattern(key, legacy: false)
          types =
            if legacy
              [Array, String]
            else
              Array
            end
          return unless validate_key_type(key, types)

          Array(data.fetch(key, [])).each do |pattern|
            unless pattern.is_a?(String)
              errors << "each exclude pattern should be a string, but '#{pattern.inspect}' is a #{pattern.class.to_s.downcase}"
            end
          end
        end
      end
    end
  end
end