Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes #467 this is a useful feature for some folks with complex deployments #538

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/coverband/adapters/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ def merge_expanded_data(new_expanded, old_expanded)

# TODO: This should only be 2 cases get our dup / not dups aligned
def array_add(latest, original)
if Coverband.configuration.use_oneshot_lines_coverage
if latest.empty? && original.empty?
[]
elsif Coverband.configuration.use_oneshot_lines_coverage
latest.map!.with_index { |v, i| ((v + original[i] >= 1) ? 1 : 0) if v && original[i] }
elsif Coverband.configuration.simulate_oneshot_lines_coverage
latest.map.with_index { |v, i| ((v + original[i] >= 1) ? 1 : 0) if v && original[i] }
Expand Down
9 changes: 9 additions & 0 deletions lib/coverband/adapters/redis_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ def raw_store
@redis
end

def file_count
data = redis.get type_base_key(Coverband::RUNTIME_TYPE)
JSON.parse(data).keys.length
end

def cached_file_count
@cached_file_count ||= file_count
end

private

attr_reader :redis
Expand Down
38 changes: 36 additions & 2 deletions lib/coverband/reporters/json_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
module Coverband
module Reporters
class JSONReport < Base
attr_accessor :filtered_report_files, :options, :page, :as_report, :store, :filename, :base_path
attr_accessor :filtered_report_files, :options, :page, :as_report, :store, :filename, :base_path, :line_coverage,
:for_merged_report

def initialize(store, options = {})
self.options = options
self.page = options.fetch(:page) { nil }
self.filename = options.fetch(:filename) { nil }
self.as_report = options.fetch(:as_report) { false }
self.line_coverage = options.fetch(:line_coverage) { false }
self.for_merged_report = options.fetch(:for_merged_report) { false }
self.base_path = options.fetch(:base_path) { "./" }
self.store = store

Expand All @@ -28,6 +31,33 @@ def report
report_as_json
end

def merge_reports(first_report, second_report, options = {})
merged_data = {}
merged_data[Coverband::RUNTIME_TYPE.to_s] = Coverband::Adapters::Base.new.send(
:merge_reports,
first_report[Coverband::RUNTIME_TYPE.to_s],
second_report[Coverband::RUNTIME_TYPE.to_s],
{skip_expansion: true}
)
if first_report[Coverband::EAGER_TYPE.to_s] && second_report[Coverband::EAGER_TYPE.to_s]
merged_data[Coverband::EAGER_TYPE.to_s] = Coverband::Adapters::Base.new.send(
:merge_reports,
first_report[Coverband::EAGER_TYPE.to_s],
second_report[Coverband::EAGER_TYPE.to_s],
{skip_expansion: true}
)
end
if first_report[Coverband::MERGED_TYPE.to_s] && second_report[Coverband::MERGED_TYPE.to_s]
merged_data[Coverband::MERGED_TYPE.to_s] = Coverband::Adapters::Base.new.send(
:merge_reports,
first_report[Coverband::MERGED_TYPE.to_s],
second_report[Coverband::MERGED_TYPE.to_s],
{skip_expansion: true}
)
end
merged_data
end

private

def coverage_css_class(covered_percent)
Expand All @@ -43,6 +73,8 @@ def coverage_css_class(covered_percent)
end

def report_as_json
return filtered_report_files.to_json if for_merged_report

result = Coverband::Utils::Results.new(filtered_report_files)
source_files = result.source_files

