diff --git a/.editorconfig b/.editorconfig index 6923bce..eb57fc2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,3 +8,7 @@ trim_trailing_whitespace = true [*.yml] indent_style = space indent_size = 2 + +[*.md.erb] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a9ce59..7e6dd25 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,7 +49,9 @@ jobs: - name: Install dependencies run: bundler install - name: Run the test - run: bundle exec rake test spec + run: bundle exec rake test spec && cat coverage/coverage.md >> $GITHUB_STEP_SUMMARY + env: + COVERAGE: true notify: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index d8d2871..810ff11 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /.gem_rbs_collection /tmp /gemfiles/*.lock +/coverage diff --git a/.projections.json b/.projections.json new file mode 100644 index 0000000..a43279c --- /dev/null +++ b/.projections.json @@ -0,0 +1,40 @@ +{ + "lib/*.rb": { + "type": "lib", + "alternate": "spec/{}_spec.rb", + "related": [ + "sig/{}.rbs" + ] + }, + "test/*_test.rb": { + "type": "test", + "dispatch": "bundle exec ruby -Itest {file}", + "alternate": "lib/{}.rb", + "related": [ + "sig/{}.rbs" + ] + }, + "spec/*_spec.rb": { + "type": "spec", + "dispatch": "bundle exec ruby -Ispec {file}", + "alternate": "lib/{}.rb", + "related": [ + "sig/{}.rbs" + ] + }, + "sig/*.rbs": { + "type": "sig", + "alternate": "lib/{}.rb", + "related": [ + "spec/{}_spec.rb", + "test/{}_test.rb" + ] + }, + "README.md": { + "type": "doc" + }, + "*": { + "make": "bundle exec rake", + "console": "bundle exec irb -rgraft" + } +} diff --git a/gemfiles/ruby-3.3.gemfile b/gemfiles/ruby-3.3.gemfile index bbe071f..897dd7a 100644 --- a/gemfiles/ruby-3.3.gemfile +++ b/gemfiles/ruby-3.3.gemfile @@ -7,6 +7,7 @@ gem "rake", "~> 13.1.0" group :test do gem "minitest", "~> 5.22.3" gem "minitest-reporters", "~> 1.7.1" + gem "simplecov", require: false end group :debug do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 10c3149..7d9094a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true +require_relative "spec_helper/simplecov" require_relative "spec_helper/minitest/reporter" diff --git a/spec/spec_helper/simplecov.rb b/spec/spec_helper/simplecov.rb new file mode 100644 index 0000000..4f6719c --- /dev/null +++ b/spec/spec_helper/simplecov.rb @@ -0,0 +1,24 @@ +if %w[y yes true 1].include? ENV["COVERAGE"] + require "simplecov" + require "simplecov_json_formatter" + require_relative "simplecov/formatters/markdown_formatter" + + SimpleCov.configure do + add_filter %r{(?:spec|test|bin)} + + SimpleCov.formatters = [ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::JSONFormatter, + SimpleCov::Formatter::MarkdownFormatter + ] + + # Ruby 2.5+ + enable_coverage :branch + primary_coverage :branch + + # Ruby 3.2+ + enable_coverage_for_eval + end + + SimpleCov.start +end diff --git a/spec/spec_helper/simplecov/formatters/markdown_formatter.rb b/spec/spec_helper/simplecov/formatters/markdown_formatter.rb new file mode 100644 index 0000000..601a8cb --- /dev/null +++ b/spec/spec_helper/simplecov/formatters/markdown_formatter.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +# Ensure we are using a compatible version of SimpleCov +major, minor, patch = SimpleCov::VERSION.scan(/\d+/).first(3).map(&:to_i) +if major < 0 || minor < 9 || patch < 0 + raise "The version of SimpleCov you are using is too old. " \ + "Please update with `gem install simplecov` or `bundle update simplecov`" +end + +require "simplecov-html" + +module SimpleCov + module Formatter + class MarkdownFormatter < HTMLFormatter + def initialize + @branchable_result = SimpleCov.branch_coverage? + @templates = {} + end + + def format(result) + File.open(File.join(output_path, "coverage.md"), "wb") do |file| + file.puts template("layout").result(binding) + end + + # TODO: disabled til `views/source_file.md.erb` is implemented + # result.source_files.each do |source_file| + # path = File.dirname(File.join(output_path, shortened_filename(source_file))) + # + # FileUtils.mkdir_p(path) + # + # File.open(File.join(output_path, shortened_filename(source_file)) + ".md", "wb") do |file| + # file.puts formatted_source_file(source_file) + # end + # end + + puts output_message(result) + end + + def output_message(result) + str = "Markdown coverage report generated for #{result.command_name} to #{output_path}. #{result.covered_lines} / #{result.total_lines} LOC (#{result.covered_percent.round(2)}%) covered." + str += " #{result.covered_branches} / #{result.total_branches} branches (#{result.coverage_statistics[:branch].percent.round(2)}%) covered." if branchable_result? + str + end + + private + + # Returns the an erb instance for the template of given name + def template(name) + @templates[name] ||= ERB.new(File.read(File.join(File.dirname(__FILE__), "./views/", "#{name}.md.erb"))) + end + + def link_to_source_file(source_file) + shortened_filename source_file + end + end + end +end diff --git a/spec/spec_helper/simplecov/formatters/views/covered_percent.md.erb b/spec/spec_helper/simplecov/formatters/views/covered_percent.md.erb new file mode 100644 index 0000000..dd208bf --- /dev/null +++ b/spec/spec_helper/simplecov/formatters/views/covered_percent.md.erb @@ -0,0 +1 @@ +<%= percent.round(2) %>% \ No newline at end of file diff --git a/spec/spec_helper/simplecov/formatters/views/file_list.md.erb b/spec/spec_helper/simplecov/formatters/views/file_list.md.erb new file mode 100644 index 0000000..11f665a --- /dev/null +++ b/spec/spec_helper/simplecov/formatters/views/file_list.md.erb @@ -0,0 +1,10 @@ +# All Files ( <%= covered_percent(source_files.covered_percent) %> covered at <%= source_files.covered_strength.round(2) %> ) hits / line + +**<%= source_files.length %>** files in total. +**<%= source_files.lines_of_code %>** relevant lines, **<%= source_files.covered_lines %>** lines covered and **<%= source_files.missed_lines %>** lines missed. (<%= covered_percent(source_files.covered_percent) %>)<% if branchable_result? %> +**<%= source_files.total_branches %>** total branches, **<%= source_files.covered_branches %>** branches covered and **<%= source_files.missed_branches %>** branches missed. (<%= covered_percent(source_files.branch_covered_percent) %>)<% end %> + +| File | % covered | Lines | Relevant Lines | Lines covered | Lines missed | Avg. Hits / Line | <% if branchable_result? %> Branch Coverage | Branches | Covered branches | Missed branches | <% end %> +| ---- | --------: | ----: | -------------: | ------------: | -----------: | ---------------: | <% if branchable_result? %> --------------: | -------: | ---------------: | --------------: | <% end %> +<% source_files.each do |source_file| %>| <%= link_to_source_file(source_file) %> | <%= sprintf("%.2f", source_file.covered_percent.round(2)) %> % | <%= source_file.lines.count %> | <%= source_file.covered_lines.count + source_file.missed_lines.count %> | <%= source_file.covered_lines.count %> | <%= source_file.missed_lines.count %> | <%= sprintf("%.2f", source_file.covered_strength.round(2)) %> |<% if branchable_result? %> <%= sprintf("%.2f", source_file.branches_coverage_percent.round(2)) %> % | <%= source_file.total_branches.count %> | <%= source_file.covered_branches.count %> | <%= source_file.missed_branches.count %> |<% end %> +<% end %> diff --git a/spec/spec_helper/simplecov/formatters/views/layout.md.erb b/spec/spec_helper/simplecov/formatters/views/layout.md.erb new file mode 100644 index 0000000..cd3f2f1 --- /dev/null +++ b/spec/spec_helper/simplecov/formatters/views/layout.md.erb @@ -0,0 +1,6 @@ + +<%= formatted_file_list("All Files", result.source_files) %> + +<% result.groups.each do |name, files| %> +<%= formatted_file_list(name, files) %> +<% end %> \ No newline at end of file diff --git a/spec/spec_helper/simplecov/formatters/views/source_file.md.erb b/spec/spec_helper/simplecov/formatters/views/source_file.md.erb new file mode 100644 index 0000000..c5cefd3 --- /dev/null +++ b/spec/spec_helper/simplecov/formatters/views/source_file.md.erb @@ -0,0 +1 @@ +<%= shortened_filename source_file %> \ No newline at end of file