fix: 将 ARM64 wheel 纳入发布校验和上传流程

补齐全部架构的运行证据、GitHub 发布说明和 PyPI 逐文件下载核验。已通过 161 项测试、代码和文档门禁、九个 wheel 的本地索引下载核验,以及 ARM 三个 ABI 的 40 帧 CPU 检查。
This commit is contained in:
ykcheungab
2026-10-15 21:39:31 +08:00
parent bb15b750fb
commit 9c951e9d3c
10 changed files with 496 additions and 47 deletions
+25 -19
View File
@@ -1,8 +1,8 @@
"""Local release gate: everything that must hold before publishing a wheel.
``release preflight`` answers one question with an exit code: is this checkout,
this version and these wheels safe to publish? It never publishes anything, and
by default it makes no network calls.
this version and these wheels safe to publish? It never publishes anything;
native verification environments may download dependencies from PyPI.
Steps, in order:
@@ -52,6 +52,7 @@ from wheel.layout import ( # noqa: E402
from release import report as report_mod # noqa: E402
from release import version as version_mod # noqa: E402
from release.runtime import verify_manylinux_wheel, wheel_target # noqa: E402
@dataclass
@@ -411,31 +412,29 @@ class Preflight:
return Step("wheel-inspection", not problems, detail, data={"count": len(self.wheels)})
def _platform_token(self) -> str:
return "win_amd64" if sys.platform == "win32" else "manylinux"
return "win_amd64" if sys.platform == "win32" else platform.machine().lower()
def _runtime_targets(self) -> list[tuple[str, Path, Path | None]]:
token = self._platform_token()
if self.options.all_wheel_pythons:
targets: list[tuple[str, Path, Path | None]] = []
for tag in ("cp310", "cp311", "cp312"):
match = next(
(w for w in self.wheels if f"-{tag}-" in w.name and token in w.name), None
)
if match is None:
raise RuntimeError(
f"no {tag} {token} wheel among {[w.name for w in self.wheels]}"
)
executable = version_mod.python_for_tag(tag)
if executable is None:
for wheel in self.wheels:
tag, target = wheel_target(wheel)
executable = None
if target == "win_amd64":
if sys.platform != "win32":
raise RuntimeError("Verify Windows wheels from a Windows host")
executable = version_mod.python_for_tag(tag)
if target == "win_amd64" and executable is None:
raise RuntimeError(
f"cannot resolve an interpreter for {tag}; create the conda env "
f"py{tag[2:]} or set CONDA_ENVS_ROOT"
)
targets.append((tag, match, executable))
targets.append((tag, wheel, executable))
return targets
tag = f"cp{sys.version_info.major}{sys.version_info.minor}"
match = next((w for w in self.wheels if f"-{tag}-" in w.name and token in w.name), None)
match = next((w for w in self.wheels if wheel_target(w) == (tag, token)), None)
if match is None:
raise RuntimeError(
f"no {tag} {token} wheel among {[w.name for w in self.wheels]}; pass "
@@ -475,17 +474,24 @@ class Preflight:
for tag, wheel, executable in targets:
label = f"{tag} {wheel.name}"
try:
digest = _sha256_file(wheel)
# One venv per wheel: it runs the import smoke test, the bundled
# asset check and the frame pipeline together.
record = verify_wheel(
verifier = verify_wheel
extra = {"python_executable": executable, "offline": self.options.offline}
if wheel_target(wheel)[1] != "win_amd64":
verifier = verify_manylinux_wheel
extra = {"repo_root": self.repo_root}
record = verifier(
wheel,
video=video,
config_name=self.options.config_name,
frames=self.options.frames,
python_executable=executable,
offline=self.options.offline,
check_assets=not self.options.no_assets,
**extra,
)
if _sha256_file(wheel) != digest:
raise RuntimeError(f"{wheel.name} changed during runtime verification")
except subprocess.CalledProcessError as exc:
problems.append(f"{label}: command failed ({exc})")
continue
@@ -497,7 +503,7 @@ class Preflight:
f"{label}: {record['assets']} | frames={record['frames']} "
f"flow={record['flow_shape']}"
)
self.runtime_records.append({"tag": tag, **record})
self.runtime_records.append({"tag": tag, **record, "sha256": digest})
detail = "\n".join(lines)
if problems: