From d372598fc08787494b003d2a477b8f4e43805a03 Mon Sep 17 00:00:00 2001 From: Daniel Vandersluis Date: Wed, 22 Sep 2021 14:33:43 -0400 Subject: [PATCH] [Fix #9934] Fix configuration loading to not raise an error for an obsolete ruby version that is subsequently overridden. --- ..._fix_configuration_loading_to_not_raise.md | 1 + lib/rubocop/config.rb | 5 ++ lib/rubocop/config_loader.rb | 2 + lib/rubocop/config_validator.rb | 10 ++- spec/rubocop/config_loader_spec.rb | 79 +++++++++++++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_fix_configuration_loading_to_not_raise.md diff --git a/changelog/fix_fix_configuration_loading_to_not_raise.md b/changelog/fix_fix_configuration_loading_to_not_raise.md new file mode 100644 index 00000000000..5677d7c1481 --- /dev/null +++ b/changelog/fix_fix_configuration_loading_to_not_raise.md @@ -0,0 +1 @@ +* [#9934](https://github.com/rubocop/rubocop/issues/9934): Fix configuration loading to not raise an error for an obsolete ruby version that is subsequently overridden. ([@dvandersluis][]) diff --git a/lib/rubocop/config.rb b/lib/rubocop/config.rb index 50de3b963c1..9bdcad1ec95 100644 --- a/lib/rubocop/config.rb +++ b/lib/rubocop/config.rb @@ -51,6 +51,11 @@ def check self end + def validate_after_resolution + @validator.validate_after_resolution + self + end + def_delegators :@hash, :[], :[]=, :delete, :dig, :each, :key?, :keys, :each_key, :fetch, :map, :merge, :replace, :to_h, :to_hash, :transform_values def_delegators :@validator, :validate, :target_ruby_version diff --git a/lib/rubocop/config_loader.rb b/lib/rubocop/config_loader.rb index d6f2e7a8515..e3a46a791d1 100644 --- a/lib/rubocop/config_loader.rb +++ b/lib/rubocop/config_loader.rb @@ -101,6 +101,8 @@ def configuration_from_file(config_file, check: true) return default_configuration if config_file == DEFAULT_FILE config = load_file(config_file, check: check) + config.validate_after_resolution if check + if ignore_parent_exclusion? print 'Ignoring AllCops/Exclude from parent folders' if debug? else diff --git a/lib/rubocop/config_validator.rb b/lib/rubocop/config_validator.rb index 87656273736..8d4868350bc 100644 --- a/lib/rubocop/config_validator.rb +++ b/lib/rubocop/config_validator.rb @@ -44,7 +44,6 @@ def validate check_obsoletions alert_about_unrecognized_cops(invalid_cop_names) - check_target_ruby validate_new_cops_parameter validate_parameter_names(valid_cop_names) validate_enforced_styles(valid_cop_names) @@ -52,6 +51,15 @@ def validate reject_mutually_exclusive_defaults end + # Validations that should only be run after all config resolving has + # taken place: + # * The target ruby version is only checked once the entire inheritance + # chain has been loaded so that only the final value is validated, and + # any obsolete but overridden values are ignored. + def validate_after_resolution + check_target_ruby + end + def target_ruby_version target_ruby.version end diff --git a/spec/rubocop/config_loader_spec.rb b/spec/rubocop/config_loader_spec.rb index 30c2044d938..6fa0c96a96b 100644 --- a/spec/rubocop/config_loader_spec.rb +++ b/spec/rubocop/config_loader_spec.rb @@ -1155,6 +1155,85 @@ class Loop < Cop end end + context 'when a file inherits a configuration that specifies TargetRubyVersion' do + let(:file_path) { '.rubocop.yml' } + let(:target_ruby_version) { configuration_from_file['AllCops']['TargetRubyVersion'] } + let(:default_ruby_version) { RuboCop::TargetRuby::DEFAULT_VERSION } + + before do + create_file('.rubocop-parent.yml', <<~YAML) + AllCops: + TargetRubyVersion: #{inherited_version} + YAML + end + + context 'when the specified version is current' do + before do + create_file(file_path, <<~YAML) + inherit_from: .rubocop-parent.yml + YAML + end + + let(:inherited_version) { default_ruby_version } + + it 'sets TargetRubyVersion' do + expect(target_ruby_version).to eq(inherited_version) + end + end + + context 'when the specified version is obsolete' do + let(:inherited_version) { '2.4' } + + context 'and it is not overridden' do + before do + create_file(file_path, <<~YAML) + inherit_from: .rubocop-parent.yml + YAML + end + + it 'raises a validation error' do + expect { configuration_from_file }.to raise_error(RuboCop::ValidationError) do |error| + expect(error.message).to start_with('RuboCop found unsupported Ruby version 2.4') + end + end + end + + context 'and it is overridden' do + before do + create_file(file_path, <<~YAML) + inherit_from: .rubocop-parent.yml + + AllCops: + TargetRubyVersion: #{default_ruby_version} + YAML + end + + it 'uses the given version' do + expect(target_ruby_version).to eq(default_ruby_version) + end + end + + context 'with deeper nesting' do + before do + create_file('.rubocop-child.yml', <<~YAML) + inherit_from: .rubocop-parent.yml + YAML + + create_file('.rubocop.yml', <<~YAML) + inherit_from: .rubocop-child.yml + + AllCops: + TargetRubyVersion: #{default_ruby_version} + YAML + end + + it 'uses the given version' do + expect(target_ruby_version).to eq(default_ruby_version) + end + end + end + end + context 'EnabledByDefault / DisabledByDefault' do def cop_enabled?(cop_class) configuration_from_file.for_cop(cop_class).fetch('Enabled')