Module: Polyrun::Coverage::Collector
- Defined in:
- lib/polyrun/coverage/collector.rb,
lib/polyrun/coverage/collector_finish.rb
Overview
Stdlib Coverage → SimpleCov-compatible JSON for merge-coverage / report-coverage. No SimpleCov gem. Enable with POLYRUN_COVERAGE=1 or call start! from spec_helper.
Disable with POLYRUN_COVERAGE_DISABLE=1 or SIMPLECOV_DISABLE=1 (migration alias).
Branch coverage: set POLYRUN_COVERAGE_BRANCHES=1 so stdlib Coverage.start records branches; merge-coverage merges branch keys when present in fragments.
Class Method Summary collapse
- .branch_coverage_enabled? ⇒ Boolean
- .build_meta(cfg) ⇒ Object
-
.coverage_requested_for_quick?(root = Dir.pwd) ⇒ Boolean
Whether polyrun quick should call Rails.start! before loading quick files: not disabled, and (+POLYRUN_COVERAGE=1+ or (
config/polyrun_coverage.ymlexists and POLYRUN_QUICK_COVERAGE=1)). - .disabled? ⇒ Boolean
- .finish ⇒ Object
- .finish_debug_time_label ⇒ Object
- .keep_under_root(blob, root, track_under) ⇒ Object
- .normalize_blob_paths(blob, root) ⇒ Object
- .normalize_groups(groups) ⇒ Object
-
.result_to_blob(raw) ⇒ Object
Normalizes stdlib Coverage.result to merge-compatible file entries (lines; branches when collected).
-
.run_formatter_per_worker? ⇒ Boolean
When
POLYRUN_SHARD_TOTAL> 1, each worker only writes the JSON fragment; merged reports (merge-coverage/report-coverage) are authoritative. - .start!(root:, reject_patterns: [], track_under: ["lib"], track_files: nil, groups: nil, output_path: nil, minimum_line_percent: nil, strict: nil, meta: {}, formatter: nil, report_output_dir: nil, report_basename: "polyrun-coverage") ⇒ Object
-
.started? ⇒ Boolean
True after a successful Collector.start! in this process (stdlib
Coverageis active).
Class Method Details
.branch_coverage_enabled? ⇒ Boolean
75 76 77 |
# File 'lib/polyrun/coverage/collector.rb', line 75 def branch_coverage_enabled? %w[1 true yes].include?(ENV["POLYRUN_COVERAGE_BRANCHES"]&.downcase) end |
.build_meta(cfg) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/polyrun/coverage/collector.rb', line 120 def (cfg) m = (cfg[:meta] || {}).transform_keys(&:to_s) m["polyrun_version"] = Polyrun::VERSION m["timestamp"] ||= Time.now.to_i m["command_name"] ||= "rspec" m["polyrun_coverage_root"] = cfg[:root].to_s if cfg[:groups] m["polyrun_coverage_groups"] = cfg[:groups].transform_keys(&:to_s).transform_values(&:to_s) end if cfg[:track_files] m["polyrun_track_files"] = cfg[:track_files] end m end |
.coverage_requested_for_quick?(root = Dir.pwd) ⇒ Boolean
Whether polyrun quick should call Rails.start! before loading quick files: not disabled, and (+POLYRUN_COVERAGE=1+ or (config/polyrun_coverage.yml exists and POLYRUN_QUICK_COVERAGE=1)).
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/polyrun/coverage/collector.rb', line 91 def self.coverage_requested_for_quick?(root = Dir.pwd) return false if disabled? return true if %w[1 true yes].include?(ENV["POLYRUN_COVERAGE"]&.to_s&.downcase) path = File.join(File.(root), "config", "polyrun_coverage.yml") return false unless File.file?(path) # Config file alone is for merge/report defaults; opt-in so test suites that only # keep polyrun_coverage.yml for gates do not start Collector during `polyrun quick`. %w[1 true yes].include?(ENV["POLYRUN_QUICK_COVERAGE"]&.to_s&.downcase) end |
.disabled? ⇒ Boolean
79 80 81 82 |
# File 'lib/polyrun/coverage/collector.rb', line 79 def disabled? %w[1 true yes].include?(ENV["POLYRUN_COVERAGE_DISABLE"]&.downcase) || %w[1 true yes].include?(ENV["SIMPLECOV_DISABLE"]&.downcase) end |
.finish ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/polyrun/coverage/collector_finish.rb', line 9 def finish cfg = @config || return # rubocop:disable ThreadSafety/ClassInstanceVariable -- Collector stores @config from start! (same process) Polyrun::Debug.log_worker_kv( collector_finish: "start", polyrun_shard_index: ENV["POLYRUN_SHARD_INDEX"], polyrun_shard_total: ENV["POLYRUN_SHARD_TOTAL"], output_path: cfg[:output_path] ) Polyrun::Debug.time(Collector.finish_debug_time_label) do blob = Collector.send(:prepare_finish_blob, cfg) summary = Merge.console_summary(blob) group_payload = cfg[:groups] ? TrackFiles.group_summaries(blob, cfg[:root], cfg[:groups]) : nil Collector.send(:exit_if_below_minimum_line_percent, cfg, summary) Collector.send(:write_finish_fragment!, cfg, blob, group_payload) Collector.send(:run_finish_formatter!, cfg, blob, group_payload) Polyrun::Log.warn Merge.format_console_summary(summary) if ENV["POLYRUN_COVERAGE_VERBOSE"] end end |
.finish_debug_time_label ⇒ Object
112 113 114 115 116 117 118 |
# File 'lib/polyrun/coverage/collector.rb', line 112 def self.finish_debug_time_label if ENV["POLYRUN_SHARD_TOTAL"].to_i > 1 "worker pid=#{$$} shard=#{ENV.fetch("POLYRUN_SHARD_INDEX", "?")} Coverage::Collector.finish (write fragment)" else "Coverage::Collector.finish (write fragment)" end end |
.keep_under_root(blob, root, track_under) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/polyrun/coverage/collector.rb', line 168 def keep_under_root(blob, root, track_under) return blob if track_under.nil? || track_under.empty? root = File.(root) prefixes = track_under.map { |d| File.join(root, d) } blob.each_with_object({}) do |(path, entry), acc| p = path.to_s next unless prefixes.any? { |pre| p == pre || p.start_with?(pre + "/") } acc[path] = entry end end |
.normalize_blob_paths(blob, root) ⇒ Object
152 153 154 155 156 157 |
# File 'lib/polyrun/coverage/collector.rb', line 152 def normalize_blob_paths(blob, root) root = File.(root) blob.each_with_object({}) do |(path, entry), acc| acc[File.(path.to_s, root)] = entry end end |
.normalize_groups(groups) ⇒ Object
159 160 161 162 163 164 165 166 |
# File 'lib/polyrun/coverage/collector.rb', line 159 def normalize_groups(groups) return nil if groups.nil? h = groups.is_a?(Hash) ? groups : {} return nil if h.empty? h.transform_keys(&:to_s).transform_values(&:to_s) end |
.result_to_blob(raw) ⇒ Object
Normalizes stdlib Coverage.result to merge-compatible file entries (lines; branches when collected).
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/polyrun/coverage/collector.rb', line 136 def result_to_blob(raw) out = {} raw.each do |path, cov| next unless cov.is_a?(Hash) lines = cov[:lines] || cov["lines"] next unless lines.is_a?(Array) entry = {"lines" => lines.map { |x| x }} br = cov[:branches] || cov["branches"] entry["branches"] = br if br out[path.to_s] = entry end out end |
.run_formatter_per_worker? ⇒ Boolean
When POLYRUN_SHARD_TOTAL > 1, each worker only writes the JSON fragment; merged reports (merge-coverage / report-coverage) are authoritative. Set POLYRUN_COVERAGE_WORKER_FORMATS=1 to force per-worker formatter output (debug only; duplicates work N times).
106 107 108 109 110 |
# File 'lib/polyrun/coverage/collector.rb', line 106 def run_formatter_per_worker? return true if ENV["POLYRUN_COVERAGE_WORKER_FORMATS"] == "1" ENV["POLYRUN_SHARD_TOTAL"].to_i <= 1 end |
.start!(root:, reject_patterns: [], track_under: ["lib"], track_files: nil, groups: nil, output_path: nil, minimum_line_percent: nil, strict: nil, meta: {}, formatter: nil, report_output_dir: nil, report_basename: "polyrun-coverage") ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/polyrun/coverage/collector.rb', line 37 def start!(root:, reject_patterns: [], track_under: ["lib"], track_files: nil, groups: nil, output_path: nil, minimum_line_percent: nil, strict: nil, meta: {}, formatter: nil, report_output_dir: nil, report_basename: "polyrun-coverage") return if disabled? root = File.(root) shard = ENV.fetch("POLYRUN_SHARD_INDEX", "0") output_path ||= File.join(root, "coverage", "polyrun-fragment-#{shard}.json") strict = if minimum_line_percent.nil? false else strict.nil? || strict end @config = { root: root, track_under: Array(track_under).map(&:to_s), track_files: track_files, groups: normalize_groups(groups), reject_patterns: reject_patterns, output_path: output_path, minimum_line_percent: minimum_line_percent, strict: strict, meta: , formatter: formatter, report_output_dir: report_output_dir, report_basename: report_basename, shard_total_at_start: ENV["POLYRUN_SHARD_TOTAL"].to_i } unless ::Coverage.running? ::Coverage.start(lines: true, branches: branch_coverage_enabled?) end unless instance_variable_defined?(:@collector_finish_at_exit_registered) @collector_finish_at_exit_registered = true at_exit { finish } end nil end |
.started? ⇒ Boolean
True after a successful start! in this process (stdlib Coverage is active).
85 86 87 |
# File 'lib/polyrun/coverage/collector.rb', line 85 def self.started? instance_variable_defined?(:@config) && @config end |