Files
zijunchiang ba988f6ca6 fix(packaging): 发布包 exe 的 PE 版本资源必须等于发布版本(v0.2.2)
缺陷(v0.2.1 实测):把 opendance-windows-v0.2.1.zip 解开、在 Windows 上
「右键 → 属性 → 详细信息」,显示的是

    文件版本    0.1.0
    产品版本    0.1.0

而产物名、Git tag、README 全是 v0.2.1 —— 正是文档 §11.2 要禁止的
「不可核对的发布」。

根因:export_presets.cfg 的 application/file_version /
application/product_version 被硬编码在 0.1.0,而它们**不会**跟随
project.godot 的 application/config/version 自动更新;check-version.sh 当时
只比 project.godot ↔ project.yaml(两处一致),所以静态校验全绿、产物却是错的。
漂移发生在没人看的第三个位置 —— 校验位置少一个,等于没校验。

证据:
  strings -a -el OpenDance.exe  ->  FileVersion 0.1.0 / ProductVersion 0.1.0
  VS_FIXEDFILEINFO @0x67b976c   ->  FileVersion 0.1.0.0 / ProductVersion 0.0.0.0
对照组:官方模板 windows_release_x86_64.exe 的 FileVersion = 4.7.2,
说明本机 rcedit 改写是生效的,问题纯粹在预设的值本身。

修复:
  * build/sync-export-version.sh(新增):导出前把版本号写进导出预设,
    幂等、拒绝非 X.Y.Z;
  * build/check-pe-version.sh(新增):直接读 exe 的 PE 版本资源 ——
    VS_FIXEDFILEINFO(签名 0xFEEF04BD 后 16 字节,grep -abo 取偏移约 40 ms)
    与 StringFileInfo(strings -el,资源管理器属性页显示的就是它)。
    两处都查:实测固定信息里的 ProductVersion 恒为 0.0.0.0;
  * build/check-version.sh:新增导出预设两个键的校验;
  * build/export-windows.sh:导出前同步、导出后直接复核产物;
  * build/package-release.sh:打包前校验源 exe、解包后再校验包内 exe;
  * build/verify.sh:新增步骤 1/5「产物 PE 版本资源」(未导出则跳过);
  * tests/test_about.gd:新增 test_export_preset_version_matches_project_version。

反向验证:把预设 file_version 改回 0.1.0 →
  check-version.sh 退出码 1(报出两处不一致);
  无头测试 753 通过 / 1 失败,失败项正是
  「导出预设的 file_version 与版本号唯一来源一致」。

实测 v0.2.2 产物:PE FileVersion 0.2.2.0 / StringFileInfo 0.2.2,
版本号在 project.godot / project.yaml / export_presets.cfg / exe 元数据 /
产物名 / tag 六处一致。verify.sh 全绿(754 通过 / 0 失败 / 5 跳过)。

同时把 LZMA 压缩的取舍写清楚:deflate 包 38,248,818 B 仍超 IIS
30,000,000 B 上限,故 Release 资产仍是 LZMA 整包(26,628,529 B,不拆分卷);
若上限放开或改由 Web /static 分发,用 ZIP_METHOD=deflate 重打包即可得到
资源管理器可直接双击解压的包。
2026-09-17 04:22:57 +08:00

