diff --git a/CHANGELOG.md b/CHANGELOG.md index be809a170cd..0315c9762d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * [#7776](https://github.com/rubocop-hq/rubocop/issues/7776): Fix crash for `Layout/MultilineMethodCallBraceLayout` when comment is present before closing braces. ([@shekhar-patil][]) * [#8282](https://github.com/rubocop-hq/rubocop/issues/8282): Fix `Style/IfUnlessModifier` bad precedence detection. ([@tejasbubane][]) * [#8289](https://github.com/rubocop-hq/rubocop/issues/8289): Fix `Style/AccessorGrouping` to not register offense for accessor with comment. ([@tejasbubane][]) +* [#8310](https://github.com/rubocop-hq/rubocop/pull/8310): Handle major version requirements in `Gemspec/RequiredRubyVersion`. ([@eugeneius][]) ### Changes diff --git a/docs/modules/ROOT/pages/cops_gemspec.adoc b/docs/modules/ROOT/pages/cops_gemspec.adoc index ec8b98b3cb6..619828ca092 100644 --- a/docs/modules/ROOT/pages/cops_gemspec.adoc +++ b/docs/modules/ROOT/pages/cops_gemspec.adoc @@ -187,6 +187,11 @@ end Gem::Specification.new do |spec| spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0'] end + +# good +Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2.5' +end ---- === Configurable attributes diff --git a/lib/rubocop/cop/gemspec/required_ruby_version.rb b/lib/rubocop/cop/gemspec/required_ruby_version.rb index 906d3dc9b6d..c399bb4ab53 100644 --- a/lib/rubocop/cop/gemspec/required_ruby_version.rb +++ b/lib/rubocop/cop/gemspec/required_ruby_version.rb @@ -35,6 +35,11 @@ module Gemspec # Gem::Specification.new do |spec| # spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0'] # end + # + # # good + # Gem::Specification.new do |spec| + # spec.required_ruby_version = '~> 2.5' + # end class RequiredRubyVersion < Cop MSG = '`required_ruby_version` (%s, ' \ 'declared in %s) and `TargetRubyVersion` ' \ @@ -68,7 +73,7 @@ def extract_ruby_version(required_ruby_version) end end - required_ruby_version.str_content.match(/(\d\.\d)/)[1] + required_ruby_version.str_content.scan(/\d/).first(2).join('.') end def message(required_ruby_version, target_ruby_version) diff --git a/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb b/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb index 54b976fd34d..44d7d4abe5f 100644 --- a/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb +++ b/spec/rubocop/cop/gemspec/required_ruby_version_spec.rb @@ -2,8 +2,7 @@ RSpec.describe RuboCop::Cop::Gemspec::RequiredRubyVersion, :config do context 'target ruby version > 2.7', :ruby27 do - it 'registers an offense when `required_ruby_version` is lower than ' \ - '`TargetRubyVersion`' do + it 'registers an offense when `required_ruby_version` is specified with >= and is lower than `TargetRubyVersion`' do expect_offense(<<~RUBY, '/path/to/foo.gemspec') Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.6.0' @@ -12,6 +11,15 @@ RUBY end + it 'registers an offense when `required_ruby_version` is specified with ~> and is lower than `TargetRubyVersion`' do + expect_offense(<<~RUBY, '/path/to/foo.gemspec') + Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2.6.0' + ^^^^^^^^^^ `required_ruby_version` (2.6, declared in foo.gemspec) and `TargetRubyVersion` (2.7, which may be specified in .rubocop.yml) should be equal. + end + RUBY + end + describe 'false negatives' do it 'does not register an offense when `required_ruby_version` ' \ 'is assigned as a variable (string literal)' do @@ -37,8 +45,7 @@ end context 'target ruby version > 2.5', :ruby25 do - it 'registers an offense when `required_ruby_version` is higher than ' \ - '`TargetRubyVersion`' do + it 'registers an offense when `required_ruby_version` is specified with >= and is higher than `TargetRubyVersion`' do expect_offense(<<~RUBY, '/path/to/bar.gemspec') Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.6.0' @@ -46,11 +53,19 @@ end RUBY end + + it 'registers an offense when `required_ruby_version` is specified with ~> and is higher than `TargetRubyVersion`' do + expect_offense(<<~RUBY, '/path/to/bar.gemspec') + Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2.6.0' + ^^^^^^^^^^ `required_ruby_version` (2.6, declared in bar.gemspec) and `TargetRubyVersion` (2.5, which may be specified in .rubocop.yml) should be equal. + end + RUBY + end end context 'target ruby version > 2.6', :ruby26 do - it 'does not register an offense when `required_ruby_version` equals ' \ - '`TargetRubyVersion`' do + it 'does not register an offense when `required_ruby_version` is specified with >= and equals `TargetRubyVersion`' do expect_no_offenses(<<~RUBY) Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.6.0' @@ -58,8 +73,16 @@ RUBY end - it 'does not register an offense when `required_ruby_version` ' \ - '(omit patch version) equals `TargetRubyVersion`' do + it 'does not register an offense when `required_ruby_version` is specified with ~> and equals `TargetRubyVersion`' do + expect_no_offenses(<<~RUBY) + Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2.6.0' + end + RUBY + end + + it 'does not register an offense when `required_ruby_version` is specified with >= without a patch version and ' \ + 'equals `TargetRubyVersion`' do expect_no_offenses(<<~RUBY) Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.6' @@ -67,6 +90,15 @@ RUBY end + it 'does not register an offense when `required_ruby_version` is specified with ~> without a patch version and ' \ + 'equals `TargetRubyVersion`' do + expect_no_offenses(<<~RUBY) + Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2.6' + end + RUBY + end + it 'does not register an offense when lowest version of ' \ '`required_ruby_version` equals `TargetRubyVersion`' do expect_no_offenses(<<~RUBY) @@ -75,5 +107,25 @@ end RUBY end + + it 'registers an offense when `required_ruby_version` is specified with >= without a minor version and is lower ' \ + 'than `TargetRubyVersion`' do + expect_offense(<<~RUBY, 'bar.gemspec') + Gem::Specification.new do |spec| + spec.required_ruby_version = '>= 2' + ^^^^^^ `required_ruby_version` (2, declared in bar.gemspec) and `TargetRubyVersion` (2.6, which may be specified in .rubocop.yml) should be equal. + end + RUBY + end + + it 'registers an offense when `required_ruby_version` is specified with ~> without a minor version and is lower ' \ + 'than `TargetRubyVersion`' do + expect_offense(<<~RUBY, 'bar.gemspec') + Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2' + ^^^^^^ `required_ruby_version` (2, declared in bar.gemspec) and `TargetRubyVersion` (2.6, which may be specified in .rubocop.yml) should be equal. + end + RUBY + end end end