mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 21:43:23 -05:00
fix: redeploy the site on any script it imports
This commit is contained in:
1 parent
240a30f1d7
commit
d3e02c8c5e
2 files changed
+129
-5
No files matched your search
@@ -8,11 +8,47 @@ on:
|
||||
- "emulators/**"
|
||||
- "provenance/**"
|
||||
- "wiki/**"
|
||||
- "scripts/generate_site.py"
|
||||
- "scripts/generate_readme.py"
|
||||
- "scripts/validate_site.py"
|
||||
- "scripts/verify.py"
|
||||
# Every script the build runs or imports (tests/test_workflow_paths.py).
|
||||
- "scripts/artifacts.py"
|
||||
- "scripts/auto_fetch.py"
|
||||
- "scripts/common.py"
|
||||
- "scripts/cross_reference.py"
|
||||
- "scripts/crypto_verify.py"
|
||||
- "scripts/deterministic_zip.py"
|
||||
- "scripts/dumpcatalog.py"
|
||||
- "scripts/generate_pack.py"
|
||||
- "scripts/generate_readme.py"
|
||||
- "scripts/generate_site.py"
|
||||
- "scripts/hashing.py"
|
||||
- "scripts/largefiles.py"
|
||||
- "scripts/list_platforms.py"
|
||||
- "scripts/nativemode.py"
|
||||
- "scripts/packextras.py"
|
||||
- "scripts/packpaths.py"
|
||||
- "scripts/packreadme.py"
|
||||
- "scripts/packresolve.py"
|
||||
- "scripts/packverify.py"
|
||||
- "scripts/profile_sync.py"
|
||||
- "scripts/provenance_report.py"
|
||||
- "scripts/refresh_data_dirs.py"
|
||||
- "scripts/region.py"
|
||||
- "scripts/release_record.py"
|
||||
- "scripts/restore_large_files.py"
|
||||
- "scripts/safeparse.py"
|
||||
- "scripts/sect233r1.py"
|
||||
- "scripts/siterender.py"
|
||||
- "scripts/sitesources.py"
|
||||
- "scripts/sitewrite.py"
|
||||
- "scripts/slot.py"
|
||||
- "scripts/slots.py"
|
||||
- "scripts/split_pack.py"
|
||||
- "scripts/truth.py"
|
||||
- "scripts/upstream.py"
|
||||
- "scripts/validate_schemas.py"
|
||||
- "scripts/validate_site.py"
|
||||
- "scripts/validation.py"
|
||||
- "scripts/verify.py"
|
||||
- "scripts/ziptools.py"
|
||||
- "schemas/**"
|
||||
- "tests/**"
|
||||
- "docs_assets/**"
|
||||
@@ -20,7 +56,6 @@ on:
|
||||
- "install.py"
|
||||
- "database.json"
|
||||
- "release.json"
|
||||
- "scripts/release_record.py"
|
||||
- "mkdocs.yml"
|
||||
- ".github/workflows/deploy-site.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
"""The site redeploys whenever a script it runs changes.
|
||||
|
||||
Deploy Site listed five scripts by hand while the build imports forty:
|
||||
a change to siterender.py, which writes every page, published nothing
|
||||
until some unrelated file moved.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import fnmatch
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
SCRIPTS = REPO_ROOT / "scripts"
|
||||
|
||||
|
||||
def _module_file(name: str) -> Path | None:
|
||||
name = name.removeprefix("scripts.")
|
||||
for candidate in (
|
||||
SCRIPTS / (name.replace(".", "/") + ".py"),
|
||||
SCRIPTS / name.replace(".", "/") / "__init__.py",
|
||||
):
|
||||
if candidate.exists():
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def _imports(path: Path) -> set[Path]:
|
||||
found: set[Path] = set()
|
||||
for node in ast.walk(ast.parse(path.read_text(encoding="utf-8"))):
|
||||
if isinstance(node, ast.Import):
|
||||
names = [alias.name for alias in node.names]
|
||||
elif isinstance(node, ast.ImportFrom) and node.level == 0 and node.module:
|
||||
names = [node.module, *(f"{node.module}.{a.name}" for a in node.names)]
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
base = path.parent / (node.module or "").replace(".", "/")
|
||||
candidates = [base / f"{a.name}.py" for a in node.names]
|
||||
candidates += [base.with_suffix(".py"), base / "__init__.py"]
|
||||
found.update(c for c in candidates if c.is_file())
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
found.update(f for f in map(_module_file, names) if f)
|
||||
return found
|
||||
|
||||
|
||||
def closure(entry_points: list[str]) -> set[str]:
|
||||
seen: set[Path] = set()
|
||||
stack = [SCRIPTS / name for name in entry_points]
|
||||
while stack:
|
||||
path = stack.pop()
|
||||
if path not in seen:
|
||||
seen.add(path)
|
||||
stack.extend(_imports(path))
|
||||
return {str(p.relative_to(REPO_ROOT)) for p in seen}
|
||||
|
||||
|
||||
class DeploySiteTriggers(unittest.TestCase):
|
||||
def test_every_script_the_build_imports_triggers_it(self):
|
||||
workflow = yaml.safe_load(
|
||||
(REPO_ROOT / ".github/workflows/deploy-site.yml").read_text(encoding="utf-8")
|
||||
)
|
||||
on = workflow.get("on", workflow.get(True))
|
||||
patterns = on["push"]["paths"]
|
||||
run = "\n".join(
|
||||
step.get("run", "") for job in workflow["jobs"].values() for step in job["steps"]
|
||||
)
|
||||
entry_points = sorted(
|
||||
{
|
||||
word.removeprefix("scripts/")
|
||||
for word in run.split()
|
||||
if word.startswith("scripts/") and word.endswith(".py")
|
||||
}
|
||||
)
|
||||
self.assertIn("generate_site.py", entry_points)
|
||||
uncovered = sorted(
|
||||
path
|
||||
for path in closure(entry_points)
|
||||
if not any(fnmatch.fnmatch(path, p.replace("**", "*")) for p in patterns)
|
||||
)
|
||||
self.assertEqual(uncovered, [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user