mirror of
https://github.com/radareorg/r2sleigh.git
synced 2026-11-07 06:36:00 -10:00
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01456qmqCGpCWJkrg6JUZNNM
62 lines
2.5 KiB
Python
Executable File
62 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Fails a change to a vendored Sleigh specification that brings no lift evidence (ROADMAP D35, D28).
|
|
|
|
A pull request that changes a `.sinc`, `.slaspec` or `.pspec` under `vendor/sleigh-config`
|
|
must also add or change a lift test: a CPU oracle's `cases.txt` or `expected.txt`, a Rust test
|
|
source directly under `crates/r2sleigh-lift/tests/`, or the lift's own test module
|
|
(`crates/r2sleigh-lift/src/**/tests.rs`). A deleted file is no evidence.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from collections.abc import Collection
|
|
|
|
SPECIFICATION = re.compile(r"^vendor/sleigh-config/.*\.(sinc|slaspec|pspec)$")
|
|
EVIDENCE = re.compile(
|
|
r"^crates/r2sleigh-lift/(tests/[^/]+\.rs|tests/[^/]+_oracle/(cases|expected)\.txt|src/(.+/)?tests\.rs)$"
|
|
)
|
|
|
|
|
|
def unevidenced(paths: list[str], deleted: Collection[str] = ()) -> list[str]:
|
|
"""The specification files changed without any lift test, other than a deleted one, beside them."""
|
|
specifications = sorted(path for path in paths if SPECIFICATION.match(path))
|
|
if any(EVIDENCE.match(path) and path not in deleted for path in paths):
|
|
return []
|
|
return specifications
|
|
|
|
|
|
def changed(base: str, head: str = "HEAD", only: str = "") -> list[str]:
|
|
"""Every path the change touches since it left `base` (of the `--diff-filter` kinds `only` names)."""
|
|
out = subprocess.run(
|
|
["git", "diff", "--name-only", f"--diff-filter={only}", f"{base}...{head}"],
|
|
check=True,
|
|
capture_output=True,
|
|
text=True,
|
|
).stdout
|
|
return [line for line in out.splitlines() if line]
|
|
|
|
|
|
def main(argv: list[str] | None = None) -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--base", required=True, help="the commit the change is graded against")
|
|
parser.add_argument("--head", default="HEAD")
|
|
args = parser.parse_args(argv)
|
|
missing = unevidenced(changed(args.base, args.head), changed(args.base, args.head, "D"))
|
|
if not missing:
|
|
print("spec evidence: no vendored specification changed without a lift test")
|
|
return 0
|
|
print("A vendored Sleigh specification changed with no lift evidence (ROADMAP D35, D28):")
|
|
for path in missing:
|
|
print(f" {path}")
|
|
print("Add or change an oracle case or an r2il::eval test under crates/r2sleigh-lift/tests/")
|
|
print("or in the lift's test module (crates/r2sleigh-lift/src/**/tests.rs).")
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|