Skip to content

Commit

Permalink
New option --display-only-failed for junit format
Browse files Browse the repository at this point in the history
Speeds up test report processing for large codebases and helps address
the sorts of concerns raised at
mikian/rubocop-junit-formatter#18.

Refactors file_finished method in junit_formatter.rb to reduce
complexity.

Fixes buggy error message when --disable-uncorrectable is run without
--auto-correct, which I noticed because I added similar error messaging
when you try to run --display-only-failed without --format junit

Tests, CHANGELOG.md, doc updates, and help message updates to accompany
new option.
  • Loading branch information
burnettk authored and bbatsov committed Jun 1, 2020
1 parent b29d767 commit c1e0f10
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@
* [#7908](https://github.com/rubocop-hq/rubocop/pull/7908): Add new `Style/RedundantRegexpEscape` cop. ([@owst][])
* [#7978](https://github.com/rubocop-hq/rubocop/pull/7978): Add new option `OnlyFor` to the `Bundler/GemComment` cop. ([@ric2b][])
* [#8063](https://github.com/rubocop-hq/rubocop/issues/8063): Add new `AllowedNames` option for `Naming/ClassAndModuleCamelCase`. ([@tejasbubane][])
* New option `--display-only-failed` that can be used with `--format junit`. Speeds up test report processing for large codebases and helps address the sorts of concerns raised at [mikian/rubocop-junit-formatter #18](https://github.com/mikian/rubocop-junit-formatter/issues/18). ([@burnettk][])

### Bug fixes

Expand Down Expand Up @@ -4558,3 +4559,4 @@
[@CvX]: https://github.com/CvX
[@jschneid]: https://github.com/jschneid
[@ric2b]: https://github.com/ric2b
[@burnettk]: https://github.com/burnettk
13 changes: 13 additions & 0 deletions docs/modules/ROOT/pages/formatters.adoc
Expand Up @@ -280,6 +280,19 @@ $ rubocop --format junit
</testsuites>
----

The `junit` style formatter is very useful for continuous integration systems
such as Jenkins, most of which support junit formatting when parsing test
results. A typical invocation in this type of scenario might look like:

[source,sh]
----
$ rubocop --format junit --out test-reports/junit.xml
----

Since there is one XML node for each cop for each file, the size of the resulting
XML can get quite large. If it is too large for you, you can restrict the output
to just failures by adding the `--display-only-failed` option.

== Offense Count Formatter

Sometimes when first applying RuboCop to a codebase, it's nice to be able to
Expand Down
14 changes: 13 additions & 1 deletion legacy-docs/formatters.md
Expand Up @@ -242,7 +242,7 @@ The JSON structure is like the following example:
**Machine-parsable**
The `junit` style formatter provides the JUnit formatting.
This formatter is based on [rubocop-junit-formatter gem](https://github.com/mikian/rubocop-junit-formatter).
This formatter is based on the [rubocop-junit-formatter gem](https://github.com/mikian/rubocop-junit-formatter).
```sh
$ rubocop --format junit
Expand All @@ -268,6 +268,18 @@ $ rubocop --format junit
</testsuites>
```
The `junit` style formatter is very useful for continuous integration systems
such as Jenkins, most of which support junit formatting when parsing test
results. A typical invocation in this type of scenario might look like:
```sh
$ rubocop --format junit --out test-reports/junit.xml
```
Since there is one XML node for each cop for each file, the size of the resulting
XML can get quite large. If it is too large for you, you can restrict the output
to just failures by adding the `--display-only-failed` option.
## Offense Count Formatter
Sometimes when first applying RuboCop to a codebase, it's nice to be able to
Expand Down
18 changes: 14 additions & 4 deletions lib/rubocop/formatter/junit_formatter.rb
Expand Up @@ -35,19 +35,29 @@ def file_finished(file, offenses)
#
# In the future, it would be preferable to return only enabled cops.
Cop::Cop.all.each do |cop|
target_offenses = offenses_for_cop(offenses, cop)

next unless relevant_for_output?(options, target_offenses)

REXML::Element.new('testcase', @testsuite).tap do |testcase|
testcase.attributes['classname'] = classname_attribute_value(file)
testcase.attributes['name'] = cop.cop_name

target_offenses = offenses.select do |offense|
offense.cop_name == cop.cop_name
end

add_failure_to(testcase, target_offenses, cop.cop_name)
end
end
end

def relevant_for_output?(options, target_offenses)
!options[:display_only_failed] || target_offenses.any?
end

def offenses_for_cop(all_offenses, cop)
all_offenses.select do |offense|
offense.cop_name == cop.cop_name
end
end

def classname_attribute_value(file)
file.gsub(/\.rb\Z/, '').gsub("#{Dir.pwd}/", '').tr('/', '.')
end
Expand Down
16 changes: 14 additions & 2 deletions lib/rubocop/options.rb
Expand Up @@ -143,6 +143,8 @@ def add_formatting_options(opts)
@options[:output_path] = path
end
end

option(opts, '--display-only-failed')
end

def add_severity_option(opts)
Expand Down Expand Up @@ -286,6 +288,7 @@ def validate_compatibility # rubocop:disable Metrics/MethodLength
end
validate_auto_gen_config
validate_auto_correct
validate_display_only_failed
validate_parallel

return if incompatible_options.size <= 1
Expand All @@ -309,13 +312,20 @@ def validate_auto_gen_config
end
end

def validate_display_only_failed
return unless @options.key?(:display_only_failed)
return if @options[:format] == 'junit'

raise OptionArgumentError,
format('--display-only-failed can only be used together with --format junit.')
end

def validate_auto_correct
return if @options.key?(:auto_correct)
return unless @options.key?(:disable_uncorrectable)

raise OptionArgumentError,
format('--%<flag>s can only be used together with --auto-correct.',
flag: '--disable-uncorrectable')
format('--disable-uncorrectable can only be used together with --auto-correct.')
end

def validate_parallel
Expand Down Expand Up @@ -431,6 +441,8 @@ module OptionsHelp
'if no format is specified.'],
fail_level: ['Minimum severity (A/R/C/W/E/F) for exit',
'with error code.'],
display_only_failed: ['Only output offense messages. Omit passing',
'cops. Only valid for --format junit.'],
display_only_fail_level_offenses:
['Only output offense messages at',
'the specified --fail-level or above'],
Expand Down
14 changes: 14 additions & 0 deletions spec/rubocop/options_spec.rb
Expand Up @@ -92,6 +92,8 @@ def abs(path)
This option applies to the previously
specified --format, or the default format
if no format is specified.
--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
with error code.
Expand Down Expand Up @@ -224,6 +226,18 @@ def abs(path)
end
end

describe '--display-only-failed' do
it 'fails if given without --format junit' do
expect { options.parse %w[--display-only-failed] }
.to raise_error(RuboCop::OptionArgumentError)
end

it 'works if given with --format junit' do
expect { options.parse %w[--format junit --display-only-failed] }
.not_to raise_error(RuboCop::OptionArgumentError)
end
end

describe '--fail-level' do
it 'accepts full severity names' do
%w[refactor convention warning error fatal].each do |severity|
Expand Down

0 comments on commit c1e0f10

Please sign in to comment.