Files
xinjian0101-continuity-dire…/scripts/validate_release.py
xinjian0101 2f3428b6dd feat: release Continuity Director v0.8.20 after 20 iterations
Merge 20 sequential plugin iterations covering lifecycle validation, frontend smoke tests, six reliability nodes, bilingual help pages, installable ZIP packaging, and expanded CI.
2026-06-19 15:32:07 +08:00

28 lines
2.0 KiB
Python

from __future__ import annotations
import ast
import importlib.util
import json
import sys
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
REQUIRED=["__init__.py","nodes.py","extended_nodes.py","environment_nodes.py","continuity_core.py","production_core.py","runtime_core.py","collaboration_core.py","validation_core.py","js/continuity_director.js","js/reliability_panel.js","js/continuity_director.css","pyproject.toml","README.md","LICENSE"]
def fail(message): raise SystemExit(f"release validation failed: {message}")
for path in REQUIRED:
if not (ROOT/path).is_file(): fail(f"missing {path}")
for path in ROOT.glob("*.py"): ast.parse(path.read_text(encoding="utf-8"),filename=str(path))
if any((ROOT/".bootstrap").glob("*")) if (ROOT/".bootstrap").exists() else False: fail("legacy bootstrap artifacts remain")
spec=importlib.util.spec_from_file_location("continuity_director_release",ROOT/"__init__.py",submodule_search_locations=[str(ROOT)])
if spec is None or spec.loader is None: fail("unable to import package")
module=importlib.util.module_from_spec(spec); sys.modules[spec.name]=module; spec.loader.exec_module(module)
if len(module.NODE_CLASS_MAPPINGS)!=20: fail(f"expected 20 registered nodes, found {len(module.NODE_CLASS_MAPPINGS)}")
if set(module.NODE_CLASS_MAPPINGS)!=set(module.NODE_DISPLAY_NAME_MAPPINGS): fail("display mappings do not match node mappings")
for node_name in module.NODE_CLASS_MAPPINGS:
if not (ROOT/"js"/"docs"/f"{node_name}.md").is_file(): fail(f"missing fallback docs for {node_name}")
storyboard=json.loads((ROOT/"examples/starter_storyboard.json").read_text(encoding="utf-8"))
if not isinstance(storyboard.get("shots"),list) or not storyboard["shots"]: fail("starter storyboard has no shots")
for file_name in ("continuity_director.js","reliability_panel.js"):
text=(ROOT/"js"/file_name).read_text(encoding="utf-8")
if "app.registerExtension" not in text: fail(f"{file_name} does not register an extension")
print("release validation passed: 20 nodes, two frontend panels, localized docs, and package metadata")