CI ran .gitea/ci/commit_message_lint.py, an independent reimplementation that parsed the type/emoji mapping out of docs/common/commit_message.md. Its scope pattern accepted fix(-a), fix(a-), fix(a--b) and fix(_), and it had no subject length check, so the gate that actually blocks merges enforced weaker rules than the Validation this skill reports. The CI entry is now a wrapper that locates the skill validator and delegates to it with no arguments; commit_policy.json becomes the only rule source and explanatory docs stop being a machine policy input. The validator also learns the workflow_run event, whose payload carries neither a PR title nor a before/after range. An upstream pull_request now validates <integration-branch>..head_sha instead of HEAD alone, taking the branch name from COMMIT_LINT_MAIN_BRANCH, and degrades to the upstream head commit with a WARN rather than guessing a base. Alongside: --help now documents the no-argument CI mode it had always supported silently, CI wiring detail moves to references/ci-wiring.md, and the description gains negative boundaries. test/test_commit_message_policy.py asserts policy/spec-table equality and uses ast to assert the CI entry imports no regex and reads no file, so a second implementation cannot reappear unnoticed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.2 KiB
CI 接线(CI Wiring)
配置或排查 CI 上的提交信息校验时读本文件。交互式起草提交信息不需要它。
唯一实现
scripts/validate_commit_message.py 是提交信息规则的唯一实现,策略来自
references/commit_policy.json。CI 入口只负责定位并调用它:
python <skill-root>/scripts/validate_commit_message.py
无参数即进入 CI 输入校验模式。退出码原样透传:0 全部通过、1 存在不合规主题、
2 策略/参数/输入错误。
CI 入口不得自行实现校验,不得从 docs/common/commit_message.md 之类的说明性文档
解析 type/emoji 映射。说明性文档是给人读的;把它当机器策略来源会让 CI 与
commit_policy.json 各自演进,而 validator 报告的 Validation 就不再代表实际
拦合并的那道门。本仓库的 .gitea/ci/commit_message_lint.py 是薄 wrapper 范例,
其纪律由 test/test_commit_message_policy.py 机器保证。
事件覆盖范围
以 validate_commit_message.py --help 的当前输出为权威;下表是形状说明。
| 事件 | 取回的主题 |
|---|---|
pull_request* |
pull_request.title 加 base.sha..head.sha 的完整提交范围 |
push |
before..after 完整范围;before 为零对象时按分支图计算新增提交 |
workflow_run |
见下节 |
| 其它 / 本地 | 回退 HEAD 一条 |
已识别事件缺失或损坏 payload 时失败;shallow repository 一律失败。不能用可能截断的
payload commits 数组或计数字段证明范围完整。
workflow_run 编排
workflow_run payload 不含 PR 标题,也不含 before/after,workflow_run.head_sha
是唯一锚点。因此:
- 上游为
pull_request*:取<集成分支>..head_sha的完整范围。集成分支名读$COMMIT_LINT_MAIN_BRANCH(默认main),依次尝试refs/remotes/origin/<名字>与refs/heads/<名字>。 - 其它上游事件:只校验
head_sha一条。 - 集成分支无法解析、上游
head_branch就是集成分支、或计算出的范围为空时,退化为 只校验head_sha并打印WARN,不猜测 base。默认分支的 push 因此只校验被推 上去的那一条,这是可接受的:进入默认分支的路径由 PR 那道门守。
该架构下 PR 标题不参与校验,这是 payload 决定的,不是配置项。完整提交范围校验取代
它,且强度更高——标题一直只是历史的代理,范围校验管的是真正留在历史里的东西。若确实
需要校验 PR 标题,只能在直接响应 pull_request 的那个 workflow 里做。
可信编排
workflow 编排必须来自可信 base/default branch。两条路:
- 直接触发用
pull_request_target。 - 先由
pull_request准备输入,再由默认分支的workflow_run执行。
普通 pull_request 中来自 PR head 的 workflow 即使切到 base worktree,仍可被待审改动
删除或绕过。可信 workflow 必须从可信 base 运行 wrapper、validator 和 policy;只能读取
PR head 的 Git 对象,不能在持有 secret 的步骤 checkout 或执行 PR head 内容。
排查
| 现象 | 处理 |
|---|---|
rc=2 且 ERROR: ...policy... |
部署或配置问题,不是提交信息不合规;检查 policy 路径与 schema |
rc=2 且 ERROR: ...payload... |
事件 payload 缺失或损坏;核对 GITHUB_EVENT_PATH |
rc=2 且 requires complete ... history |
checkout 是 shallow;改为完整 fetch |
checks: 1 subject(s) 但期望是一个范围 |
读 stderr 的 WARN:集成分支未解析,或上游不是 PR |
validator: ... not found |
wrapper 的候选路径与实际部署布局不符 |