From a3ddbe2bcbfb476e0ed8f95cc1ff4b84c8645262 Mon Sep 17 00:00:00 2001 From: Teppei Shintani Date: Sun, 7 Apr 2024 16:16:25 +0900 Subject: [PATCH] Add JSON output format option to rails stats Enhance the rails stats command to support JSON formatted output, enabling easier consumption of architecture metrics by automated systems. This modification improves the utility of the stats command for continuous monitoring of application maturity and health. Example usage: ``` $ bin/rails stats[json] | jq . { "code_statistics": [ { "name": "Controllers", "statistic": { "lines": 12345, "code_lines": 12345, "classes": 123, "methods": 1234 } }, ... ], "total": { "lines": 12345, "code_lines": 12345, "classes": 123, "methods": 1234 } } ``` --- railties/CHANGELOG.md | 30 ++++++++++ railties/lib/rails/code_statistics.rb | 12 ++++ .../lib/rails/code_statistics_calculator.rb | 9 +++ railties/lib/rails/tasks/statistics.rake | 10 +++- .../test/code_statistics_calculator_test.rb | 5 ++ railties/test/code_statistics_test.rb | 55 +++++++++++++++++++ 6 files changed, 119 insertions(+), 2 deletions(-) diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 5cff64f07e157..5d9c5fe202a83 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,33 @@ +* Add JSON output format to `rails stats` via `format` option. + + Enables JSON formatted output for better integration with automated systems. Maintains default table format unless specified. + + ```shell + $ bin/rails stats[json] | jq . + { + "code_statistics": [ + { + "name": "Controllers", + "statistic": { + "lines": 12345, + "code_lines": 12345, + "classes": 123, + "methods": 1234 + } + }, + ... + ], + "total": { + "lines": 12345, + "code_lines": 12345, + "classes": 123, + "methods": 1234 + } + } + ``` + + *Teppei Shintani* + * Allow Actionable Errors encountered when running tests to be retried. ```txt diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index cead365037e79..cc0130a8120e1 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -35,6 +35,18 @@ def to_s print_code_test_stats end + def to_h + { + code_statistics: @statistics.map do |k, v| + { + name: k, + statistic: v.to_h + } + end, + total: @total&.to_h + } + end + private def calculate_statistics Hash[@pairs.map { |pair| [pair.first, calculate_directory_statistics(pair.last)] }] diff --git a/railties/lib/rails/code_statistics_calculator.rb b/railties/lib/rails/code_statistics_calculator.rb index 1503eb7eefc20..c1515d847e4fb 100644 --- a/railties/lib/rails/code_statistics_calculator.rb +++ b/railties/lib/rails/code_statistics_calculator.rb @@ -86,6 +86,15 @@ def add_by_io(io, file_type) end end + def to_h + { + lines: lines, + code_lines: code_lines, + classes: classes, + methods: methods + } + end + private def file_type(file_path) if file_path.end_with? "_test.rb" diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake index c8198c4ee18bf..dae6602ffb88d 100644 --- a/railties/lib/rails/tasks/statistics.rake +++ b/railties/lib/rails/tasks/statistics.rake @@ -29,10 +29,16 @@ STATS_DIRECTORIES ||= [ ] desc "Report code statistics (KLOCs, etc) from the application or engine" -task :stats do +task :stats, :format do |_, args| require "rails/code_statistics" stat_directories = STATS_DIRECTORIES.collect do |name, dir| [ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ] end.select { |name, dir| File.directory?(dir) } - CodeStatistics.new(*stat_directories).to_s + statistics = CodeStatistics.new(*stat_directories) + case args[:format] + when "json" + puts statistics.to_h.to_json + else + statistics.to_s + end end diff --git a/railties/test/code_statistics_calculator_test.rb b/railties/test/code_statistics_calculator_test.rb index 49c123fa998e2..2eacb0870467b 100644 --- a/railties/test/code_statistics_calculator_test.rb +++ b/railties/test/code_statistics_calculator_test.rb @@ -84,6 +84,11 @@ class A; end assert_equal 6, @code_statistics_calculator.methods end + test "return statistics as a hash" do + code_statistics_calculator = CodeStatisticsCalculator.new(1, 2, 3, 4) + assert_equal({ lines: 1, code_lines: 2, classes: 3, methods: 4 }, code_statistics_calculator.to_h) + end + test "calculate number of Ruby methods" do code = <<-'CODE' def foo diff --git a/railties/test/code_statistics_test.rb b/railties/test/code_statistics_test.rb index 7ad1ac309486a..48d31b3c4f5ec 100644 --- a/railties/test/code_statistics_test.rb +++ b/railties/test/code_statistics_test.rb @@ -31,4 +31,59 @@ def foo CodeStatistics.new(["hidden file", @tmp_path]) end end + + test "output results in table format" do + File.write File.join(@tmp_path, "example.rb"), <<-CODE + class Example + def foo + puts 'foo' + end + end + CODE + + code_statistics = CodeStatistics.new(["tmp dir", @tmp_path]) + expected = <<~TABLE + +----------------------+--------+--------+---------+---------+-----+-------+ + | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | + +----------------------+--------+--------+---------+---------+-----+-------+ + | tmp dir | 5 | 5 | 1 | 1 | 1 | 3 | + +----------------------+--------+--------+---------+---------+-----+-------+ + Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0 + + TABLE + + output, _ = capture_io do + code_statistics.to_s + end + + assert_equal expected, output + end + + test "return results in hash format" do + File.write File.join(@tmp_path, "example.rb"), <<-CODE + class Example + def foo + puts 'foo' + end + end + CODE + + code_statistics = CodeStatistics.new(["tmp dir", @tmp_path]) + expected = { + code_statistics: [ + { + name: "tmp dir", + statistic: { + lines: 5, + code_lines: 5, + classes: 1, + methods: 1 + } + } + ], + total: nil + } + + assert_equal expected, code_statistics.to_h + end end