release: v0.2.4 里程碑快照(孤儿提交,无父;树 = dev 68362e5)
CI / fmt (rustfmt --check) (push) Waiting to run
CI / clippy (ubuntu-latest) (push) Waiting to run
CI / clippy (windows-latest) (push) Waiting to run
CI / test (ubuntu-latest) (push) Waiting to run
CI / test (windows-latest) (push) Waiting to run
CI / build release (ubuntu-latest) (push) Waiting to run
CI / build release (windows-latest) (push) Waiting to run
CI / runtime smoke (ubuntu x64, xvfb) (push) Waiting to run
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / update-e2e (windows x64) (push) Waiting to run
GPU evidence / GPU 判据自测(不需 GPU;跳过 ≠ 已验证) (push) Waiting to run
GPU evidence / GPU 证据 — 探测可用产物与硬件适配器 (push) Waiting to run
Guards / core 零 UI 守门 (push) Waiting to run
Guards / presenter 零 UI 守门 (push) Waiting to run
Guards / design 零第三方依赖守门 (push) Waiting to run
Guards / unsafe 落点守门(集合必须恰好等于期望) (push) Waiting to run
Guards / 文件行数 ≤400 守门 (push) Waiting to run
Guards / 依赖许可与来源(cargo-deny) (push) Waiting to run
Release guard / 发布标记语义守门(push tag → 稳定版) (push) Waiting to run
Signing status(播报,不是门禁) / 判据自测(三行/退出码/变异重放/接线) (push) Waiting to run
Signing status(播报,不是门禁) / 签名就绪度(播报) (push) Waiting to run
Release / 选槽位(默认四个:Windows 两档 + Linux 两档) (push) Waiting to run

本批内容见 CHANGELOG.md 的 0.2.4 段。按 D41 用孤儿快照推 main,保留「公开史只有里程碑」的模型。
This commit is contained in:
AskaEth committed 2026-11-11 21:41:38 +08:00
commit a5d1dec495
1580 files changed
+320938

No files matched your search

+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""GitHub `if:` 表达式的小求值器(M253 / r2 复审返工,判据 3 用)。
为什么需要它:字符串存在性判据被两轮复审证伪过 —— `if: needs.probe.outputs.available == 'true' || always()`
用 `in` 判照样绿,`if: true` 也绿。所以这里**真求值**:给 `needs.probe.outputs.available` 分别取
`'true'` / `'false'` / `''`,门必须分别判真 / 假 / 假 —— 门到底还挂不挂,由语义决定,不由子串决定。
**只认一小撮语法,其余一律抛 `ConditionError`(调用方按红处理,宁可假红)**:
`==` / `!=` / `&&` / `||` / 括号 / 单引号字符串 / 数字 / `needs.<job>.outputs.<名>` / `true|false|null` /
`always()|success()|failure()|cancelled()`(后四个按「假定上游成功」取常量)。**不支持 `!`**:GitHub 与
Python 的 `!` 优先级不同,认不出比误判安全。不是 GitHub 语义的替身,是它的一个保守子集。
"""
from __future__ import annotations
import re
AVAILABLE_IDENT = "needs.probe.outputs.available"
CALL_FUNCS = {"always": True, "success": True, "failure": False, "cancelled": False}
_TOKEN_RE = re.compile(r"(?P<string>'[^']*')|(?P<number>\d+)|(?P<ident>[A-Za-z_][\w.\-]*)|(?P<op>==|!=|&&|\|\||[()!])")
class ConditionError(Exception):
"""`if:` 表达式认不出 —— 认不出即判红,绝不默认放过。"""
def evaluate_condition(raw, available: str) -> bool:
"""把 GitHub 的 `if:` 表达式求值。只认一小撮语法,其余抛 `ConditionError`(= 判红)。"""
text = str(raw).strip()
if text.startswith("${{") and text.endswith("}}"):
text = text[3:-2].strip()
for name, value in CALL_FUNCS.items():
text = re.sub(rf"\b{name}\s*\(\s*\)", "true" if value else "false", text)
if re.search(r"\b(" + "|".join(CALL_FUNCS) + r")\s*\(", text):
raise ConditionError("函数只支持不带参数的形式")
parts: list[str] = []
pos = 0
while pos < len(text):
if text[pos].isspace():
pos += 1
continue
match = _TOKEN_RE.match(text, pos)
if not match:
raise ConditionError(f"认不出的字符 {text[pos]!r}")
pos = match.end()
token = match.group()
if match.lastgroup in ("string", "number"):
parts.append(token)
elif match.lastgroup == "ident":
if token == AVAILABLE_IDENT:
parts.append("__available")
elif token in ("true", "false", "null"):
parts.append({"true": "True", "false": "False", "null": "None"}[token])
else:
raise ConditionError(f"认不出的标识符 `{token}`")
else:
if token == "!":
raise ConditionError("不支持 `!`(GitHub 与 Python 的优先级不同,宁可认不出)")
parts.append({"&&": "and", "||": "or"}.get(token, token))
source = " ".join(parts)
try:
return bool(eval(source, {"__builtins__": {}}, {"__available": available})) # noqa: S307 - 词表是白名单,见上
except Exception as error: # noqa: BLE001 - 任何求值失败都按「认不出」处理
raise ConditionError(f"求值失败({error}):`{source}`") from None