Skip to content

Commit

Permalink
Add JSONReporter
Browse files Browse the repository at this point in the history
Using the `-r` or `--reporter` argument, now it's possible to specify a
reporter other than the default.  The `--show-reporters` argument
returns back the list of available reporters.  The Reporter class was
modified to statically keep a list of its descendants. See:
http://stackoverflow.com/a/7774881

For the detailed specification, see:
http://www.rubydoc.info/gems/rubocop/0.11.0#JSON_Formatter

`haml-lint` doesn't return the column where the offense is, so it's
omitted from the location hash.

Change-Id: Ib116914d7f00502503ae4e65bd0bf81cc33c99ee
Reviewed-on: http://gerrit.causes.com/46518
Reviewed-by: Shane da Silva <[email protected]>
Tested-by: Shane da Silva <[email protected]>
  • Loading branch information
skateman authored and sds committed Feb 13, 2015
1 parent 182b536 commit 7d04364
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 3 deletions.
15 changes: 15 additions & 0 deletions lib/haml_lint/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def act_on_options(options)
elsif options[:show_linters]
print_available_linters
Sysexits::EX_OK
elsif options[:show_reporters]
print_available_reporters
Sysexits::EX_OK
else
scan_for_lints(options)
end
Expand Down Expand Up @@ -89,6 +92,18 @@ def print_available_linters
end
end

def print_available_reporters
log.info 'Available reporters:'

reporter_names = Reporter.descendants.map do |reporter|
reporter.name.split('::').last.sub(/Reporter$/, '').downcase
end

reporter_names.sort.each do |reporter_name|
log.log " - #{reporter_name}"
end
end

def print_help(options)
log.log options[:help]
end
Expand Down
9 changes: 9 additions & 0 deletions lib/haml_lint/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def add_linter_options(parser)
"Specify which linters you don't want to run") do |linters|
@options[:excluded_linters] = linters
end

parser.on('-r', '--reporter reporter', String,
"Specify which reporter you want to use to generate the output") do |reporter|
@options[:reporter] = HamlLint::Reporter.const_get("#{reporter.capitalize}Reporter")
end
end

def add_file_options(parser)
Expand All @@ -64,6 +69,10 @@ def add_info_options(parser)
@options[:show_linters] = true
end

parser.on('--show-reporters', 'Display available reporters') do
@options[:show_reporters] = true
end

parser.on('--[no-]color', 'Force output to be colorized') do |color|
@options[:color] = color
end
Expand Down
4 changes: 3 additions & 1 deletion lib/haml_lint/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ module HamlLint
# Contains information about all lints detected during a scan.
class Report
attr_accessor :lints
attr_reader :files

def initialize(lints)
def initialize(lints, files)
@lints = lints.sort_by { |l| [l.filename, l.line] }
@files = files
end

def failed?
Expand Down
11 changes: 11 additions & 0 deletions lib/haml_lint/reporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,30 @@ module HamlLint
# @abstract
class Reporter
attr_reader :lints
attr_reader :files

# @param logger [HamlLint::Logger]
# @param report [HamlLint::Report]
def initialize(logger, report)
@log = logger
@lints = report.lints
@files = report.files
end

# Implemented by subclasses to display lints from a {HamlLint::Report}.
def report_lints
raise NotImplementedError
end

# Keep tracking all the descendants of this class for the list of available reporters
def self.descendants
@descendants ||= []
end

def self.inherited(descendant)
descendants << descendant
end

private

attr_reader :log
Expand Down
34 changes: 34 additions & 0 deletions lib/haml_lint/reporter/json_reporter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module HamlLint
# Outputs JSON
class Reporter::JsonReporter < Reporter
def report_lints
grouped = lints.group_by(&:filename)
report = {
:metadata => {
:hamllint_version => VERSION,
:ruby_engine => RUBY_ENGINE,
:ruby_patchlevel => RUBY_PATCHLEVEL.to_s,
:ruby_platform => RUBY_PLATFORM
},
:files => grouped.map { |l| map_file(l) },
:summary => {
:offense_count => lints.length,
:target_file_count => grouped.length,
:inspected_file_count => files.length
}
}