Expand Down Expand Up @@ -97,7 +129,7 @@ def coverage_totals(source_files)
def coverage_files(result, source_files)
source_files.each_with_object({}) do |source_file, hash|
runtime_coverage = result.file_with_type(source_file, Coverband::RUNTIME_TYPE)&.covered_lines_count || 0
hash[source_file.short_name] = {
data = {
filename: source_file.filename,
hash: Digest::SHA1.hexdigest(source_file.filename),
never_loaded: source_file.never_loaded,
Expand All @@ -109,6 +141,8 @@ def coverage_files(result, source_files)
covered_percent: source_file.covered_percent,
covered_strength: source_file.covered_strength
}
data[:coverage] = source_file.coverage if line_coverage
hash[source_file.short_name] = data
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/coverband/utils/dead_methods.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# frozen_string_literal: ntrue
# frozen_string_literal: true

require "coverband/utils/method_definition_scanner"

Expand Down
41 changes: 39 additions & 2 deletions lib/coverband/utils/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@
require "coverband/utils/results"
require "coverband/reporters/json_report"

report = Coverband::Reporters::JSONReport.new(Coverband.configuration.store).report
File.write("coverage/coverage.json", report)
report = Coverband::Reporters::JSONReport.new(Coverband.configuration.store, {
for_merged_report: !!ENV["FOR_MERGED_REPORT"],
line_coverage: true
}).report
`mkdir -p coverage`
File.write("coverage/coverage.json.#{Time.now.to_f}", report)
end

###
Expand Down Expand Up @@ -68,6 +72,39 @@
SimpleCov::Formatter::HTMLFormatter.new.format(result)
end

####
# This task can aggregate multiple coverage files into a single coverage report
# * `FOR_MERGED_REPORT=true bundle exec rake coverband:coverage_json` to generate the JSON files
# * collect all the files over time in some system or as artifacts in CI, then run...
# * `bundle exec rake coverband:aggregate_coverage` to merge the files
# * the output will include a timestamp of when it was output...
####
task :aggregate_coverage do |task, args|
require "coverband/utils/result"
require "coverband/utils/file_list"
require "coverband/utils/source_file"
require "coverband/utils/lines_classifier"
require "coverband/utils/results"
require "coverband/reporters/json_report"

directory = "./coverage"
pattern = "coverage.json*"

# Use Dir.glob to find files matching the pattern in the specified directory
files = Dir.glob(File.join(directory, pattern))

report = {}
files.each do |file|
data = JSON.parse(File.read(file))
report = if report.empty?
data
else
Coverband::Reporters::JSONReport.new(Coverband.configuration.store).merge_reports(report, data)
end
end
File.write("coverage/coverage_merged.json.#{Time.now.to_f}", report.to_json)
end

desc "Run a simple rack app to report Coverband code coverage"
task :coverage_server do
if Rake::Task.task_defined?("environment")
Expand Down
1 change: 0 additions & 1 deletion test/coverband/reporters/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ def setup
roots = ['/base/[0-9]*/', '/base/78/app/']

Coverband.configuration.stubs(:all_root_paths).returns(roots)
lines_hit = [1, 3, 6]
store.stubs(:merged_coverage).returns(coverage)
File.expects(:exist?).at_least_once
.with('/base/[0-9]*/app/controllers/dashboard_controller.rb')
Expand Down
11 changes: 11 additions & 0 deletions test/coverband/reporters/json_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,15 @@ def setup
assert_equal parsed["files"][file].keys, expected_keys
end
end

test "supports merging" do
@store.send(:save_report, basic_coverage)
first_report = JSON.parse(Coverband::Reporters::JSONReport.new(@store, for_merged_report: true).report)

@store.send(:save_report, increased_basic_coverage)
second_report = JSON.parse(Coverband::Reporters::JSONReport.new(@store, for_merged_report: true).report)
data = Coverband::Reporters::JSONReport.new(@store).merge_reports(first_report, second_report)
assert_equal data[Coverband::RUNTIME_TYPE.to_s]["app_path/dog.rb"]["data"], [0, 4, 10]
assert_equal data[Coverband::MERGED_TYPE.to_s]["app_path/dog.rb"]["data"], [0, 4, 10]
end
end
4 changes: 4 additions & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ def basic_coverage
{"app_path/dog.rb" => example_line}
end

def increased_basic_coverage
{"app_path/dog.rb" => [0, 2, 6]}
end

def basic_coverage_full_path
{basic_coverage_file_full_path => example_line}
end
Expand Down