Own canonical consumer validation, selective workflow generation, Maven caching and RC completion in the shared orb. Centralize native workers and preserve acceptance/publication contracts with packed-output, behavioral and estate-audit tests. Co-Authored-By: OpenAI Codex <noreply@openai.com> Signed-off-by: James Maes <james@kof22.com>
83 lines
4.9 KiB
Python
83 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Protect native Next coverage while moving worker ownership into the orb."""
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
|
|
import yaml
|
|
|
|
sys.dont_write_bytecode = True
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
spec = importlib.util.spec_from_file_location("next_bridge", ROOT / "src/scripts/generate_next_workflow.py")
|
|
bridge = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(bridge)
|
|
|
|
|
|
class NextNativeTests(unittest.TestCase):
|
|
def test_circle_keeps_tag_validation_and_removes_branch_checks(self):
|
|
before = yaml.safe_load((ROOT / "tests/fixtures/next-circle.yml").read_text(encoding="utf-8"))
|
|
after = json.loads((ROOT / "src/scripts/templates/frontend-next.json").read_text(encoding="utf-8"))
|
|
self.assertEqual(set(after["workflows"]), {"publish_release"})
|
|
expected_steps = before["jobs"]["publish_dashboard_jar"]["steps"][1:]
|
|
self.assertEqual(after["jobs"]["publish_dashboard_jar"]["steps"], expected_steps)
|
|
self.assertNotIn("commands", after)
|
|
original_jobs = before["workflows"]["publish_release"]["jobs"]
|
|
jobs = after["workflows"]["publish_release"]["jobs"]
|
|
self.assertEqual(jobs[1], original_jobs[1])
|
|
self.assertEqual(jobs[0]["qqq-orb/node_app_build"]["filters"]["tags"],
|
|
original_jobs[0]["qqq-orb/node_app_build"]["filters"]["tags"])
|
|
for job in jobs:
|
|
self.assertEqual(next(iter(job.values()))["filters"]["branches"], {"ignore": "/.*/"})
|
|
spec = importlib.util.spec_from_file_location("standard", ROOT / "src/scripts/validate_standard.py")
|
|
standard = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(standard)
|
|
caller = standard.canonical_caller("frontend-next", "0.7.0")
|
|
options = caller["workflows"]["setup"]["jobs"][0]["qqq-orb/generate_pipeline"]
|
|
self.assertEqual(options["filters"]["branches"], {"ignore": "/.*/"})
|
|
|
|
def test_workers_keep_every_existing_job_and_step(self):
|
|
for source, worker in (("ci.yml", "next-ci.yml"), ("acceptance.yml", "next-acceptance.yml"),
|
|
("dashboard-image.yml", "next-dashboard-image.yml")):
|
|
before = yaml.safe_load((ROOT / "tests/fixtures" / ("next-" + source)).read_text(encoding="utf-8"))
|
|
after = yaml.safe_load((ROOT / ".github/workflows" / worker).read_text(encoding="utf-8"))
|
|
self.assertEqual(before["jobs"], after["jobs"], worker)
|
|
self.assertEqual(before.get("env"), after.get("env"), worker)
|
|
self.assertEqual(before.get("permissions"), after.get("permissions"), worker)
|
|
self.assertIn("workflow_call", after[True]) # PyYAML's YAML1.1 interpretation of 'on'.
|
|
self.assertNotIn("push", after[True])
|
|
self.assertNotIn("pull_request", after[True])
|
|
|
|
def test_acceptance_selector_retains_18_full_and_4_pr_cells(self):
|
|
path = (ROOT / "tests/fixtures/next-acceptance-select.mjs").as_uri()
|
|
code = f"import {{planAcceptance}} from {json.dumps(path)}; console.log(JSON.stringify([planAcceptance({{eventName:'push'}}),planAcceptance({{eventName:'pull_request',paths:['src/components/navigation.tsx']}}),planAcceptance({{eventName:'pull_request',labels:['full-acceptance']}})]))"
|
|
full, pr, labelled = json.loads(subprocess.check_output(["node", "--input-type=module", "-e", code], text=True))
|
|
self.assertEqual(len(full["matrix"]["include"]), 18)
|
|
self.assertEqual(len(pr["matrix"]["include"]), 4)
|
|
self.assertEqual(labelled, full)
|
|
self.assertEqual({x["project"] for x in full["matrix"]["include"]}, {"chromium", "firefox", "webkit", "mobile", "tablet"})
|
|
self.assertEqual({x["project"] for x in pr["matrix"]["include"]}, {"chromium", "mobile"})
|
|
|
|
def test_bridge_pins_workers_and_limits_label_reruns(self):
|
|
ref = "a" * 40
|
|
caller = bridge.canonical_next(ref)
|
|
self.assertEqual(set(caller["jobs"]), {"ci", "acceptance", "dashboard-image"})
|
|
for job in caller["jobs"].values():
|
|
self.assertTrue(job["uses"].startswith("QRun-IO/qqq-orb/.github/workflows/next-"))
|
|
self.assertTrue(job["uses"].endswith("@" + ref))
|
|
self.assertIn("github.event.label.name == 'full-acceptance'", caller["jobs"]["acceptance"]["if"])
|
|
for name in ("ci", "dashboard-image"):
|
|
self.assertIn("!contains", caller["jobs"][name]["if"])
|
|
self.assertNotIn("full-acceptance", caller["jobs"][name]["if"])
|
|
self.assertEqual(caller["jobs"]["dashboard-image"]["permissions"], {"contents": "read", "packages": "write"})
|
|
self.assertEqual(yaml.safe_load(yaml.safe_dump(caller)), caller)
|
|
for invalid in ("main", "v1.0.0", "", "a" * 39, "not-a-ref"):
|
|
with self.assertRaises(ValueError):
|
|
bridge.canonical_next(invalid)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|