polyrun 1.5.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +2 -2
- data/docs/SETUP_PROFILE.md +2 -0
- data/lib/polyrun/cli/help.rb +7 -2
- data/lib/polyrun/cli/helpers.rb +16 -0
- data/lib/polyrun/cli/init_command.rb +8 -1
- data/lib/polyrun/cli/partition_diagnostics.rb +22 -0
- data/lib/polyrun/cli/plan_command.rb +47 -18
- data/lib/polyrun/cli/queue_command.rb +25 -2
- data/lib/polyrun/cli/run_queue_command.rb +145 -0
- data/lib/polyrun/cli/run_shards_command.rb +6 -1
- data/lib/polyrun/cli/run_shards_parallel_children.rb +2 -1
- data/lib/polyrun/cli/run_shards_plan_boot_phases.rb +47 -2
- data/lib/polyrun/cli/run_shards_plan_options.rb +12 -2
- data/lib/polyrun/cli/run_shards_planning.rb +20 -12
- data/lib/polyrun/cli/run_shards_run.rb +21 -4
- data/lib/polyrun/cli/spec_quality_commands.rb +140 -0
- data/lib/polyrun/cli.rb +16 -2
- data/lib/polyrun/coverage/example_diff.rb +122 -0
- data/lib/polyrun/data/factory_counts.rb +14 -1
- data/lib/polyrun/database/clone_shards.rb +2 -0
- data/lib/polyrun/database/shard.rb +2 -1
- data/lib/polyrun/minitest.rb +9 -0
- data/lib/polyrun/partition/hrw.rb +40 -3
- data/lib/polyrun/partition/paths_build.rb +8 -3
- data/lib/polyrun/partition/plan.rb +88 -19
- data/lib/polyrun/partition/plan_lpt.rb +49 -7
- data/lib/polyrun/partition/plan_sharding.rb +8 -0
- data/lib/polyrun/partition/reports.rb +139 -0
- data/lib/polyrun/partition/timing_diagnostics.rb +139 -0
- data/lib/polyrun/partition/timing_keys.rb +2 -1
- data/lib/polyrun/queue/duration.rb +30 -0
- data/lib/polyrun/queue/file_store.rb +107 -3
- data/lib/polyrun/quick/example_runner.rb +2 -0
- data/lib/polyrun/quick/runner.rb +21 -0
- data/lib/polyrun/rspec.rb +8 -0
- data/lib/polyrun/spec_quality/config.rb +134 -0
- data/lib/polyrun/spec_quality/fragment.rb +39 -0
- data/lib/polyrun/spec_quality/merge.rb +78 -0
- data/lib/polyrun/spec_quality/minitest_hook.rb +42 -0
- data/lib/polyrun/spec_quality/plan_loader.rb +47 -0
- data/lib/polyrun/spec_quality/profile.rb +91 -0
- data/lib/polyrun/spec_quality/report.rb +261 -0
- data/lib/polyrun/spec_quality/rspec_hook.rb +55 -0
- data/lib/polyrun/spec_quality/sql_counter.rb +34 -0
- data/lib/polyrun/spec_quality.rb +205 -0
- data/lib/polyrun/templates/POLYRUN.md +6 -0
- data/lib/polyrun/templates/ci_matrix.polyrun.yml +4 -0
- data/lib/polyrun/templates/polyrun_hooks_spec_quality.rb +12 -0
- data/lib/polyrun/templates/polyrun_spec_quality.yml +20 -0
- data/lib/polyrun/templates/rails_prepare.polyrun.yml +5 -0
- data/lib/polyrun/timing/merge.rb +5 -5
- data/lib/polyrun/timing/stats.rb +76 -0
- data/lib/polyrun/timing/summary.rb +5 -2
- data/lib/polyrun/timing/variance_report.rb +51 -0
- data/lib/polyrun/version.rb +1 -1
- metadata +22 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Polyrun
|
|
2
|
+
module Timing
|
|
3
|
+
# Normalizes scalar or object timing entries for merge and binpack weight lookup.
|
|
4
|
+
module Stats
|
|
5
|
+
STAT_KEYS = %w[last_seconds min max mean p95 runs failures timeouts].freeze
|
|
6
|
+
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def normalize_entry(value)
|
|
10
|
+
case value
|
|
11
|
+
when Hash
|
|
12
|
+
normalize_hash(value)
|
|
13
|
+
else
|
|
14
|
+
sec = value.to_f
|
|
15
|
+
{
|
|
16
|
+
"last_seconds" => sec,
|
|
17
|
+
"min" => sec,
|
|
18
|
+
"max" => sec,
|
|
19
|
+
"mean" => sec,
|
|
20
|
+
"p95" => sec,
|
|
21
|
+
"runs" => 1,
|
|
22
|
+
"failures" => 0,
|
|
23
|
+
"timeouts" => 0
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity -- timing hash key coercion
|
|
29
|
+
def normalize_hash(h)
|
|
30
|
+
out = {}
|
|
31
|
+
sec = h["last_seconds"] || h[:last_seconds] || h["seconds"] || h[:seconds]
|
|
32
|
+
sec = sec.to_f if sec
|
|
33
|
+
mean = (h["mean"] || h[:mean] || sec)&.to_f
|
|
34
|
+
out["last_seconds"] = (sec || mean || 0.0).to_f
|
|
35
|
+
out["min"] = (h["min"] || h[:min] || out["last_seconds"]).to_f
|
|
36
|
+
out["max"] = (h["max"] || h[:max] || out["last_seconds"]).to_f
|
|
37
|
+
out["mean"] = (mean || out["last_seconds"]).to_f
|
|
38
|
+
out["p95"] = (h["p95"] || h[:p95] || out["max"]).to_f
|
|
39
|
+
out["runs"] = Integer(h["runs"] || h[:runs] || 1)
|
|
40
|
+
out["failures"] = Integer(h["failures"] || h[:failures] || 0)
|
|
41
|
+
out["timeouts"] = Integer(h["timeouts"] || h[:timeouts] || 0)
|
|
42
|
+
out
|
|
43
|
+
end
|
|
44
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
45
|
+
|
|
46
|
+
def binpack_weight(entry)
|
|
47
|
+
h = normalize_entry(entry)
|
|
48
|
+
h["last_seconds"].positive? ? h["last_seconds"] : h["mean"]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# rubocop:disable Metrics/AbcSize -- weighted mean merge
|
|
52
|
+
def merge_entries(a, b)
|
|
53
|
+
ha = normalize_entry(a)
|
|
54
|
+
hb = normalize_entry(b)
|
|
55
|
+
runs = ha["runs"] + hb["runs"]
|
|
56
|
+
mean =
|
|
57
|
+
if runs.positive?
|
|
58
|
+
((ha["mean"] * ha["runs"]) + (hb["mean"] * hb["runs"])) / runs.to_f
|
|
59
|
+
else
|
|
60
|
+
0.0
|
|
61
|
+
end
|
|
62
|
+
{
|
|
63
|
+
"last_seconds" => [ha["last_seconds"], hb["last_seconds"]].max,
|
|
64
|
+
"min" => [ha["min"], hb["min"]].min,
|
|
65
|
+
"max" => [ha["max"], hb["max"]].max,
|
|
66
|
+
"mean" => mean,
|
|
67
|
+
"p95" => [ha["p95"], hb["p95"]].max,
|
|
68
|
+
"runs" => runs,
|
|
69
|
+
"failures" => ha["failures"] + hb["failures"],
|
|
70
|
+
"timeouts" => ha["timeouts"] + hb["timeouts"]
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
# rubocop:enable Metrics/AbcSize
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
require_relative "stats"
|
|
2
|
+
|
|
1
3
|
module Polyrun
|
|
2
4
|
module Timing
|
|
3
5
|
# Human-readable slow-file list from merged timing JSON (per-file cost).
|
|
4
6
|
module Summary
|
|
5
7
|
module_function
|
|
6
8
|
|
|
7
|
-
# +merged+ is path (String) => seconds (Float), as produced by +Timing::Merge.merge_files+.
|
|
9
|
+
# +merged+ is path (String) => seconds (Float) or stats Hash, as produced by +Timing::Merge.merge_files+.
|
|
8
10
|
def format_slow_files(merged, top: 30, title: "Polyrun slowest files (by wall time, seconds)")
|
|
9
11
|
return "#{title}\n (no data)\n" if merged.nil? || merged.empty?
|
|
10
12
|
|
|
11
|
-
pairs = merged.
|
|
13
|
+
pairs = merged.map { |path, sec| [path, Stats.binpack_weight(sec)] }
|
|
14
|
+
.sort_by { |(_, sec)| -sec.to_f }.first(Integer(top))
|
|
12
15
|
lines = [title, ""]
|
|
13
16
|
pairs.each_with_index do |(path, sec), i|
|
|
14
17
|
lines << format(" %2d. %s %.4f", i + 1, path, sec.to_f)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Polyrun
|
|
2
|
+
module Timing
|
|
3
|
+
# Flags high-variance, flaky, and regression timing entries.
|
|
4
|
+
module VarianceReport
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
# rubocop:disable Metrics/AbcSize -- variance flag scan
|
|
8
|
+
def analyze(merged_stats)
|
|
9
|
+
flags = []
|
|
10
|
+
merged_stats.each do |path, entry|
|
|
11
|
+
h = Stats.normalize_entry(entry)
|
|
12
|
+
next if h["runs"] < 2
|
|
13
|
+
|
|
14
|
+
median = h["mean"]
|
|
15
|
+
if median.positive? && (h["p95"] / median) > 2.0
|
|
16
|
+
flags << {path: path, kind: "high_variance", detail: "p95/mean=#{format("%.2f", h["p95"] / median)}"}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if h["runs"] >= 3 && (h["failures"].to_f / h["runs"]) > 0.3
|
|
20
|
+
flags << {path: path, kind: "often_failed", detail: "failures=#{h["failures"]}/#{h["runs"]}"}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if h["timeouts"].to_i >= 2
|
|
24
|
+
flags << {path: path, kind: "timeout_cluster", detail: "timeouts=#{h["timeouts"]}"}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if h["mean"].positive? && h["last_seconds"] > (2.0 * h["mean"])
|
|
28
|
+
flags << {path: path, kind: "runtime_regression", detail: "last=#{h["last_seconds"]} mean=#{h["mean"]}"}
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
flags
|
|
32
|
+
end
|
|
33
|
+
# rubocop:enable Metrics/AbcSize
|
|
34
|
+
|
|
35
|
+
def emit_warnings!(merged_stats)
|
|
36
|
+
analyze(merged_stats).each do |f|
|
|
37
|
+
Polyrun::Log.warn "polyrun timing #{f[:kind]}: #{f[:path]} (#{f[:detail]})"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def format_report(merged_stats)
|
|
42
|
+
lines = ["Polyrun timing variance report", ""]
|
|
43
|
+
analyze(merged_stats).each do |f|
|
|
44
|
+
lines << " [#{f[:kind]}] #{f[:path]} — #{f[:detail]}"
|
|
45
|
+
end
|
|
46
|
+
lines << " (none)" if lines.size == 2
|
|
47
|
+
lines.join("\n") + "\n"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/polyrun/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: polyrun
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
@@ -180,12 +180,14 @@ files:
|
|
|
180
180
|
- lib/polyrun/cli/helpers.rb
|
|
181
181
|
- lib/polyrun/cli/hooks_command.rb
|
|
182
182
|
- lib/polyrun/cli/init_command.rb
|
|
183
|
+
- lib/polyrun/cli/partition_diagnostics.rb
|
|
183
184
|
- lib/polyrun/cli/plan_command.rb
|
|
184
185
|
- lib/polyrun/cli/prepare_command.rb
|
|
185
186
|
- lib/polyrun/cli/prepare_recipe.rb
|
|
186
187
|
- lib/polyrun/cli/queue_command.rb
|
|
187
188
|
- lib/polyrun/cli/quick_command.rb
|
|
188
189
|
- lib/polyrun/cli/report_commands.rb
|
|
190
|
+
- lib/polyrun/cli/run_queue_command.rb
|
|
189
191
|
- lib/polyrun/cli/run_shards_command.rb
|
|
190
192
|
- lib/polyrun/cli/run_shards_parallel_children.rb
|
|
191
193
|
- lib/polyrun/cli/run_shards_parallel_wait.rb
|
|
@@ -194,6 +196,7 @@ files:
|
|
|
194
196
|
- lib/polyrun/cli/run_shards_planning.rb
|
|
195
197
|
- lib/polyrun/cli/run_shards_run.rb
|
|
196
198
|
- lib/polyrun/cli/run_shards_worker_interrupt.rb
|
|
199
|
+
- lib/polyrun/cli/spec_quality_commands.rb
|
|
197
200
|
- lib/polyrun/cli/start_bootstrap.rb
|
|
198
201
|
- lib/polyrun/cli/timing_command.rb
|
|
199
202
|
- lib/polyrun/config.rb
|
|
@@ -204,6 +207,7 @@ files:
|
|
|
204
207
|
- lib/polyrun/coverage/collector.rb
|
|
205
208
|
- lib/polyrun/coverage/collector_finish.rb
|
|
206
209
|
- lib/polyrun/coverage/collector_fragment_meta.rb
|
|
210
|
+
- lib/polyrun/coverage/example_diff.rb
|
|
207
211
|
- lib/polyrun/coverage/filter.rb
|
|
208
212
|
- lib/polyrun/coverage/formatter.rb
|
|
209
213
|
- lib/polyrun/coverage/merge.rb
|
|
@@ -252,11 +256,14 @@ files:
|
|
|
252
256
|
- lib/polyrun/partition/plan.rb
|
|
253
257
|
- lib/polyrun/partition/plan_lpt.rb
|
|
254
258
|
- lib/polyrun/partition/plan_sharding.rb
|
|
259
|
+
- lib/polyrun/partition/reports.rb
|
|
255
260
|
- lib/polyrun/partition/stable_shuffle.rb
|
|
261
|
+
- lib/polyrun/partition/timing_diagnostics.rb
|
|
256
262
|
- lib/polyrun/partition/timing_keys.rb
|
|
257
263
|
- lib/polyrun/prepare/artifacts.rb
|
|
258
264
|
- lib/polyrun/prepare/assets.rb
|
|
259
265
|
- lib/polyrun/process_stdio.rb
|
|
266
|
+
- lib/polyrun/queue/duration.rb
|
|
260
267
|
- lib/polyrun/queue/file_store.rb
|
|
261
268
|
- lib/polyrun/queue/file_store_pending.rb
|
|
262
269
|
- lib/polyrun/quick.rb
|
|
@@ -274,13 +281,27 @@ files:
|
|
|
274
281
|
- lib/polyrun/reporting/rspec_failure_fragment_formatter.rb
|
|
275
282
|
- lib/polyrun/reporting/rspec_junit.rb
|
|
276
283
|
- lib/polyrun/rspec.rb
|
|
284
|
+
- lib/polyrun/spec_quality.rb
|
|
285
|
+
- lib/polyrun/spec_quality/config.rb
|
|
286
|
+
- lib/polyrun/spec_quality/fragment.rb
|
|
287
|
+
- lib/polyrun/spec_quality/merge.rb
|
|
288
|
+
- lib/polyrun/spec_quality/minitest_hook.rb
|
|
289
|
+
- lib/polyrun/spec_quality/plan_loader.rb
|
|
290
|
+
- lib/polyrun/spec_quality/profile.rb
|
|
291
|
+
- lib/polyrun/spec_quality/report.rb
|
|
292
|
+
- lib/polyrun/spec_quality/rspec_hook.rb
|
|
293
|
+
- lib/polyrun/spec_quality/sql_counter.rb
|
|
277
294
|
- lib/polyrun/templates/POLYRUN.md
|
|
278
295
|
- lib/polyrun/templates/ci_matrix.polyrun.yml
|
|
279
296
|
- lib/polyrun/templates/minimal_gem.polyrun.yml
|
|
297
|
+
- lib/polyrun/templates/polyrun_hooks_spec_quality.rb
|
|
298
|
+
- lib/polyrun/templates/polyrun_spec_quality.yml
|
|
280
299
|
- lib/polyrun/templates/rails_prepare.polyrun.yml
|
|
281
300
|
- lib/polyrun/timing/merge.rb
|
|
282
301
|
- lib/polyrun/timing/rspec_example_formatter.rb
|
|
302
|
+
- lib/polyrun/timing/stats.rb
|
|
283
303
|
- lib/polyrun/timing/summary.rb
|
|
304
|
+
- lib/polyrun/timing/variance_report.rb
|
|
284
305
|
- lib/polyrun/version.rb
|
|
285
306
|
- lib/polyrun/worker_ping.rb
|
|
286
307
|
- polyrun.gemspec
|