refactor(release): PE 读回步骤体拆进 packaging/ci-pe-version-gate.sh(release-build.yml 400 行守门)

复审 P1-1:main 上 release-build.yml 是 400 行(贴线),上一版 +23/−10 顶到 421,越过
guards.yml 的 file-size 硬门禁(LIMIT=400 是用户硬约束,不许抬)。按复审给定的方向「拆」:

- 新增 packaging/ci-pe-version-gate.sh(59 行):读回两个产物 + 从 Cargo.toml 同源取版本号 +
  失败逐条转 ::error:: 注解(上限 30 行)+ 非 0 退出;找不到 python 仍 fail;
  临时日志用 mktemp + trap 清理,仓库根按脚本位置反推(不依赖 cwd)
- release-build.yml 那一步只留 bash packaging/ci-pe-version-gate.sh "$BUILD_DIR" →
  文件 421 → 396 行(比 main 的 400 还少 4)
- 判据一行没改:仍然读产物字节、仍然由 check_pe_version.py 决定红绿、仍然非 0 退出

复审 P2-2:check_pe_version.py 的「什么时候退出非 0」清单补上第 7 条第 ③ 项
(签名后不足 16 字节、读不到 dwFileVersion,check():124-125)。
This commit is contained in:
AskaEth committed 2026-11-12 09:25:30 +08:00
1 parent 47386ef2ff
commit bb572ac2dd
3 files changed
+71 -29

No files matched your search

