缺陷(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 重打包即可得到
资源管理器可直接双击解压的包。
118 lines
4.0 KiB
Bash
Executable File
118 lines
4.0 KiB
Bash
Executable File
#!/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 "============================================================"
|