118 lines
4.0 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================
# OpenDance Studio —— Windows 客户端一键验证
#
# 依次执行:脚本编译检查 → 无头单元/集成测试 → 应用启动检查
# 任一环节失败即退出非 0。
#
# 用法:GODOT_BIN=/path/to/godot bash build/verify.sh
# ============================================================
set -uo pipefail
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"
GODOT_BIN="${GODOT_BIN:-}"
if [ -z "$GODOT_BIN" ]; then
for candidate in godot godot4 Godot; do
if command -v "$candidate" >/dev/null 2>&1; then GODOT_BIN="$candidate"; break; fi
done
fi
if [ -z "$GODOT_BIN" ]; then
echo "错误:未找到 Godot。请用 GODOT_BIN=<路径> 指定。" >&2
exit 1
fi
FAILED=0
echo "============================================================"
echo " 0/5 版本号一致性(project.godot / project.yaml / export_presets.cfg)"
echo "============================================================"
if bash "$PROJECT_DIR/build/check-version.sh"; then
:
else
echo "✗ 版本一致性校验失败"
FAILED=1
fi
echo ""
echo "============================================================"
echo " 1/5 产物 PE 版本资源(Windows 属性页显示的版本)"
echo "============================================================"
EXPORTED_EXE="$PROJECT_DIR/build/windows/OpenDance.exe"
EXPECTED_VERSION="$(sed -n 's/^config\/version="\(.*\)"$/\1/p' "$PROJECT_DIR/project.godot" | head -1)"
if [ -f "$EXPORTED_EXE" ]; then
if bash "$PROJECT_DIR/build/check-pe-version.sh" "$EXPORTED_EXE" "$EXPECTED_VERSION"; then
:
else
echo "✗ 已导出 exe 的 PE 版本资源与 v$EXPECTED_VERSION 不一致(属性页会显示错版本)"
FAILED=1
fi
else
echo "· 尚未导出 build/windows/OpenDance.exe,跳过(打包时 package-release.sh 会强制校验)"
fi
echo ""
echo "============================================================"
echo " 2/5 脚本编译检查"
echo "============================================================"
IMPORT_LOG=$(mktemp)
"$GODOT_BIN" --headless --path "$PROJECT_DIR" --import >"$IMPORT_LOG" 2>&1
if grep -qE "SCRIPT ERROR|Parse Error|Compile Error" "$IMPORT_LOG"; then
echo "✗ 存在脚本编译错误:"
grep -E "SCRIPT ERROR|Parse Error|Compile Error" "$IMPORT_LOG" | head -20
FAILED=1
else
echo "✓ 全部脚本编译通过"
fi
rm -f "$IMPORT_LOG"
echo ""
echo "============================================================"
echo " 3/5 无头测试(单元 + 真实 API 集成)"
echo "============================================================"
TEST_LOG=$(mktemp)
"$GODOT_BIN" --headless --path "$PROJECT_DIR" --script res://tests/run_tests.gd >"$TEST_LOG" 2>&1
TEST_STATUS=$?
grep -E "^(== 结果|全部通过)" "$TEST_LOG" || true
if [ "$TEST_STATUS" -ne 0 ]; then
echo "✗ 测试失败(退出码 $TEST_STATUS)"
grep -E "✗" "$TEST_LOG" | head -20
FAILED=1
else
echo "✓ 测试全部通过"
fi
rm -f "$TEST_LOG"
echo ""
echo "============================================================"
echo " 4/5 应用启动检查(180 帧)"
echo "============================================================"
RUN_LOG=$(mktemp)
timeout 120 "$GODOT_BIN" --headless --path "$PROJECT_DIR" --quit-after 180 >"$RUN_LOG" 2>&1
RUN_STATUS=$?
if [ "$RUN_STATUS" -ne 0 ]; then
echo "✗ 启动失败(退出码 $RUN_STATUS)"
tail -20 "$RUN_LOG"
FAILED=1
elif grep -qE "SCRIPT ERROR|ERROR:" "$RUN_LOG"; then
echo "✗ 启动过程有错误:"
grep -E "SCRIPT ERROR|ERROR:" "$RUN_LOG" | head -10
FAILED=1
else
echo "✓ 应用启动正常,无运行时错误"
fi
rm -f "$RUN_LOG"
echo ""
if [ "$FAILED" -ne 0 ]; then
echo "============================================================"
echo " 验证失败"
echo "============================================================"
exit 1
fi
echo "============================================================"
echo " 验证全部通过"
echo "============================================================"