Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,42 @@ jobs:
- run: uv sync
- name: Python tests (Windows)
run: uv run pytest tests/ -v
# v0.2.30 教训(Build Release 31661378619):Test 全绿 ≠ .iss 能编译。
# make-installer.sh 的 emrg.iss 只在 tag 触发 Build Release 时经 iscc 编译,
# #727 误用 LoadStringFromFile 单参数形式(Inno 真实签名是 2 参数 out-param)
# → iscc "Invalid number of parameters" 发版才暴露。此处用 runner 预装的
# iscc 编译渲染出的 emrg.iss(stub payload),PR CI 即拦截 .iss 语法/签名错误。
- name: Inno Setup script compile smoke test
shell: bash
run: |
set -euo pipefail
STAGE="$(mktemp -d)"
mkdir -p "$STAGE/payload/bin" "$STAGE/dist/artifacts"
touch "$STAGE/payload/bin/stop-emrg.cmd"
# icon.ico 是 gen-assets 产物(未入库)——生成最小合法 .ico 供 iscc 编译期
# SetupIconFile 检查;{app}(={%USERPROFILE}\.emrg\install)引用的文件
# (UninstallDisplayIcon/[Icons]/[UninstallRun])也需存在。
uv run python - <<'PY'
import struct
def write_ico(path):
hdr = struct.pack('<HHH', 0, 1, 1)
entry = struct.pack('<BBBBHHII', 1, 1, 0, 0, 1, 32, 44, 22)
bih = struct.pack('<IiiHHIIiiII', 40, 1, 1, 1, 32, 0, 4, 0, 0, 0, 0)
open(path, 'wb').write(hdr + entry + bih + b'\x00\x00\x00\x00')
write_ico('packaging/assets/icon.ico')
PY
APP="$USERPROFILE/.emrg/install"
mkdir -p "$APP/bin" "$APP/emrg-gui/EMRG"
touch "$APP/bin/emrg.cmd" "$APP/bin/python.exe" "$APP/emrg-gui/EMRG/EMRG.exe"
# 渲染 make-installer.sh 的 emrg.iss heredoc(变量展开与真实构建一致)。
# 先赋值再统一 export(单行 export 内自引用触发 shellcheck SC2318/SC2097/SC2098)。
VERSION="0.0.0-smoke"
DIST_WIN="$(cygpath -m "$STAGE/dist")"
STAGE_WIN="$(cygpath -m "$STAGE")"
ROOT_WIN="$(cygpath -m "$PWD")"
export VERSION DIST_WIN STAGE_WIN ROOT_WIN STAGE
# 单引号内避免 \$ 字面量(shellcheck SC2016),用无 $ 的锚定模式
sed -n '/cat > .*emrg\.iss.*<</,/^EOF$/p' packaging/make-installer.sh > "$STAGE/gen.sh"
bash "$STAGE/gen.sh"
command -v iscc >/dev/null 2>&1 || { echo "::error::iscc not on PATH (runner image regression)"; exit 1; }
iscc "$STAGE/emrg.iss"
12 changes: 10 additions & 2 deletions packaging/make-installer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ var
ResultCode: Integer;
StopScript: string;
LogFile: string;
LogText: string;
LogText: AnsiString;
begin
Result := '';
ExtractTemporaryFile('stop-emrg.cmd');
Expand All @@ -400,8 +400,16 @@ begin
if ResultCode <> 0 then
begin
LogText := '';
// LoadStringFromFile 的 Inno Pascal Script 签名是
// function LoadStringFromFile(const FileName: String; var S: AnsiString): Boolean;
// (6.7.1 → 7.x 全版本一致,见 issrc Shared.ScriptFunc.pas)——不存在单参数
// 字符串返回形式!v0.2.30 Build Release 31661378619 因此编译失败
// (iscc "Invalid number of parameters",Test CI 不编译 .iss 未拦住)。
// 正确用法:out-param 写入 LogText,返回 Boolean 表示成功。
// 注意:本注释位于未加引号 heredoc 内,禁用反引号与命令替换语法
// (iscc compile gate 实证捕获),以免破坏 .iss 渲染。
if FileExists(LogFile) then
LogText := LoadStringFromFile(LogFile);
LoadStringFromFile(LogFile, LogText);
if Length(LogText) > 2000 then
LogText := Copy(LogText, 1, 2000);
if LogText <> '' then
Expand Down
12 changes: 11 additions & 1 deletion tests/test_installer_stop.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,17 @@ def test_make_installer_iss_has_prepare_to_install():
# R125: rant 2026-08-13T09:24:37 — 输出重定向到 {tmp}\stop-emrg.log(2>&1),
# 失败时 LoadStringFromFile 读日志展示杀不掉的进程,不再让宿主手动跑诊断
assert '/c ""\' + StopScript + \'" > "\' + LogFile + \'" 2>&1"' in content
assert "LoadStringFromFile(LogFile)" in content
# ⚡ LoadStringFromFile 的 Inno Pascal Script 签名是 2 参数 out-param 形式
# `(const FileName: String; var S: AnsiString): Boolean`(6.7.1 → 7.x 一致,
# issrc Shared.ScriptFunc.pas)——单参数字符串返回形式不存在,iscc 编译报
# "Invalid number of parameters"(v0.2.30 Build Release 31661378619 实际失败,
# Test CI 不编译 .iss 未拦住)。正反两态钉死正确调用形态。
assert "LoadStringFromFile(LogFile, LogText)" in content # 正:out-param 形式
assert ":= LoadStringFromFile(LogFile)" not in content # 反:1 参数形式不存在
# ⚡ 2 参形式第 2 参是 var S: AnsiString——LogText 必须声明 AnsiString(Inno 6
# 的 string=UnicodeString,传 string 变量 → iscc "Type mismatch",门禁实测拦截)。
assert "LogText: AnsiString;" in content # 正:AnsiString 变量
assert "LogText: string;" not in content # 反:UnicodeString 不匹配 var AnsiString
assert "Length(LogText) > 2000" in content
assert "Details from stop-emrg.cmd:" in content
assert "SW_HIDE" in content # 批处理执行不弹控制台窗口(#592 纪律)
Expand Down
Loading