Module: Testivai::Shard
- Defined in:
- lib/testivai/shard.rb
Overview
Shard participation for parallel and sharded runs.
Playwright can tell its reporter --shard=i/N; RSpec cannot. So the
mechanism is the environment, not a framework API, and every TestivAI
adapter honours the same two variables:
TESTIVAI_CAPTURE_ONLY=1 capture, do not compare
TESTIVAI_SHARD=3/8 this process is shard 3 of 8
That is what keeps a Ruby suite a first-class citizen of the same sharded CI flow as Playwright rather than a second-class one.
Constant Summary collapse
- PATTERN =
%r{\A\s*(\d+)\s*(?:/|of)\s*(\d+)\s*\z}i- MANIFEST =
"testivai-shard.json"
Class Method Summary collapse
- .capture_only?(env = ENV) ⇒ Boolean
-
.from_env(env = ENV) ⇒ Object
Parse TESTIVAI_SHARD; nil when unset or malformed.
- .parse(raw) ⇒ Object
-
.write_manifest(temp_dir, shard, complete: false) ⇒ Object
Write (or refresh) the manifest merge-captures reads.
Class Method Details
.capture_only?(env = ENV) ⇒ Boolean
41 42 43 44 45 46 47 |
# File 'lib/testivai/shard.rb', line 41 def capture_only?(env = ENV) raw = env["TESTIVAI_CAPTURE_ONLY"].to_s return !%w[0 false].include?(raw.downcase) unless raw.empty? s = from_env(env) !s.nil? && s[:total] > 1 end |
.from_env(env = ENV) ⇒ Object
Parse TESTIVAI_SHARD; nil when unset or malformed.
26 27 28 |
# File 'lib/testivai/shard.rb', line 26 def from_env(env = ENV) parse(env["TESTIVAI_SHARD"]) end |
.parse(raw) ⇒ Object
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/testivai/shard.rb', line 30 def parse(raw) m = PATTERN.match(raw.to_s) return nil unless m current = m[1].to_i total = m[2].to_i return nil if total < 1 || current < 1 || current > total { current: current, total: total } end |
.write_manifest(temp_dir, shard, complete: false) ⇒ Object
Write (or refresh) the manifest merge-captures reads.
RSpec gives the gem no end-of-run hook, so this is refreshed on every
capture and complete stays false — it records that the shard
participated, not that it finished.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/testivai/shard.rb', line 54 def write_manifest(temp_dir, shard, complete: false) dir = Pathname.new(temp_dir) dir.mkpath captures = dir.children.select(&:directory?).map { |p| p.basename.to_s }.sort dir.join(MANIFEST).write( JSON.pretty_generate( "shard" => { "current" => shard[:current], "total" => shard[:total] }, "captures" => captures, "complete" => complete, "timestamp" => Time.now.utc.iso8601 ) ) rescue StandardError # rubocop:disable Lint/SuppressedException # Never fail a capture over a manifest. end |