57fcc880c3
ISSUES CLOSED: #176
164 lines
5.0 KiB
Python
164 lines
5.0 KiB
Python
"""Robot Framework helper for validation apply gate.
|
|
|
|
Provides a CLI-style interface for Robot to invoke validation
|
|
attachment creation, runner execution, and gate evaluation.
|
|
Exit code 0 = success, 1 = failure.
|
|
|
|
Usage::
|
|
|
|
python robot/helper_validation_apply.py run-gate \\
|
|
<plan_id> <val_name> <res_id> <mode> <ctx_key> <ctx_val>
|
|
python robot/helper_validation_apply.py summary \\
|
|
<plan_id> <n_req_pass> <n_req_fail>
|
|
python robot/helper_validation_apply.py check-block \\
|
|
<plan_id> <n_req_pass> <n_req_fail>
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Ensure the src directory is on the import path.
|
|
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
|
if _SRC not in sys.path:
|
|
sys.path.insert(0, _SRC)
|
|
|
|
from cleveragents.application.services.validation_apply import ( # noqa: E402
|
|
ApplyValidationGate,
|
|
ApplyValidationResult,
|
|
ApplyValidationSummary,
|
|
DefaultValidationRunner,
|
|
ValidationAttachment,
|
|
)
|
|
from cleveragents.domain.models.core.tool import ValidationMode # noqa: E402
|
|
|
|
|
|
def _cmd_run_gate(args: list[str]) -> int:
|
|
"""Run the validation gate with a single attachment."""
|
|
if len(args) < 6:
|
|
print(
|
|
"Usage: run-gate <plan_id> <val_name> <res_id> <mode> <ctx_key> <ctx_val>"
|
|
)
|
|
return 1
|
|
plan_id = args[0]
|
|
att = ValidationAttachment(
|
|
attachment_id="01ATT000000000000000000000",
|
|
validation_name=args[1],
|
|
resource_id=args[2],
|
|
mode=ValidationMode(args[3]),
|
|
)
|
|
ctx = {args[4]: args[5]}
|
|
runner = DefaultValidationRunner()
|
|
gate = ApplyValidationGate(runner=runner)
|
|
summary = gate.run(plan_id, [att], ctx)
|
|
blocked = gate.should_block_apply(summary)
|
|
status = "BLOCKED" if blocked else "ALLOWED"
|
|
print(f"val-gate-ok: {status}")
|
|
print(f" total={summary.total}")
|
|
print(f" required_passed={summary.required_passed}")
|
|
print(f" required_failed={summary.required_failed}")
|
|
return 0
|
|
|
|
|
|
def _cmd_summary(args: list[str]) -> int:
|
|
"""Build a summary and print metadata."""
|
|
if len(args) < 3:
|
|
print("Usage: summary <plan_id> <n_req_pass> <n_req_fail>")
|
|
return 1
|
|
plan_id = args[0]
|
|
n_pass, n_fail = int(args[1]), int(args[2])
|
|
results: list[ApplyValidationResult] = []
|
|
for i in range(n_pass):
|
|
results.append(
|
|
ApplyValidationResult(
|
|
attachment_id=f"01ATT{i:021d}",
|
|
validation_name=f"val-{i}",
|
|
resource_id=f"res-{i}",
|
|
mode=ValidationMode.REQUIRED,
|
|
passed=True,
|
|
message="ok",
|
|
)
|
|
)
|
|
for i in range(n_fail):
|
|
results.append(
|
|
ApplyValidationResult(
|
|
attachment_id=f"01ATT{n_pass + i:021d}",
|
|
validation_name=f"val-{n_pass + i}",
|
|
resource_id=f"res-{n_pass + i}",
|
|
mode=ValidationMode.REQUIRED,
|
|
passed=False,
|
|
message="failed",
|
|
)
|
|
)
|
|
summary = ApplyValidationSummary(plan_id=plan_id, results=results)
|
|
md = summary.to_plan_metadata()
|
|
print(f"val-summary-ok: {json.dumps(md, default=str)}")
|
|
return 0
|
|
|
|
|
|
def _cmd_check_block(args: list[str]) -> int:
|
|
"""Check if gate blocks apply."""
|
|
if len(args) < 3:
|
|
print("Usage: check-block <plan_id> <n_req_pass> <n_req_fail>")
|
|
return 1
|
|
plan_id = args[0]
|
|
n_pass, n_fail = int(args[1]), int(args[2])
|
|
results: list[ApplyValidationResult] = []
|
|
for i in range(n_pass):
|
|
results.append(
|
|
ApplyValidationResult(
|
|
attachment_id=f"01ATT{i:021d}",
|
|
validation_name=f"val-{i}",
|
|
resource_id=f"res-{i}",
|
|
mode=ValidationMode.REQUIRED,
|
|
passed=True,
|
|
message="ok",
|
|
)
|
|
)
|
|
for i in range(n_fail):
|
|
results.append(
|
|
ApplyValidationResult(
|
|
attachment_id=f"01ATT{n_pass + i:021d}",
|
|
validation_name=f"val-{n_pass + i}",
|
|
resource_id=f"res-{n_pass + i}",
|
|
mode=ValidationMode.REQUIRED,
|
|
passed=False,
|
|
message="failed",
|
|
)
|
|
)
|
|
summary = ApplyValidationSummary(plan_id=plan_id, results=results)
|
|
gate = ApplyValidationGate(runner=DefaultValidationRunner())
|
|
blocked = gate.should_block_apply(summary)
|
|
status = "BLOCKED" if blocked else "ALLOWED"
|
|
print(f"val-check-block-ok: {status}")
|
|
return 0
|
|
|
|
|
|
def main() -> int:
|
|
"""Entry point called by Robot Framework ``Run Process``."""
|
|
if len(sys.argv) < 2:
|
|
print("Usage: helper_validation_apply.py <run-gate|summary|check-block> ...")
|
|
return 1
|
|
|
|
command = sys.argv[1]
|
|
args = sys.argv[2:]
|
|
|
|
dispatch = {
|
|
"run-gate": _cmd_run_gate,
|
|
"summary": _cmd_summary,
|
|
"check-block": _cmd_check_block,
|
|
}
|
|
|
|
handler = dispatch.get(command)
|
|
if handler is None:
|
|
print(f"Unknown command: {command}")
|
|
return 1
|
|
|
|
return handler(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|