拉取请求检查#
以下工作流均位于 .github/workflows/ 目录下。除特别说明外,
均针对目标分支为 master 的拉取请求触发。
1. triage.yaml — PR 打标签#
触发条件: pull_request_target 事件,类型为 opened、synchronize、
reopened、ready_for_review。
pull_request_target 运行在基础仓库(base repository)的上下文中,因此即使是来自
fork 的 PR,它也有权限写入标签。该工作流会:
- 使用
actions/labeler结合.github/labeler.yml配置,根据改动路径打上标签 (例如vendor/NVIDIA、tests、ops/cpp、documentation、examples、ops/alpha—— 其他工作流会依据这些标签决定是否运行)。 - 根据 diff 大小打上尺寸标签(
size/XSmall…size/XLarge)。 - 当 PR 标题匹配特定活动时,添加
competition或KernelGen标签。
unittest.yaml 会先等待 triage.yaml 执行完毕才读取标签,从而确保按标签
门控的作业在判断是否运行之前,标签已经打好。
2. rule-check.yaml — 静态规则检查#
触发条件: pull_request 事件,类型为 opened、reopened、synchronize。
针对 PR 中变更的算子(通过对比 PR 基线与头部提交中 conf/operators.yaml
及相关源码文件的差异得出),运行一系列轻量级 Python 脚本(位于
tools/ci_checks/ 目录下):
| 作业 | 检查内容 |
|---|---|
derive-changed-operators | 计算变更的算子/文件列表,供以下所有作业使用 |
check-operators-yaml | 新增/变更的算子是否在 conf/operators.yaml 中正确注册 |
check-init-exports | __init__.py 中导出的算子是否已注册,以及反向的一致性检查 |
check-kernelgen-tests | 测试文件是否调用了 use_gems()(会绕过与参考实现的比较) |
check-operator-markers | 每个算子是否都有对应的测试文件和匹配的 @pytest.mark.<id> 标记 |
check-aten-operators | operators.yaml 中的 for: 字段是否为合法的 ATen 算子名称 |
check-api-logs | (仅警告,始终以状态码 0 退出)算子是否遵循 API 日志规范 |
check-benchmark-coverage | (仅警告,始终以状态码 0 退出)变更的算子是否有对应的性能测试文件 |
上述大部分作业都通过 if: needs.derive-changed-operators.outputs.has_changes == 'true' 进行门控,对于不涉及算子相关文件改动的 PR(例如纯文档或纯 CI
脚本改动),这些作业会被跳过。
rule-check-required 作业会汇总以上所有作业的结果,并始终运行
(if: always()),将被跳过的上游作业视为通过。分支保护规则应当要求这个
汇总作业,而不是逐个要求单独的子作业 —— 如果某个检查在部分 PR 上会被跳过,
将其设为 required 会导致该检查永久停留在 pending 状态,从而阻塞合并。
ci-report-feishu.yaml 会监听 rule-check 的完成事件(workflow_run),
将结果汇总上报到飞书多维表格(Bitable),即使 PR 来自 fork 仓库也能正常上报
(因为 workflow_run 同样运行在基础仓库上下文中,具备访问 secrets 的权限)。
3. linter.yml — 代码风格检查#
触发条件: pull_request 事件,类型为 opened、edited、reopened、
synchronize;此外推送到 master 分支时也会触发。
运行 pre-commit(与贡献者通过 pre-commit install 在本地执行的钩子相同),
检查 Python 代码格式和基本风格规范。
4. unittest.yaml — 算子与后端测试#
触发条件: pull_request 事件,类型为 opened、synchronize、
reopened、labeled、unlabeled;此外推送到 master 分支和手动触发
(workflow_dispatch)也会执行。
这是主要的测试入口。preprocess 作业首先等待 triage.yaml 执行完毕,
然后计算 PR 的变更文件列表、PR 编号、当前标签,以及按后端划分的测试矩阵
(来自 .github/backends.json,只保留 PR 上带有对应 vendor/* 标签的后端)。
其余所有作业均按标签门控 —— 只有当 PR 带有匹配标签时才会运行:
| 作业 | 触发所需标签 | 功能说明 |
|---|---|---|
build-doc | documentation(且 PR 已合并) | 通过 sync-docs.yaml 同步文档 |
cpp-op | ops/cpp | 构建并运行 C++ 扩展测试套件(cpp-op-test.yaml) |
python-op | tests | 对变更算子运行 tools/test-op.sh(NVIDIA runner) |
examples | examples | 运行 tools/test-examples.sh(端到端模型测试) |
backend-tests | 任意 vendor/* 标签 | 针对每个匹配的后端/runner 运行一次 backend-test.yaml |
alpha-ops | ops/alpha | 在 NVIDIA 上运行实验性算子的测试脚本 |
backend-test.yaml(一个可复用的 workflow_call 工作流)会检出 PR 代码、
运行对应厂商的 GPU 可用性检查、通过 setup-flaggems 组合动作搭建环境,
然后针对 PR 变更的文件运行 tools/test-op.sh(alpha-ops 场景下使用
另一个 test_script)。
其中五个厂商(Hygon、MetaX、MooreThreads、Iluvatar、Kunlunxin)的驱动/运行时
只在厂商容器内可用,因此这些作业需在对应容器中运行。容器镜像、docker run
选项、卷挂载以及 runner 标签,全部来自 .github/backends.json 中各后端条目下的
container 配置块:unittest.yaml 将其读入测试矩阵,并作为 workflow_call
入参透传给 backend-test.yaml。这样容器配置就保存在单一数据源
(.github/backends.json)中,并与下文的按需工作流 command.yaml 共用。
由于这些作业在对应标签缺失时会被跳过,unittest-required 汇总作业会以
if: always() 聚合 preprocess、cpp-op、python-op、examples、
backend-tests、alpha-ops 的结果,使分支保护规则可以要求这一个始终存在
的检查,而不必逐个要求那些按标签门控的作业。
unittest.yaml 的 python-op、examples,以及 cpp-op-test.yaml、
backend-test.yaml 中的作业,会先独立执行一次允许失败的
actions/checkout,再调用 checkout-retry。该组合动作内部最多尝试检出
3 次(首次检出加最多 2 次重试,每次重试前等待 30 秒),因此这类 PR 测试
作业合计最多可尝试检出 4 次。
rule-check.yaml 和 linter.yml 均将 robust-checkout 的 rounds
设为 30(动作默认值为 3)。每轮先尝试 SSH(有密钥时),再尝试 HTTPS;
任一链路成功就结束,密钥为空时跳过 SSH。每条链路的连接探测最多 10 秒,
fetch 的硬超时为 180 秒。HTTP fetch 若连续 20 秒低于 20 KiB/s 也会中止;
SSH 每隔 5 秒发送 keepalive,连续 2 次无响应则中止。
轮次之间没有固定等待。“30 轮”指链路轮转次数,并非重试检出 30 次;
上述 4 次检出上限不适用于这两个工作流。
5. 按需触发与评论触发的工作流#
以下工作流响应 PR 下的 issue_comment 事件,任何具有写权限的用户都可以
通过评论触发:
command.yaml(/test <算子名>:<runner>) —— 检出 PR 代码(包括来自 fork 的 PR,通过github/command设置allow_forks: true实现),在指定 runner 上运行指定算子的测试,并将结果(对于已有算子,还包括改动前后的 对比)以 PR 评论的形式发布。fix-sort.yaml(/fix-sort) —— 使用来自可信master分支的tools/ci_checks/sort_exports.py --fix脚本对 PR 分支执行修复, 如有变更则自动提交并推送,同时评论说明处理结果。
command.yaml 包含一个通用作业,外加每个容器化厂商各一个作业(Hygon、MetaX、
MooreThreads、Iluvatar、Kunlunxin)。由于该工作流由 issue_comment 而非
pull_request 触发,默认的检出不会落在 PR 分支上,因此每个作业都通过
checkout-pr 组合动作里的 gh pr checkout 显式检出 PR 分支。各厂商作业从
.github/backends.json 中相同的 container 配置块解析容器镜像、选项和 runner
标签(在 preprocess 中查表),因而容器配置不会在 command.yaml 和
backend-test.yaml 之间重复。共享的步骤逻辑放在 .github/actions/ 下的组合
动作中:
| 组合动作 | 用途 |
|---|---|
checkout-pr | 若缺失则安装 gh CLI(按 runner 的 CPU 架构选择对应二进制),再 gh pr checkout 检出 PR 分支 |
setup-flaggems | 针对该后端运行 setup.sh 及 GPU 可用性检查 |
ondemand-test | 运行单算子精度/性能对比、上传结果产物并发布 PR 评论 |
设置 Required 状态检查#
在为 master 配置分支保护规则或仓库 Ruleset 时,对于存在条件判断
(if:)或按标签门控作业的工作流,应优先选择汇总(gate)作业,而不是
单独的子作业:
rule-check / rule-check-requiredunittest / unittest-requiredlinter / code-style(该作业未被门控,可以直接安全地设为 required)
如果将某个在部分 PR 上会被 GitHub Actions 合理跳过的作业设为 required, 该检查会永久停留在"Expected"状态,从而无限期阻塞 auto-merge —— 因为在 required-check 的判定逻辑中,"跳过(skipped)"并不等同于"通过(passed)"。