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
- .fragment_default_basename_from_env(env = ENV) ⇒ 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
84 85 86 |
# File 'lib/polyrun/coverage/collector.rb', line 84 def branch_coverage_enabled? %w[1 true yes].include?(ENV["POLYRUN_COVERAGE_BRANCHES"]&.downcase) end |
.build_meta(cfg) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/polyrun/coverage/collector.rb', line 125 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 CollectorFragmentMeta.(m, cfg[:fragment_meta]) 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)).
100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/polyrun/coverage/collector.rb', line 100 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
88 89 90 91 |
# File 'lib/polyrun/coverage/collector.rb', line 88 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 29 30 |
# 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"], polyrun_shard_matrix_index: ENV["POLYRUN_SHARD_MATRIX_INDEX"], polyrun_shard_matrix_total: ENV["POLYRUN_SHARD_MATRIX_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
121 122 123 |
# File 'lib/polyrun/coverage/collector.rb', line 121 def self.finish_debug_time_label CollectorFragmentMeta.finish_debug_time_label end |
.fragment_default_basename_from_env(env = ENV) ⇒ Object
39 40 41 |
# File 'lib/polyrun/coverage/collector.rb', line 39 def self.fragment_default_basename_from_env(env = ENV) CollectorFragmentMeta.fragment_default_basename_from_env(env) end |
.keep_under_root(blob, root, track_under) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/polyrun/coverage/collector.rb', line 174 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
158 159 160 161 162 163 |
# File 'lib/polyrun/coverage/collector.rb', line 158 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
165 166 167 168 169 170 171 172 |
# File 'lib/polyrun/coverage/collector.rb', line 165 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).
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/polyrun/coverage/collector.rb', line 142 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).
115 116 117 118 119 |
# File 'lib/polyrun/coverage/collector.rb', line 115 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
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 74 75 76 77 78 79 80 81 82 |
# File 'lib/polyrun/coverage/collector.rb', line 43 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) basename = fragment_default_basename_from_env output_path ||= File.join(root, "coverage", "polyrun-fragment-#{basename}.json") strict = if minimum_line_percent.nil? false else strict.nil? || strict end = CollectorFragmentMeta.(basename) @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, fragment_meta: } 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).
94 95 96 |
# File 'lib/polyrun/coverage/collector.rb', line 94 def self.started? instance_variable_defined?(:@config) && @config end |