Class: Polyrun::Hooks
- Inherits:
-
Object
- Object
- Polyrun::Hooks
- Includes:
- WorkerShell
- Defined in:
- lib/polyrun/hooks.rb,
lib/polyrun/hooks/dsl.rb,
lib/polyrun/hooks/worker_shell.rb,
lib/polyrun/hooks/worker_runner.rb
Overview
Shell and Ruby DSL hooks around parallel orchestration, named like RSpec lifecycle callbacks: before_suite / after_suite (+before(:suite)+ / after(:suite)), before_shard / after_shard (parent process, per partition index), before_worker / after_worker (inside each worker process, around the test command).
Configure under hooks: in polyrun.yml: shell strings, and/or ruby: path to a Ruby DSL file. Run manually: polyrun hook run <phase> (see CLI).
Orchestration respects POLYRUN_HOOKS_DISABLE=1 (run_phase_if_enabled); polyrun hook run always runs #run_phase.
Defined Under Namespace
Modules: Dsl, WorkerRunner, WorkerShell
Constant Summary collapse
- PHASES =
%i[ before_suite after_suite before_shard after_shard before_worker after_worker ].freeze
Instance Attribute Summary collapse
-
#ruby_file ⇒ Object
readonly
Returns the value of attribute ruby_file.
Class Method Summary collapse
- .disabled? ⇒ Boolean
- .from_config(cfg) ⇒ Object
-
.parse_phase(str) ⇒ Object
Maps CLI or YAML-style names (
before_suite, “before(:suite)”) to a phase symbol ornil. -
.suite_per_matrix_job? ⇒ Boolean
When
POLYRUN_SHARD_TOTALis greater than 1 (ci-shard-runmatrix), suite hooks are skipped by default; set POLYRUN_HOOKS_SUITE_PER_MATRIX_JOB=1 to runbefore_suite/after_suiteon every matrix job (legacy).
Instance Method Summary collapse
- #commands_for(phase) ⇒ Array<String>
- #empty? ⇒ Boolean
-
#initialize(raw) ⇒ Hooks
constructor
A new instance of Hooks.
-
#merge_worker_ruby_env(env) ⇒ Object
Merges
POLYRUN_HOOKS_RUBY_FILEwhen a DSL file is configured (for worker ruby -e). -
#run_phase(phase, env) ⇒ Integer
Runs Ruby DSL blocks (if any), then shell commands for
phase. -
#run_phase_if_enabled(phase, env) ⇒ Object
Like #run_phase, but no-ops when Hooks.disabled? (+POLYRUN_HOOKS_DISABLE=1+).
- #worker_hooks? ⇒ Boolean
Methods included from WorkerShell
Constructor Details
#initialize(raw) ⇒ Hooks
Returns a new instance of Hooks.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/polyrun/hooks.rb', line 52 def initialize(raw) @ruby_file = extract_ruby_file(raw) h = {} raw.each do |k, v| next if %w[ruby ruby_file].include?(k.to_s) ck = canonical_key(k) next if ck.nil? h[ck] = v end @raw = h.freeze @ruby_registry_loaded = false @ruby_registry = nil end |
Instance Attribute Details
#ruby_file ⇒ Object (readonly)
Returns the value of attribute ruby_file.
27 28 29 |
# File 'lib/polyrun/hooks.rb', line 27 def ruby_file @ruby_file end |
Class Method Details
.disabled? ⇒ Boolean
29 30 31 32 |
# File 'lib/polyrun/hooks.rb', line 29 def self.disabled? v = ENV["POLYRUN_HOOKS_DISABLE"].to_s.downcase %w[1 true yes].include?(v) end |
.from_config(cfg) ⇒ Object
41 42 43 44 |
# File 'lib/polyrun/hooks.rb', line 41 def self.from_config(cfg) raw = cfg.respond_to?(:hooks) ? cfg.hooks : {} new(raw.is_a?(Hash) ? raw : {}) end |
.parse_phase(str) ⇒ Object
Maps CLI or YAML-style names (before_suite, “before(:suite)”) to a phase symbol or nil.
47 48 49 |
# File 'lib/polyrun/hooks.rb', line 47 def self.parse_phase(str) new({}).send(:canonical_key, str) end |
.suite_per_matrix_job? ⇒ Boolean
When POLYRUN_SHARD_TOTAL is greater than 1 (ci-shard-run matrix), suite hooks are skipped by default; set POLYRUN_HOOKS_SUITE_PER_MATRIX_JOB=1 to run before_suite / after_suite on every matrix job (legacy).
36 37 38 39 |
# File 'lib/polyrun/hooks.rb', line 36 def self.suite_per_matrix_job? v = ENV["POLYRUN_HOOKS_SUITE_PER_MATRIX_JOB"].to_s.downcase %w[1 true yes].include?(v) end |
Instance Method Details
#commands_for(phase) ⇒ Array<String>
96 97 98 99 100 101 102 103 104 105 |
# File 'lib/polyrun/hooks.rb', line 96 def commands_for(phase) v = @raw[phase.to_sym] case v when nil then [] when Array then v.map(&:to_s).map(&:strip).reject(&:empty?) else s = v.to_s.strip s.empty? ? [] : [s] end end |
#empty? ⇒ Boolean
68 69 70 71 72 73 74 75 76 77 |
# File 'lib/polyrun/hooks.rb', line 68 def empty? no_shell = PHASES.all? { |p| commands_for(p).empty? } return false unless no_shell return true if @ruby_file.nil? || @ruby_file.to_s.strip.empty? return true unless File.file?(File.(@ruby_file, Dir.pwd)) reg = ruby_registry reg.nil? || reg.empty? end |
#merge_worker_ruby_env(env) ⇒ Object
Merges POLYRUN_HOOKS_RUBY_FILE when a DSL file is configured (for worker ruby -e).
86 87 88 89 90 91 92 |
# File 'lib/polyrun/hooks.rb', line 86 def merge_worker_ruby_env(env) return env unless @ruby_file abs = File.(@ruby_file, Dir.pwd) return env unless File.file?(abs) env.merge("POLYRUN_HOOKS_RUBY_FILE" => abs) end |
#run_phase(phase, env) ⇒ Integer
Runs Ruby DSL blocks (if any), then shell commands for phase.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/polyrun/hooks.rb', line 109 def run_phase(phase, env) return 0 unless PHASES.include?(phase.to_sym) merged = stringify_env_for_hook(env).merge( "POLYRUN_HOOK_PHASE" => phase.to_s, "POLYRUN_HOOK" => "1" ) reg = ruby_registry if reg&.any?(phase) begin reg.run(phase, merged) rescue => e Polyrun::Log.warn "polyrun hooks: #{phase} ruby hook failed: #{e.class}: #{e.}" return 1 end end commands_for(phase).each do |cmd| ok = system(merged, "sh", "-c", cmd) return $?.exitstatus unless ok end 0 end |
#run_phase_if_enabled(phase, env) ⇒ Object
Like #run_phase, but no-ops when disabled? (+POLYRUN_HOOKS_DISABLE=1+). Used by run-shards / ci-shard orchestration.
135 136 137 138 139 |
# File 'lib/polyrun/hooks.rb', line 135 def run_phase_if_enabled(phase, env) return 0 if self.class.disabled? run_phase(phase, env) end |
#worker_hooks? ⇒ Boolean
79 80 81 82 83 |
# File 'lib/polyrun/hooks.rb', line 79 def worker_hooks? return true if commands_for(:before_worker).any? || commands_for(:after_worker).any? !!ruby_registry&.worker_hooks? end |