+3 -28
View File
@@ -217,40 +217,15 @@ jobs:
# 版本号、FIXEDFILEINFO 的 dwFileVersion)全在 `packaging/check_pe_version.py`,本机可跑。
# 只在 Windows 槽位跑:Linux/macOS 产物没有 PE 头,那边 `build.rs` 整段不执行(见
# `packaging/pe_version.rs` 文件头)。**工具缺失也 fail**:找不到 python 就等于门禁失效。
# 步骤体本身在 `packaging/ci-pe-version-gate.sh`:读回 + 同源取版本号 + 失败逐条转 `::error::`
# 注解(M264 从本文件拆出,给 400 行硬门禁腾地方;判据没动,仍由检查器 exit 1)。
- name: PE 版本资源读回(CompanyName / ProductName / 版权 / 版本号真的在产物里)
if: runner.os == 'Windows'
shell: bash
env:
BUILD_DIR: ${{ inputs.build_dir }}
run: |
set -euo pipefail
PY=$(command -v python3 || command -v python)
if [ -z "$PY" ]; then echo "::error::找不到 python,PE 版本资源门禁无法运行(门禁不降级)"; exit 1; fi
# 先把「产物到底是哪个文件、多大」落成日志:这一步红了,第一件要排除的就是「读的不是那个文件」。
# `|| echo` 是刻意的:让「文件不存在」的判据由检查器自己报(它的措辞比 ls 更适合当注解)。
ls -l "$BUILD_DIR/unlucky-launcher-iced.exe" "$BUILD_DIR/ull.exe" \
|| echo "::warning::ls 没列出产物(文件可能不存在),判据交给下面的检查器"
# 版本号与 Cargo.toml **同源**:`[workspace.package] version = "x.y.z"`。
version=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)
echo "expect-version=$version"
# 判据本身不降级(仍然只看产物字节、仍然 exit 1),但**失败原因必须自己浮出来**:v0.2.4 的
# run 43031591576 两个 Windows 槽位红在这里,注解 API 上只剩一句 `Process completed with exit
# code 1.`(检查器把原因打在 stderr,而 step 没转成注解),只能靠猜。故整段输出 tee 到文件,
# failure 时逐行转 `::error::` 注解。
log="$RUNNER_TEMP/pe-version.log"
status=0
"$PY" packaging/check_pe_version.py \
"$BUILD_DIR/unlucky-launcher-iced.exe" "$BUILD_DIR/ull.exe" \
--expect-version "$version" 2>&1 | tee "$log" || status=$?
if [ "$status" -ne 0 ]; then
# 上限 30 行:正常失败是「每个产物几条判据」,异常失败(traceback)也不会被截掉开头。
line_no=0
while IFS= read -r line; do
line_no=$((line_no + 1))
if [ "$line_no" -le 30 ]; then echo "::error::PE 版本资源读回:$line"; fi
done < "$log"
exit "$status"
fi
bash packaging/ci-pe-version-gate.sh "$BUILD_DIR"
- name: Windows 单文件自检(导入表不得出现 VC++ 可再发行 DLL)
if: runner.os == 'Windows'
+2 -1
View File
@@ -28,7 +28,8 @@ version, so "version drifted from Cargo.toml" is caught.
4. 缺结构键 `VS_VERSION_INFO` / `StringFileInfo` / `VarFileInfo` / `Translation`;
5. 缺承诺字段名,或字段值不等于承诺值(CompanyName / ProductName / FileDescription / LegalCopyright);
6. `OriginalFilename` 不是 `<bin>.exe`;
7. 给了 `--expect-version` 时:四段式版本字符串不在资源里,或 `dwFileVersion` 与它不一致。
7. 给了 `--expect-version` 时:①四段式版本字符串不在资源里;②`dwFileVersion` 与它不一致;
③签名之后不足 16 字节、读不到 `dwFileVersion`(`FIXEDFILEINFO` 被截断)。
其它:`--self-test` 自检失败 → 1;没给产物也没给 `--self-test` → 2(打印用法)。
输出本身**不再是**失败原因:`safe_streams()` 保证「汉字打不出来」不会把一条通过的判据变成红。
+66
View File
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# PE 版本资源读回门禁(M190 判据在 CI 上的入口;M264 从 release-build.yml 拆出来)。
#
# 为什么是脚本而不是内联 step:`.github/workflows/release-build.yml` 撞着 400 行硬门禁
# (`guards.yml` 的 file-size,用户硬约束,不许抬 LIMIT),而「读回两个产物 + 同源取版本号 +
# 失败逐条转注解」内联进去必然顶上线。拆法与 `packaging/linux-smoke-docker.sh` /
# `packaging/linux-check-docker.sh` 同一思路:workflow 只留一行调用。
#
# 判据一行没改,仍在 `packaging/check_pe_version.py`:
# ①读的是**产物字节**(构建日志里打印过不算证据);②版本号与 `Cargo.toml` 同源;
# ③任何一条判据没过就非 0 退出(含「产物不存在」「找不到 python」——工具缺失等于门禁失效,不降级)。
# 本脚本只做「调用 + 把失败原因变成 `::error::` 注解」:v0.2.4 的 run 43031591576 两个 Windows
# 槽位红在这里时,注解 API 上只剩一句 `Process completed with exit code 1.`,只能靠猜。
#
# 用法:
# bash packaging/ci-pe-version-gate.sh [build_dir] # 默认 target/release
set -euo pipefail
BUILD_DIR="${1:-target/release}"
# 仓库根按脚本位置反推:workflow 在仓库根跑,但本地从别处调用时也不该依赖 cwd。
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
PY=$(command -v python3 || command -v python || true)
if [ -z "$PY" ]; then
echo "::error::找不到 python,PE 版本资源门禁无法运行(门禁不降级)"
exit 1
fi
# 先把「产物到底是哪个文件、多大」落成日志:这一步红了,第一件要排除的就是「读的不是那个文件」。
# `|| echo` 是刻意的:让「文件不存在」的判据由检查器自己报(它的措辞比 ls 更适合当注解)。
ls -l "$BUILD_DIR/unlucky-launcher-iced.exe" "$BUILD_DIR/ull.exe" \
|| echo "::warning::ls 没列出产物(文件可能不存在),判据交给下面的检查器"
# 版本号与 `Cargo.toml` **同源**:`[workspace.package] version = "x.y.z"`。不在这里写死任何版本。
version=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)
echo "expect-version=$version"
log=$(mktemp "${TMPDIR:-/tmp}/pe-version.XXXXXX.log" 2>/dev/null || true)
if [ -n "$log" ]; then
trap 'rm -f "$log"' EXIT INT TERM
echo "log: $log"
else
# 连临时文件都建不出来时**不判红**:判据是产物的字节,不是本脚本的管道。原因看原始输出。
echo "::warning::mktemp 失败,失败原因只能看下面的原始输出(判据不变)"
fi
status=0
"$PY" packaging/check_pe_version.py \
"$BUILD_DIR/unlucky-launcher-iced.exe" "$BUILD_DIR/ull.exe" \
--expect-version "$version" 2>&1 | tee "${log:-/dev/null}" || status=$?
if [ "$status" -ne 0 ]; then
if [ -n "$log" ]; then
# 上限 30 行:正常失败是「每个产物几条判据」,异常失败(traceback)也不会被截掉开头。
line_no=0
while IFS= read -r line; do
line_no=$((line_no + 1))
if [ "$line_no" -le 30 ]; then echo "::error::PE 版本资源读回:$line"; fi
done < "$log"
fi
exit "$status"
fi
exit 0