class Overcommit::ConfigurationValidator

Validates and normalizes a configuration.

Public Instance Methods

validate(config, hash, options) click to toggle source

Validates hash for any invalid options, normalizing where possible.

@param config [Overcommit::Configuration] @param hash [Hash] hash representation of YAML config @param options @option default [Boolean] whether hash represents the default built-in config @option logger [Overcommit::Logger] logger to output warnings to @return [Hash] validated hash (potentially modified)

# File lib/overcommit/configuration_validator.rb, line 15
def validate(config, hash, options)
  @options = options.dup
  @log = options[:logger]

  hash = convert_nils_to_empty_hashes(hash)
  ensure_hook_type_sections_exist(hash)
  check_hook_name_format(hash)
  check_hook_env(hash)
  check_for_missing_enabled_option(hash) unless @options[:default]
  check_for_too_many_processors(config, hash)
  check_for_verify_plugin_signatures_option(hash)

  hash
end

Private Instance Methods

check_for_missing_enabled_option(hash) click to toggle source

Prints a warning if there are any hooks listed in the configuration without `enabled` explicitly set.

# File lib/overcommit/configuration_validator.rb, line 125
def check_for_missing_enabled_option(hash)
  return unless @log

  any_warnings = false

  Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
    hash.fetch(hook_type) { {} }.each do |hook_name, hook_config|
      next if hook_name == 'ALL'

      if hook_config['enabled'].nil?
        @log.warning "#{hook_type}::#{hook_name} hook does not explicitly " \
                     'set `enabled` option in .overcommit.yml'
        any_warnings = true
      end
    end
  end

  @log.newline if any_warnings
end
check_for_too_many_processors(config, hash) click to toggle source

Prints a warning if any hook has a number of processors larger than the global `concurrency` setting.

# File lib/overcommit/configuration_validator.rb, line 147
def check_for_too_many_processors(config, hash)
  concurrency = config.concurrency

  errors = []
  Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
    hash.fetch(hook_type) { {} }.each do |hook_name, hook_config|
      processors = hook_config.fetch('processors') { 1 }
      if processors > concurrency
        errors << "#{hook_type}::#{hook_name} `processors` value " \
                  "(#{processors}) is larger than the global `concurrency` " \
                  "option (#{concurrency})"
      end
    end
  end

  if errors.any?
    if @log
      @log.error errors.join("\n")
      @log.newline
    end
    raise Overcommit::Exceptions::ConfigurationError,
          'One or more hooks had invalid `processor` value configured'
  end
end
check_for_verify_plugin_signatures_option(hash) click to toggle source

Prints a warning if the `verify_plugin_signatures` option is used instead of the new `verify_signatures` option.

# File lib/overcommit/configuration_validator.rb, line 174
def check_for_verify_plugin_signatures_option(hash)
  return unless @log

  if hash.key?('verify_plugin_signatures')
    @log.warning '`verify_plugin_signatures` has been renamed to ' \
                 '`verify_signatures`. Defaulting to verifying signatures.'
    @log.warning "See change log at #{REPO_URL}/blob/v0.29.0/CHANGELOG.md for details."
    @log.newline
  end
end
check_hook_env(hash) click to toggle source
# File lib/overcommit/configuration_validator.rb, line 58
def check_hook_env(hash)
  errors = []

  Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
    hash.fetch(hook_type) { {} }.each do |hook_name, hook_config|
      hook_env = hook_config.fetch('env') { {} }

      unless hook_env.is_a?(Hash)
        errors << "#{hook_type}::#{hook_name} has an invalid `env` specified: " \
                  'must be a hash of environment variable name to string value.'
        next
      end

      hook_env.each do |var_name, var_value|
        if var_name.include?('=')
          errors << "#{hook_type}::#{hook_name} has an invalid `env` specified: " \
                    "variable name `#{var_name}` cannot contain `=`."
        end

        unless var_value.nil? || var_value.is_a?(String)
          errors << "#{hook_type}::#{hook_name} has an invalid `env` specified: " \
                    "value of `#{var_name}` must be a string or `nil`, but was " \
                    "#{var_value.inspect} (#{var_value.class})"
        end
      end
    end
  end

  if errors.any?
    if @log
      @log.error errors.join("\n")
      @log.newline
    end
    raise Overcommit::Exceptions::ConfigurationError,
          'One or more hooks had an invalid `env` configuration option'
  end
end
check_hook_name_format(hash) click to toggle source

Prints an error message and raises an exception if a hook has an invalid name, since this can result in strange errors elsewhere.

# File lib/overcommit/configuration_validator.rb, line 98
def check_hook_name_format(hash)
  errors = []

  Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
    hash.fetch(hook_type) { {} }.each_key do |hook_name|
      next if hook_name == 'ALL'

      unless hook_name.match?(/\A[A-Za-z0-9]+\z/)
        errors << "#{hook_type}::#{hook_name} has an invalid name " \
                  "#{hook_name}. It must contain only alphanumeric " \
                  'characters (no underscores or dashes, etc.)'
      end
    end
  end

  if errors.any?
    if @log
      @log.error errors.join("\n")
      @log.newline
    end
    raise Overcommit::Exceptions::ConfigurationError,
          'One or more hooks had invalid names'
  end
end
convert_nils_to_empty_hashes(hash) click to toggle source

Normalizes `nil` values to empty hashes.

This is useful for when we want to merge two configuration hashes together, since it's easier to merge two hashes than to have to check if one of the values is nil.

# File lib/overcommit/configuration_validator.rb, line 46
def convert_nils_to_empty_hashes(hash)
  hash.each_with_object({}) do |(key, value), h|
    h[key] =
      case value
      when nil  then {}
      when Hash then convert_nils_to_empty_hashes(value)
      else
        value
      end
  end
end
ensure_hook_type_sections_exist(hash) click to toggle source

Ensures that keys for all supported hook types exist (PreCommit, CommitMsg, etc.)

# File lib/overcommit/configuration_validator.rb, line 34
def ensure_hook_type_sections_exist(hash)
  Overcommit::Utils.supported_hook_type_classes.each do |hook_type|
    hash[hook_type] ||= {}
    hash[hook_type]['ALL'] ||= {}
  end
end