Module: Perfgate::Policy::Engine

Defined in:
lib/perfgate/policy/engine.rb

Overview

Turns a comparison-result document (or the absence of one) into the PASS/WARN/FAIL/INCOMPARABLE decision and CI exit code baseline exits with (spec section 17):

0 PASS, or WARN under a non-blocking policy
1 Performance FAIL
2 Configuration error       (raised directly by the CLI, not here)
3 Execution error           (raised directly by the CLI, not here)
4 Missing baseline under a strict policy
5 Incompatible baseline under a strict policy

config.policy controls how "soft" signals (an incompatible fingerprint, a new/removed workload) escalate into a hard FAIL -- every one of those keys defaults to "warn" (never blocking) and only escalates when explicitly set to "fail".

Constant Summary collapse

EXIT_CODES =
{ "pass" => 0, "warn" => 0, "fail" => 1, "missing_baseline" => 4, "incomparable" => 5 }.freeze
ESCALATING_WORKLOAD_DECISIONS =
{ "new_workload" => :new_workload, "removed_workload" => :removed_workload,
"incomparable" => :incompatible }.freeze

Class Method Summary collapse

Class Method Details

.evaluate(comparison_result:, config: Perfgate.configuration) ⇒ Object



27
28
29
30
# File 'lib/perfgate/policy/engine.rb', line 27

def evaluate(comparison_result:, config: Perfgate.configuration)
  status = status_for(comparison_result, config)
  { "status" => status, "exit_code" => EXIT_CODES.fetch(status) }
end

.evaluate_missing_baseline(config: Perfgate.configuration) ⇒ Object

A separate entry point for the CLI: there is no comparison result at all when no prior baseline run could be found to compare against (spec section 17's exit code 4).



35
36
37
38
# File 'lib/perfgate/policy/engine.rb', line 35

def evaluate_missing_baseline(config: Perfgate.configuration)
  status = config.policy[:missing_baseline] == "fail" ? "missing_baseline" : "warn"
  { "status" => status, "exit_code" => EXIT_CODES.fetch(status) }
end

.incompatible_status(config) ⇒ Object



49
50
51
# File 'lib/perfgate/policy/engine.rb', line 49

def incompatible_status(config)
  config.policy[:incompatible] == "fail" ? "incomparable" : "warn"
end

.metric_status(comparison_result, config) ⇒ Object



64
65
66
67
68
69
70
# File 'lib/perfgate/policy/engine.rb', line 64

def metric_status(comparison_result, config)
  case comparison_result["decision"]
  when "fail" then "fail"
  when "warn" then config.policy[:fail_on] == "warn" ? "fail" : "warn"
  else "pass"
  end
end

.status_for(comparison_result, config) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/perfgate/policy/engine.rb', line 40

def status_for(comparison_result, config)
  return incompatible_status(config) if comparison_result["decision"] == "incompatible"

  escalation = workload_escalation(comparison_result, config)
  return escalation if escalation

  metric_status(comparison_result, config)
end

.workload_escalation(comparison_result, config) ⇒ Object



53
54
55
56
57
58
59
60
61
62
# File 'lib/perfgate/policy/engine.rb', line 53

def workload_escalation(comparison_result, config)
  workloads = comparison_result.fetch("workloads", [])
  ESCALATING_WORKLOAD_DECISIONS.each do |decision, policy_key|
    next unless config.policy[policy_key] == "fail"
    next unless workloads.any? { |w| w["decision"] == decision }

    return "fail"
  end
  nil
end