log.log report.to_json
end

private

def map_file(file)
{:path => file.first, :offenses => file.last.map { |o| map_offense(o) }}
end

def map_offense(offense)
{:severity => offense.severity, :message => offense.message, :location => {:line => offense.line}}
end
end
end
5 changes: 4 additions & 1 deletion lib/haml_lint/runner.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module HamlLint
# Responsible for running the applicable linters against the desired files.
class Runner
# Make the list of applicable files available
attr_reader :files

# Runs the appropriate linters against the desired files given the specified
# options.
#
Expand All @@ -23,7 +26,7 @@ def run(options = {})
@lints += linter.lints
end

HamlLint::Report.new(@lints)
HamlLint::Report.new(@lints, files)
end

private
Expand Down
11 changes: 11 additions & 0 deletions spec/haml_lint/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@
it { should == Sysexits::EX_OK }
end

context 'when passed the --show-reporters flag' do
let(:args) { ['--show-reporters'] }

it 'displays the available reporters' do
subject
output.should include 'default'
end

it { should == Sysexits::EX_OK }
end

context 'when passed the --version flag' do
let(:args) { ['--version'] }

Expand Down
2 changes: 1 addition & 1 deletion spec/haml_lint/reporter/default_reporter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
let(:io) { StringIO.new }
let(:output) { io.string }
let(:logger) { HamlLint::Logger.new(io) }
let(:report) { HamlLint::Report.new(lints) }
let(:report) { HamlLint::Report.new(lints, []) }
let(:reporter) { described_class.new(logger, report) }

subject { reporter.report_lints }
Expand Down
71 changes: 71 additions & 0 deletions spec/haml_lint/reporter/json_reporter_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
require 'spec_helper'

describe HamlLint::Reporter::JsonReporter do
subject { HamlLint::Reporter::JsonReporter.new(lints) }

describe '#report_lints' do
let(:io) { StringIO.new }
let(:output) { JSON.parse(io.string) }
let(:logger) { HamlLint::Logger.new(io) }
let(:report) { HamlLint::Report.new(lints, []) }
let(:reporter) { described_class.new(logger, report) }

subject { reporter.report_lints }

shared_examples_for "output format specification" do
it 'output should be consistent with the specification' do
subject
output.should be_a_kind_of(Hash)
output['metadata'].should be_a_kind_of(Hash)
output['metadata'].length.should eq 4
output['metadata']['hamllint_version'].should_not be_empty
output['metadata']['ruby_engine'].should eq RUBY_ENGINE
output['metadata']['ruby_patchlevel'].should eq RUBY_PATCHLEVEL.to_s
output['metadata']['ruby_platform'].should eq RUBY_PLATFORM.to_s
output['files'].should be_a_kind_of(Array)
output['summary'].should be_a_kind_of(Hash)
output['summary'].length.should eq 3
output['summary']['offense_count'].should be_a_kind_of(Integer)
output['summary']['target_file_count'].should be_a_kind_of(Integer)
output['summary']['inspected_file_count'].should be_a_kind_of(Integer)
end
end

context 'when there are no lints' do
let(:lints) { [] }
let(:files) { [] }

it 'list of files is empty' do
subject
output['files'].should be_empty
end

it 'number of target files is zero' do
subject
output['summary']['target_file_count'].should == 0
end

it_behaves_like "output format specification"
end

context 'when there are lints' do
let(:filenames) { ['some-filename.haml', 'other-filename.haml'] }
let(:lines) { [502, 724] }
let(:descriptions) { ['Description of lint 1', 'Description of lint 2'] }
let(:severities) { [:warning, :error] }

let(:lints) do
filenames.each_with_index.map do |filename, index|
HamlLint::Lint.new(nil, filename, lines[index], descriptions[index], severities[index])
end
end

it 'list of files contains files with offenses' do
subject
output['files'].map { |f| f['path'] }.sort.should eq filenames.sort
end

it_behaves_like "output format specification"
end
end
end

0 comments on commit 7d04364

Please sign in to comment.