From aa42496561653815199fd5798be07fb5150d01f8 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Sat, 7 Nov 2026 09:15:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(ci):=20M156=20=E4=BF=AE=20guards.yml=20?= =?UTF-8?q?=E4=B8=89=E5=A4=84=20`bash=20-e`=20=E9=9D=99=E9=BB=98=E8=87=AA?= =?UTF-8?q?=E6=9D=80=EF=BC=88presenter-no-ui=20=E4=BB=8E=E6=9C=AA=E7=BB=BF?= =?UTF-8?q?=E8=BF=87=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M155 钉死:guards.yml 的 `hits=$(… | grep -iE …)` 在 grep 零命中(exit 1)时被 runner 默认的 `bash -e {0}` 拖红整步,且脚本里 `set -uo pipefail` 关不掉 -e, 所以一条 `::error::` 都打不出来 —— presenter-no-ui 自 M89 引入起从未绿过一次。 - presenter 依赖树 step:`hits=` 补 `|| true`(零命中回到绿路,真命中仍红) - core 依赖树 step:裸 `tree=$(cargo tree …)` 改 `if ! tree=$(…)` 守卫, 与 presenter / design 两处对称,cargo tree 失败时打注解而不是静默退出 - unsafe-scope:`actual=$(git grep …)` 末尾补 `|| true`,零匹配不再中止整步 - 文件头加一条警示:「本文件所有 run: 都在 bash -e 下,裸管道/裸赋值会被静默杀死」 验证(M155 方法:step 脚本从 yml 原样切出、`bash -e` 执行): presenter 零命中 改前 exit1/0 注解 → 改后 exit0 打 OK;真命中仍 exit1/2 注解; core cargo tree 失败 改前 exit101/0 注解 → 改后 exit1/1 注解;unsafe 零匹配 改前 exit1/0 注解 → 改后 exit1/2 注解;两处正常路径均仍绿。pyyaml 可解析,398 行。 --- .github/workflows/guards.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/guards.yml b/.github/workflows/guards.yml index 807bf0d..0fbc9b1 100644 --- a/.github/workflows/guards.yml +++ b/.github/workflows/guards.yml @@ -1,5 +1,9 @@ name: Guards +# ⚠ 本文件所有 `run:` 都在 `bash -e {0}` 下跑(GitHub 未指定 shell 时的默认值),脚本里的 +# `set -uo pipefail` **关不掉 -e**:裸管道 / 裸赋值 `x=$(… | grep …)` 零命中时会把整步静默杀死, +# 一条 `::error::` 都不打(M142 在 release-build.yml 栽过,M156 在这里补账)。探测一律 `if ! x=$(…)` 或 `$(… || true)`。 + # 架构与合规守门(与 fmt/clippy 同级,不允许 continue-on-error): # 1. core-no-ui —— crates/core 零 UI 依赖(D3 铁律),依赖表 + cargo tree 双查 # 2. presenter-no-ui —— crates/presenter 零 UI 依赖(D26 / M85):Slint 版与 iced 版共用的宿主层 @@ -54,7 +58,11 @@ jobs: run: | set -uo pipefail forbidden='slint|egui|eframe|iced|winit|gtk|javafx|tauri|fltk|druid|relm' - tree=$(cargo tree -p unlucky-core --edges normal --prefix none) + # 与下方 presenter / design 的 `if ! tree=$(…)` 对称:cargo tree 自己失败(改名 / 解析失败)时裸赋值会被 -e 静默杀死,只剩 exit code 1 无注解。 + if ! tree=$(cargo tree -p unlucky-core --edges normal --prefix none); then + echo "::error::cargo tree -p unlucky-core 执行失败 —— crate 是否仍叫 unlucky-core?" + exit 1 + fi echo "$tree" if echo "$tree" | grep -vE '^unlucky-core v' | grep -qiE "$forbidden"; then echo "::error::core 的依赖树出现 UI 框架 —— 传递依赖也不允许" @@ -109,7 +117,9 @@ jobs: exit 1 fi echo "$tree" - hits=$(printf '%s\n' "$tree" | grep -vE '^unlucky-presenter v' | grep -iE "$forbidden") + # 「零命中」本来就该是绿的正路,但裸赋值会把 grep 的 exit 1 交给 -e(见文件头): + # M156 之前这里每次零命中都整步红且零注解 —— presenter-no-ui 自 M89 引入起从未绿过。 + hits=$(printf '%s\n' "$tree" | grep -vE '^unlucky-presenter v' | grep -iE "$forbidden" || true) if [ -n "$hits" ]; then echo "::error::presenter 的依赖树出现 UI 框架(传递依赖也不允许),本次命中:" printf '%s\n' "$hits" | sed 's/^/ - /' @@ -318,9 +328,10 @@ jobs: } # 只对「文本里出现过 unsafe_code」的文件跑词法器(标识符不可能被空白拆开, # 所以这个预筛不会漏)。601 个文件 → 个位数个候选,整个 job 约 2 秒。 + # `git grep` 零匹配 exit 1 + pipefail → 裸赋值同样会被 -e 静默杀死(见文件头)。 actual=$(git grep -l 'unsafe_code' -- '*.rs' 2>/dev/null | LC_ALL=C sort | while IFS= read -r f; do if scan "$f"; then printf '%s\n' "$f"; fi - done | LC_ALL=C sort) + done | LC_ALL=C sort || true) echo "期望(恰好这一个):$EXPECTED" echo "实际扫到的集合:" if [ -n "$actual" ]; then printf '%s\n' "$actual" | sed 's/^/ - /'; else echo " (空)"; fi