From 21923459157bfacef51912fbf877f1785793da32 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 16 Mar 2024 15:42:22 -0400 Subject: [PATCH 1/2] Refactor code and add a json option --- bin/churn | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/bin/churn b/bin/churn index 49f2d12..092c370 100755 --- a/bin/churn +++ b/bin/churn @@ -7,6 +7,7 @@ bin_file = Pathname.new(__FILE__).realpath $:.unshift File.expand_path("../../lib", bin_file) require 'churn/calculator' +require 'churn/reporter' require 'churn/version' require 'main' require 'yaml' @@ -24,6 +25,11 @@ Main do default false end + option('json', 'j') do + cast :boolean + default false + end + option('ignore_files', 'i') do cast :string argument :optional @@ -80,33 +86,9 @@ Main do default false end - def report_churn(output_string) - options = { - minimum_churn_count: params['minimum_churn_count'].value, - ignore_files: params['ignore_files'].value, - start_date: params['start_date'].value, - data_directory: params['data_directory'].value, - history: params['past_history'].value, - report: params['report'].value, - name: params['name'].value, - file_extension: params['extension'].value, - file_prefix: params['prefix'].value, - } - if params['version'].value - puts Churn::VERSION - return - end - - result = Churn::ChurnCalculator.new(options).report(output_string) - if output_string - result - else - YAML::dump(result) - end - end - def run - report = report_churn(!params['yaml'].value) + reporter = Churn::ChurnReporter.new(params) + report = reporter.report_churn puts report end end From 7c04103ad083e0f798c557b0ee6ca425db08c006 Mon Sep 17 00:00:00 2001 From: Ernesto Tagwerker Date: Sat, 16 Mar 2024 15:42:42 -0400 Subject: [PATCH 2/2] Refactor reporter class out of the bin/churn file This also adds support for a JSON format output. --- lib/churn/reporter.rb | 57 +++++++++++++++++++++++++++++ test/unit/reporter_test.rb | 73 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 lib/churn/reporter.rb create mode 100644 test/unit/reporter_test.rb diff --git a/lib/churn/reporter.rb b/lib/churn/reporter.rb new file mode 100644 index 0000000..0523611 --- /dev/null +++ b/lib/churn/reporter.rb @@ -0,0 +1,57 @@ +require 'json' + +require_relative 'calculator' +require_relative 'version' + +module Churn + + # The reporter of churn results. Knows how to report churn + # in different formats: + # + # - Console (stdout) + # - YAML + # - JSON + class ChurnReporter + attr_accessor :calculator, :options, :params + + def initialize(_params) + self.params = _params + self.options = { + minimum_churn_count: params['minimum_churn_count'].value, + ignore_files: params['ignore_files'].value, + start_date: params['start_date'].value, + data_directory: params['data_directory'].value, + history: params['past_history'].value, + report: params['report'].value, + name: params['name'].value, + file_extension: params['extension'].value, + file_prefix: params['prefix'].value, + json: params['json'].value, + yaml: params['yaml'].value, + } + self.calculator = Churn::ChurnCalculator.new(options) + end + + # Knows how to return a churn result in different formats. + # + # @return [String] + def report_churn + print_output = !options[:json] && !options[:yaml] + + if params['version'].value + puts Churn::VERSION + return + end + + result = calculator.report(print_output) + + if options[:json] + JSON::dump(result) + elsif options[:yaml] + YAML::dump(result) + else + result + end + end + end +end diff --git a/test/unit/reporter_test.rb b/test/unit/reporter_test.rb new file mode 100644 index 0000000..e4c5e49 --- /dev/null +++ b/test/unit/reporter_test.rb @@ -0,0 +1,73 @@ +require 'minitest/autorun' +require_relative '../../lib/churn/reporter' + +class ChurnReporterTest < Minitest::Test + StructOption = Struct.new(:value) + + def setup + @params = { + 'minimum_churn_count' => StructOption.new(3), + 'ignore_files' => StructOption.new('file.rb'), + 'start_date' => StructOption.new('2022-01-01'), + 'data_directory' => StructOption.new('/data'), + 'past_history' => StructOption.new(true), + 'report' => StructOption.new('summary'), + 'name' => StructOption.new('churn_report'), + 'extension' => StructOption.new('.rb'), + 'prefix' => StructOption.new('churn_'), + 'json' => StructOption.new(false), + 'yaml' => StructOption.new(false), + 'version' => StructOption.new(false) + } + churn_calculator = Churn::ChurnCalculator.new({:minimum_churn_count => 3}) + + churn_calculator.stubs(:parse_log_for_changes).returns([['file.rb', 4],['less.rb',1]]) + churn_calculator.stubs(:parse_log_for_revision_changes).returns(['revision']) + churn_calculator.stubs(:analyze) + @churn_reporter = Churn::ChurnReporter.new(@params) + @churn_reporter.calculator = churn_calculator + end + + test "initialize sets the params as an instance variable" do + assert_equal @params, @churn_reporter.params + end + + test "report churn prints version when version param is true" do + @params['version'].value = true + + expected_output = "#{Churn::VERSION}\n" + + assert_output(expected_output) { @churn_reporter.report_churn } + end + + test "report churn returns result as json when json param is true" do + @churn_reporter.options[:json] = true + + result = "{\"churn\":{\"changes\":[[\"file.rb\",4]],\"class_churn\":{},\"method_churn\":{}}}" + + assert_equal result, @churn_reporter.report_churn + end + + test "report churn returns result as yaml when yaml param is true" do + @churn_reporter.options[:yaml] = true + + result =<<~EOS + --- + :churn: + :changes: + - - file.rb + - 4 + :class_churn: {} + :method_churn: {} + EOS + + assert_equal result, @churn_reporter.report_churn + end + + test "report churn returns result when neither json nor yaml param is true" do + output = @churn_reporter.report_churn + + assert_match /Revision Changes/, output + assert_match /Project Churn/, output + end +end \ No newline at end of file