Files
opendance-windows/build/check-version.sh
T
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

77 lines
3.9 KiB
Bash
Executable File
Raw 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 客户端版本号一致性校验
#
# 文档 §11.2「单一来源 / 可核对」在本端的落点:
# * `project.godot` 的 `application/config/version` 是**运行时唯一来源**
# (「关于」清单直接读它,导出后打进 .pck);
# * `project.yaml` 的 `version` 是任务清单/发布记录的来源;
# * 发布产物文件名 `opendance-windows-vX.Y.Z.zip` 与 Git tag 必须一致。
#
# 三者一旦漂移,就会出现"界面显示 v0.2.0、产物却叫 v0.2.1"这种不可核对的发布,
# 因此打包前强制校验。
#
# 用法:bash build/check-version.sh [期望版本号]
# ============================================================
set -uo pipefail
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"
GODOT_VERSION="$(sed -n 's/^config\/version="\(.*\)"$/\1/p' project.godot | head -1)"
YAML_VERSION="$(sed -n 's/^version:[[:space:]]*//p' project.yaml | head -1)"
PRESET="$PROJECT_DIR/export_presets.cfg"
PRESET_FILE_VERSION="$(sed -n 's/^application\/file_version="\(.*\)"$/\1/p' "$PRESET" 2>/dev/null | head -1)"
PRESET_PRODUCT_VERSION="$(sed -n 's/^application\/product_version="\(.*\)"$/\1/p' "$PRESET" 2>/dev/null | head -1)"
EXPECTED="${1:-$YAML_VERSION}"
printf ' project.godot application/config/version = %s\n' "${GODOT_VERSION:-(未找到)}"
printf ' project.yaml version = %s\n' "${YAML_VERSION:-(未找到)}"
printf ' export_presets application/file_version = %s\n' "${PRESET_FILE_VERSION:-(未找到)}"
printf ' export_presets application/product_version= %s\n' "${PRESET_PRODUCT_VERSION:-(未找到)}"
printf ' 期望版本 = %s\n' "${EXPECTED:-(未指定)}"
FAILED=0
[ -n "$GODOT_VERSION" ] || { echo " ✗ 无法从 project.godot 解析 config/version" >&2; FAILED=1; }
[ -n "$YAML_VERSION" ] || { echo " ✗ 无法从 project.yaml 解析 version" >&2; FAILED=1; }
# 导出预设的 file_version / product_version 决定 OpenDance.exe 的 PE 版本资源,
# 即 Windows「右键 → 属性 → 详细信息」里显示的版本。它们**不会**随 project.godot
# 自动更新,曾经因此让 v0.2.1 的发布包显示 0.1.0。这里静态拦住;
# 产物那一侧再由 build/check-pe-version.sh 直接读 exe 复核。
if [ ! -f "$PRESET" ]; then
echo " ✗ 找不到 export_presets.cfg(无法校验 PE 版本资源的来源)" >&2
FAILED=1
else
for PAIR in "file_version:$PRESET_FILE_VERSION" "product_version:$PRESET_PRODUCT_VERSION"; do
KEY="${PAIR%%:*}"; VALUE="${PAIR#*:}"
if [ -z "$VALUE" ]; then
echo " ✗ export_presets.cfg 缺少 application/${KEY}(导出后 PE 版本资源会沿用旧值)" >&2
FAILED=1
elif [ -n "$GODOT_VERSION" ] && [ "$VALUE" != "$GODOT_VERSION" ]; then
echo " ✗ 导出预设 application/${KEY}=${VALUE} 与 project.godot 的 ${GODOT_VERSION} 不一致" >&2
echo " (Windows 属性页会显示 ${VALUE};跑 bash build/sync-export-version.sh 后重新导出)" >&2
FAILED=1
fi
done
fi
if [ -n "$EXPECTED" ] && [ "$GODOT_VERSION" != "$EXPECTED" ]; then
echo " ✗ project.godot 的版本与期望不一致(界面/About 会显示错版本)" >&2
FAILED=1
fi
if [ -n "$YAML_VERSION" ] && [ "$GODOT_VERSION" != "$YAML_VERSION" ]; then
echo " ✗ project.godot 与 project.yaml 版本不一致" >&2
FAILED=1
fi
# 版本号格式 X.Y.Z
if [ -n "$GODOT_VERSION" ] && ! printf '%s' "$GODOT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo " ✗ 版本号应为 X.Y.Z(实际 $GODOT_VERSION)" >&2
FAILED=1
fi
if [ "$FAILED" -ne 0 ]; then
echo " ✗ 版本一致性校验失败" >&2
exit 1
fi
echo " ✓ 版本一致:v$GODOT_VERSION(project.godot = project.yaml = export_presets.cfg${EXPECTED:+ = 期望值})"