Skip to content

Commit

Permalink
[Fixes #9340] Added info Severity level to allow offenses to be lis…
Browse files Browse the repository at this point in the history
…ted but not return a non-zero error code.
  • Loading branch information
dvandersluis authored and bbatsov committed Jan 26, 2021
1 parent 1ac510e commit 6f6efd0
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 18 deletions.
1 change: 1 addition & 0 deletions changelog/new_added_info_severity_level_to_allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#9340](https://github.com/rubocop-hq/rubocop/pull/9340): Added `info` Severity level to allow offenses to be listed but not return a non-zero error code. ([@dvandersluis][])
5 changes: 4 additions & 1 deletion docs/modules/ROOT/pages/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -498,9 +498,12 @@ Style/Alias:
Each cop has a default severity level based on which department it belongs
to. The level is normally `warning` for `Lint` and `convention` for all the
others, but this can be changed in user configuration. Cops can customize their
severity level. Allowed values are `refactor`, `convention`, `warning`, `error`
severity level. Allowed values are `info`, `refactor`, `convention`, `warning`, `error`
and `fatal`.

Cops with severity `info` will be reported but will not cause `rubocop` to return
a non-zero value.

There is one exception from the general rule above and that is `Lint/Syntax`, a
special cop that checks for syntax errors before the other cops are invoked. It
cannot be disabled and its severity (`fatal`) cannot be changed in
Expand Down
6 changes: 3 additions & 3 deletions lib/rubocop/cop/severity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ module Cop
class Severity
include Comparable

NAMES = %i[refactor convention warning error fatal].freeze
NAMES = %i[info refactor convention warning error fatal].freeze

# @api private
CODE_TABLE = { R: :refactor, C: :convention,
CODE_TABLE = { I: :info, R: :refactor, C: :convention,
W: :warning, E: :error, F: :fatal }.freeze

# @api public
Expand All @@ -18,7 +18,7 @@ class Severity
#
# @return [Symbol]
# severity.
# any of `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
# any of `:info`, `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
attr_reader :name

def self.name_from_code(code)
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop/formatter/git_hub_actions_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def github_escape(string)

def minimum_severity_to_fail
@minimum_severity_to_fail ||= begin
# Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
name = options.fetch(:fail_level, :refactor)
RuboCop::Cop::Severity.new(name)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ module OptionsHelp
'This option applies to the previously',
'specified --format, or the default format',
'if no format is specified.'],
fail_level: ['Minimum severity (A/R/C/W/E/F) for exit',
fail_level: ['Minimum severity (A/I/R/C/W/E/F) for exit',
'with error code.'],
display_time: 'Display elapsed time in seconds.',
display_only_failed: ['Only output offense messages. Omit passing',
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ def considered_failure?(offense)

def minimum_severity_to_fail
@minimum_severity_to_fail ||= begin
# Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
name = @options[:fail_level] || :refactor
RuboCop::Cop::Severity.new(name)
end
Expand Down
97 changes: 96 additions & 1 deletion spec/rubocop/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1585,7 +1585,7 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85}
cli.run(%w[--format simple -c rubocop.yml])
expect($stderr.string)
.to eq(["Warning: Invalid severity 'superbad'. " \
'Valid severities are refactor, convention, ' \
'Valid severities are info, refactor, convention, ' \
'warning, error, fatal.',
''].join("\n"))
end
Expand Down Expand Up @@ -2069,4 +2069,99 @@ def find_suggestions
end
end
end

describe 'info severity' do
let(:code) do
<<~RUBY
# frozen-string-literal: true
'this line is longer than the accepted maximum'
RUBY
end

before do
create_file('.rubocop.yml', <<~YAML)
Lint/LineLength:
Max: 30
Severity: info
YAML

create_file('test.rb', code)
end

context 'when there are only info offenses' do
it 'returns a 0 code' do
expect(cli.run(['--format', 'simple', 'test.rb'])).to eq(0)
expect($stdout.string).to eq <<~RESULT
== test.rb ==
I: 3: 31: Layout/LineLength: Line is too long. [47/30]
1 file inspected, 1 offense detected
RESULT
end
end

context 'when there are not only info offenses' do
let(:code) do
<<~RUBY
'this line is longer than the accepted maximum'
RUBY
end

it 'returns a 1 code' do
expect(cli.run(['--format', 'simple', 'test.rb'])).to eq(1)
expect($stdout.string).to eq <<~RESULT
== test.rb ==
C: 1: 1: [Correctable] Style/FrozenStringLiteralComment: Missing frozen string literal comment.
I: 1: 31: Layout/LineLength: Line is too long. [47/30]
1 file inspected, 2 offenses detected, 1 offense auto-correctable
RESULT
end
end

context 'when given `--fail-level info`' do
it 'returns a 1 code' do
expect(cli.run(['--format', 'simple', '--fail-level', 'info', 'test.rb'])).to eq(1)
expect($stdout.string).to eq <<~RESULT
== test.rb ==
I: 3: 31: Layout/LineLength: Line is too long. [47/30]
1 file inspected, 1 offense detected
RESULT
end
end

context 'when given `--display-only-fail-level-offenses`' do
it 'returns a 0 code but does not list offenses' do
expect(cli.run(['--format', 'simple', '--display-only-fail-level-offenses', 'test.rb']))
.to eq(0)
expect($stdout.string).to eq <<~RESULT
1 file inspected, no offenses detected
RESULT
end
end

context 'when `Lint/Syntax` is given `Severity: info`' do
let(:code) do
<<~RUBY
1 /// 2
RUBY
end

before do
create_file('.rubocop.yml', <<~YAML)
Lint/Syntax:
Severity: info
YAML
end

it 'is an invalid configuration' do
expect(cli.run(['--format', 'simple', 'test.rb'])).to eq(2)
expect($stderr.string)
.to include('Error: configuration for Syntax cop found in .rubocop.yml')
end
end
end
end
16 changes: 12 additions & 4 deletions spec/rubocop/cop/offense_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,27 @@
.level
end

context 'when severity is :refactor' do
let(:severity) { :refactor }
context 'when severity is :info' do
let(:severity) { :info }

it 'is 1' do
expect(severity_level).to eq(1)
end
end

context 'when severity is :refactor' do
let(:severity) { :refactor }

it 'is 2' do
expect(severity_level).to eq(2)
end
end

context 'when severity is :fatal' do
let(:severity) { :fatal }

it 'is 5' do
expect(severity_level).to eq(5)
it 'is 6' do
expect(severity_level).to eq(6)
end
end
end
Expand Down
27 changes: 22 additions & 5 deletions spec/rubocop/cop/severity_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Severity do
let(:info) { described_class.new(:info) }
let(:refactor) { described_class.new(:refactor) }
let(:convention) { described_class.new(:convention) }
let(:warning) { described_class.new(:warning) }
Expand All @@ -26,6 +27,10 @@
end

describe '#code' do
describe 'info' do
it { expect(info.code).to eq('I') }
end

describe 'refactor' do
it { expect(refactor.code).to eq('R') }
end
Expand All @@ -48,28 +53,36 @@
end

describe '#level' do
describe 'info' do
it { expect(info.level).to eq(1) }
end

describe 'refactor' do
it { expect(refactor.level).to eq(1) }
it { expect(refactor.level).to eq(2) }
end

describe 'convention' do
it { expect(convention.level).to eq(2) }
it { expect(convention.level).to eq(3) }
end

describe 'warning' do
it { expect(warning.level).to eq(3) }
it { expect(warning.level).to eq(4) }
end

describe 'error' do
it { expect(error.level).to eq(4) }
it { expect(error.level).to eq(5) }
end

describe 'fatal' do
it { expect(fatal.level).to eq(5) }
it { expect(fatal.level).to eq(6) }
end
end

describe 'constructs from code' do
describe 'I' do
it { expect(described_class.new('I')).to eq(info) }
end

describe 'R' do
it { expect(described_class.new('R')).to eq(refactor) }
end
Expand All @@ -92,6 +105,10 @@
end

describe 'Comparable' do
describe 'info' do
it { expect(info).to be < refactor }
end

describe 'refactor' do
it { expect(refactor).to be < convention }
end
Expand Down
6 changes: 3 additions & 3 deletions spec/rubocop/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def abs(path)
--display-only-failed Only output offense messages. Omit passing
cops. Only valid for --format junit.
-r, --require FILE Require Ruby file.
--fail-level SEVERITY Minimum severity (A/R/C/W/E/F) for exit
--fail-level SEVERITY Minimum severity (A/I/R/C/W/E/F) for exit
with error code.
--display-only-fail-level-offenses
Only output offense messages at
Expand Down Expand Up @@ -253,14 +253,14 @@ def abs(path)

describe '--fail-level' do
it 'accepts full severity names' do
%w[refactor convention warning error fatal].each do |severity|
%w[info refactor convention warning error fatal].each do |severity|
expect { options.parse(['--fail-level', severity]) }
.not_to raise_error
end
end

it 'accepts severity initial letters' do
%w[R C W E F].each do |severity|
%w[I R C W E F].each do |severity|
expect { options.parse(['--fail-level', severity]) }
.not_to raise_error
end
Expand Down

0 comments on commit 6f6efd0

Please sign in to comment.