mirror of
https://github.com/magnus919/agent-skills.git
synced 2026-09-11 19:47:12 +03:00
When unittest discover processes skills/binary-analysis/tests/ before tests/, the integration package gets cached in sys.modules from the first discover call. Later discover calls reuse the cached package which doesn't contain the expected test modules, causing spurious ModuleNotFoundError failures. Fix: snapshot and restore sys.modules between discover iterations. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
108 lines
3.3 KiB
Python
108 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate runnable repository artifacts selected from the Git index."""
|
|
|
|
import argparse
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def tracked_files() -> list[Path]:
|
|
result = subprocess.run(
|
|
["git", "ls-files", "-z"],
|
|
cwd=ROOT,
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
return [ROOT / name for name in result.stdout.decode().split("\0") if name]
|
|
|
|
|
|
def is_shell_script(path: Path) -> bool:
|
|
if path.suffix in {".sh", ".bash"}:
|
|
return True
|
|
try:
|
|
first_line = path.open("rb").readline().decode("utf-8", "replace")
|
|
except OSError:
|
|
return False
|
|
return first_line.startswith("#!") and any(
|
|
shell in first_line for shell in ("/sh", "/bash", "env sh", "env bash")
|
|
)
|
|
|
|
|
|
def test_directories(files: list[Path]) -> list[Path]:
|
|
directories = set()
|
|
for path in files:
|
|
for parent in path.parents:
|
|
if parent.name == "tests":
|
|
directories.add(parent)
|
|
break
|
|
if parent == ROOT:
|
|
break
|
|
return sorted(directories)
|
|
|
|
|
|
def run_checks(files: list[Path]) -> list[str]:
|
|
errors = []
|
|
for path in files:
|
|
relative = path.relative_to(ROOT)
|
|
if path.suffix == ".py":
|
|
try:
|
|
compile(path.read_bytes(), str(relative), "exec")
|
|
except (OSError, SyntaxError) as error:
|
|
errors.append(f"python {relative}: {error}")
|
|
elif path.suffix == ".json":
|
|
try:
|
|
json.loads(path.read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError) as error:
|
|
errors.append(f"json {relative}: {error}")
|
|
if is_shell_script(path):
|
|
result = subprocess.run(
|
|
["bash", "-n", str(path)], cwd=ROOT, text=True, capture_output=True
|
|
)
|
|
if result.returncode:
|
|
errors.append(f"bash -n {relative}: {result.stderr.strip()}")
|
|
|
|
for directory in test_directories(files):
|
|
relative = directory.relative_to(ROOT)
|
|
before = set(sys.modules)
|
|
result = unittest.TextTestRunner(verbosity=0).run(
|
|
unittest.defaultTestLoader.discover(str(directory), top_level_dir=str(directory))
|
|
)
|
|
for mod in list(sys.modules):
|
|
if mod not in before:
|
|
del sys.modules[mod]
|
|
if not result.wasSuccessful():
|
|
errors.append(
|
|
f"unittest discover {relative}: "
|
|
f"{len(result.failures)} failures, {len(result.errors)} errors"
|
|
)
|
|
return errors
|
|
|
|
|
|
def self_check() -> None:
|
|
files = [ROOT / "example/tests/test_example.py", ROOT / "elsewhere/file.py"]
|
|
assert test_directories(files) == [ROOT / "example/tests"]
|
|
assert is_shell_script(ROOT / "scripts/check-artifacts.py") is False
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--self-check", action="store_true")
|
|
args = parser.parse_args()
|
|
if args.self_check:
|
|
self_check()
|
|
return 0
|
|
|
|
errors = run_checks(tracked_files())
|
|
for error in errors:
|
|
print(error, file=sys.stderr)
|
|
return 1 if errors else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|