[CI] Enforce modern stage=/runner_config= form for dispatchable test suites (#28108)
This commit is contained in:
@@ -1,7 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Pre-commit hook: validate that all Python test files under test/registered/
|
||||
contain a CI registry call (register_cuda_ci, register_amd_ci, etc.).
|
||||
Pre-commit hook: validate CI registry calls under test/registered/.
|
||||
|
||||
1. Every test file must contain a CI registry call (register_cuda_ci,
|
||||
register_amd_ci, etc.).
|
||||
2. A CUDA test must not register a `{stage}-test-{runner_config}`-shaped suite
|
||||
via the legacy single-string `suite=`: that form is not dispatchable via
|
||||
/rerun-test. Use the modern `stage=`/`runner_config=` form instead -- it
|
||||
resolves to the identical suite (CIRegistry.effective_suite is
|
||||
f"{stage}-test-{runner_config}"), so same stage and same runner, just
|
||||
/rerun-test-able. Legacy `suite=` stays valid for nightly/stress/weekly +
|
||||
AMD/CPU/NPU suites whose names don't follow that shape.
|
||||
|
||||
Reuses ut_parse_one_file() from ci_register.py (AST-based parsing)
|
||||
to match the same logic used by run_suite.py's collect_tests().
|
||||
@@ -10,8 +19,14 @@ to match the same logic used by run_suite.py's collect_tests().
|
||||
import glob
|
||||
import importlib.util
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Suite names of the form `{stage}-test-{runner_config}` are exactly what the
|
||||
# modern stage=/runner_config= form produces, so a legacy suite= carrying this
|
||||
# shape is always expressible (and should be expressed) the modern way.
|
||||
_MODERN_SHAPE = re.compile(r"^(.+)-test-(.+)$")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
# Import ci_register directly to avoid pulling in all of sglang
|
||||
@@ -21,6 +36,7 @@ def main() -> int:
|
||||
)
|
||||
ci_register = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(ci_register)
|
||||
cuda = ci_register.HWBackend.CUDA
|
||||
|
||||
# Same filter as run_suite.py: skip conftest.py, __init__.py, and utils.py
|
||||
files = sorted(
|
||||
@@ -31,25 +47,55 @@ def main() -> int:
|
||||
if not files:
|
||||
return 0
|
||||
|
||||
errors = []
|
||||
missing = []
|
||||
legacy_shape = [] # (file, suite, stage, runner_config)
|
||||
for f in files:
|
||||
try:
|
||||
registries, _has_main_entry = ci_register.ut_parse_one_file(f)
|
||||
if len(registries) == 0:
|
||||
errors.append(f)
|
||||
except Exception:
|
||||
# Skip files that can't be parsed (syntax errors, etc.)
|
||||
pass
|
||||
continue
|
||||
if len(registries) == 0:
|
||||
missing.append(f)
|
||||
continue
|
||||
for r in registries:
|
||||
# Pure legacy form on a CUDA registry: suite set, stage/runner unset.
|
||||
if not (
|
||||
r.backend == cuda
|
||||
and r.suite is not None
|
||||
and r.stage is None
|
||||
and r.runner_config is None
|
||||
):
|
||||
continue
|
||||
m = _MODERN_SHAPE.match(r.suite)
|
||||
if m:
|
||||
legacy_shape.append((f, r.suite, m.group(1), m.group(2)))
|
||||
|
||||
if errors:
|
||||
exit_code = 0
|
||||
if missing:
|
||||
print("ERROR: Files in test/registered/ missing CI registry call:")
|
||||
print(" Move manual-only tests to test/manual/.\n")
|
||||
for f in errors:
|
||||
for f in missing:
|
||||
print(f" {f}")
|
||||
print()
|
||||
return 1
|
||||
exit_code = 1
|
||||
if legacy_shape:
|
||||
print(
|
||||
"ERROR: CUDA test(s) register a `{stage}-test-{runner_config}`-shaped "
|
||||
'suite via the legacy `suite="..."` form, which is not dispatchable '
|
||||
"via /rerun-test. Switch to the modern `stage=`/`runner_config=` form "
|
||||
"(same stage, same runner):\n"
|
||||
)
|
||||
for f, suite, stage, runner_config in legacy_shape:
|
||||
print(
|
||||
f" {f}\n"
|
||||
f' suite="{suite}"'
|
||||
f' -> stage="{stage}", runner_config="{runner_config}"'
|
||||
)
|
||||
print()
|
||||
exit_code = 1
|
||||
|
||||
return 0
|
||||
return exit_code
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user