From 4eb21579874634404ceeab6371eb8c925a13061d Mon Sep 17 00:00:00 2001 From: r7kamura Date: Mon, 28 Oct 2024 10:14:56 +0900 Subject: [PATCH] Add `--format github` option --- README.md | 11 +++--- lib/reek/cli/options.rb | 4 +- lib/reek/report.rb | 12 +++--- lib/reek/report/github_report.rb | 55 ++++++++++++++++++++++++++ spec/reek/report/github_report_spec.rb | 44 +++++++++++++++++++++ 5 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 lib/reek/report/github_report.rb create mode 100644 spec/reek/report/github_report_spec.rb diff --git a/README.md b/README.md index 98b129def..b3b572084 100644 --- a/README.md +++ b/README.md @@ -556,13 +556,14 @@ e.g., `codeclimate analyze -e duplication` ## Output formats -Reek supports 5 output formats: +Reek supports 6 output formats: * plain text (default) -* HTML (`--format html`) -* YAML (`--format yaml`, see also [YAML Reports](docs/YAML-Reports.md)) -* JSON (`--format json`) -* XML (`--format xml`) +* HTML (`--format html`) +* YAML (`--format yaml`, see also [YAML Reports](docs/YAML-Reports.md)) +* JSON (`--format json`) +* XML (`--format xml`) +* GitHub (`--format github`) ## Working with Rails diff --git a/lib/reek/cli/options.rb b/lib/reek/cli/options.rb index f5143c2cb..87211af82 100644 --- a/lib/reek/cli/options.rb +++ b/lib/reek/cli/options.rb @@ -131,9 +131,9 @@ def set_generate_todo_list_options def set_alternative_formatter_options parser.separator "\nReport format:" parser.on( - '-f', '--format FORMAT', [:html, :text, :yaml, :json, :xml], + '-f', '--format FORMAT', [:html, :text, :yaml, :json, :xml, :github], 'Report smells in the given format:', - ' html', ' text (default)', ' yaml', ' json', ' xml') do |opt| + ' html', ' text (default)', ' yaml', ' json', ' xml', ' github') do |opt| self.report_format = opt end end diff --git a/lib/reek/report.rb b/lib/reek/report.rb index da0e7244e..2bf8b0967 100644 --- a/lib/reek/report.rb +++ b/lib/reek/report.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative 'report/github_report' require_relative 'report/html_report' require_relative 'report/json_report' require_relative 'report/text_report' @@ -16,11 +17,12 @@ module Reek # Reek reporting functionality. module Report REPORT_CLASSES = { - yaml: YAMLReport, - json: JSONReport, - html: HTMLReport, - xml: XMLReport, - text: TextReport + yaml: YAMLReport, + json: JSONReport, + html: HTMLReport, + xml: XMLReport, + text: TextReport, + github: GithubReport }.freeze LOCATION_FORMATTERS = { diff --git a/lib/reek/report/github_report.rb b/lib/reek/report/github_report.rb new file mode 100644 index 000000000..389fe16dd --- /dev/null +++ b/lib/reek/report/github_report.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require_relative 'base_report' + +module Reek + module Report + # + # Displays smells as GitHub Workflow commands. + # + # @public + # + class GithubReport < BaseReport + def show(out = $stdout) + out.print(workflow_commands.join) + end + + private + + def workflow_commands + smells.map do |smell| + WorkflowCommand.new(smell) + end + end + + # Represents a smell as a GitHub Workflow command. + class WorkflowCommand + def initialize(smell) + @smell = smell + end + + def to_s + format( + "::warning file=%s,line=%d::%s\n", + file: file, + line: line, + message: message) + end + + private + + def file + @smell.source + end + + def line + @smell.lines.first + end + + def message + @smell.base_message.gsub('%', '%25').gsub("\r", '%0D').gsub("\n", '%0A') + end + end + end + end +end diff --git a/spec/reek/report/github_report_spec.rb b/spec/reek/report/github_report_spec.rb new file mode 100644 index 000000000..074a56aca --- /dev/null +++ b/spec/reek/report/github_report_spec.rb @@ -0,0 +1,44 @@ +require_relative '../../spec_helper' +require_lib 'reek/examiner' +require_lib 'reek/report/json_report' + +RSpec.describe Reek::Report::GithubReport do + let(:instance) do + described_class.new + end + + let(:examiner) do + Reek::Examiner.new(source) + end + + context 'with empty source' do + let(:source) do + '' + end + + it 'prints empty string' do + instance.add_examiner(examiner) + expect { instance.show }.not_to output.to_stdout + end + end + + context 'with smelly source' do + let(:source) do + <<~RUBY + def simple(a) + a[3] + end + RUBY + end + + it 'prints smells as GitHub Workflow commands' do + instance.add_examiner(examiner) + expect { instance.show }.to output( + <<~TEXT + ::warning file=string,line=1::UncommunicativeParameterName: simple has the parameter name 'a' + ::warning file=string,line=1::UtilityFunction: simple doesn't depend on instance state (maybe move it to another class?) + TEXT + ).to_stdout + end + end +end