第40章|GitLab CI 规则与触发:rules、only/except、MR pipelines

上一章铺好了铁轨与车厢;本章管的是信号灯——什么时候开车、哪节车厢跟哪趟班列。 你会掌握现代 GitLab 的 rules(以及为何尽量告别 only/except), 理解 Merge Request pipeline 与分支流水线的差异,并用 workflow 级规则把“无效 pipeline”挡在站台外,省下 Runner 分钟与研发注意力。

workflow

Pipeline 生不生

  • workflow:rules
  • skip vs no pipeline
  • cost guardrails
job rules

Job 进不进图

  • if / when
  • changes
  • manual / delayed
MR

合并请求语境

  • merge_request_event
  • detached vs added
  • fork 安全

1. 为什么要“收束触发”?

每次 push 都跑全套集成,就像每踩一脚油门都拉满十二节车厢:短期看似省事,长期会拖垮队列、放大噪声、让“红构建”被习惯性忽略。 专业做法是把触发拆成三层:是否创建 pipeline(workflow)、哪些 job 进入 DAG(job rules)、 哪些路径变更才值得跑重任务changes 等)。三者叠加,才能把分钟数与心智成本花在刀刃上。

Two-layer gating: workflow (pipeline) vs rules (jobs) Event carries CI_PIPELINE_SOURCE; YAML decides what runs Events push · tag · MR schedule · web · api CI_PIPELINE_SOURCE merge_request_event push / pipeline / … workflow: rules Create pipeline? if match → run pipeline else → skip (no jobs) Stops “empty” pipelines early Saves queue + runner minutes Per-job rules Each job: include / manual / never light: lint + unit rules + changes: paths heavy: e2e / deploy manual or protected branch when: manual → play button; delayed → timer Fine-grained without spawning useless pipelines
图 1:先决定“整条 pipeline 要不要出现”,再决定“图里有哪些 job”。两层分工,成本与清晰度最好。

2. rules:现代默认,可读又可组合

rules 是一个有序列表:从上到下匹配,命中第一条即停止。每条可含 ifchangesexists 等条件,并用 when 指定 on_successmanualdelayednever 等。 与旧式 only/except 相比,rules 更容易表达“MR 上自动跑、主分支上手动批准”这类分支组合逻辑。

mr_checks:
  stage: test
  script:
    - npm ci
    - npm test
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

deploy_prod:
  stage: deploy
  script:
    - ./deploy.sh production
  rules:
    - if: $CI_COMMIT_TAG
      when: manual
注意:若某 job 的 rules 全部未命中,该 job 不会出现在 pipeline 图里(与“出现但跳过”不同)。 调试时若“找不到 job”,先检查 rulesworkflow 是否把 pipeline 或 job 提前挡掉。

3. workflow: rules:挡在 DAG 之前的闸机

放在顶层 workflow: 下的 rules 决定是否创建 pipeline。 典型用途:只允许 main、MR、或带 tag 的提交创建流水线;其它情况直接不生成 pipeline,连“空跑”都不出现。

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_TAG
    - when: never

最后一条 when: never 作为兜底拒绝:上面都不匹配时,GitLab 不会创建 pipeline(文档中常称 “skip pipeline creation”)。 这与 job 级 rules: - when: never 的语义层级不同:一个管“有没有 pipeline”,一个管“图里有没有该 job”。

4. Merge Request pipeline:不是“多跑一遍”,而是“换语境”

CI_PIPELINE_SOURCEmerge_request_event 时,GitLab 为 MR 创建专用流水线。 你会看到与“普通分支 push”不同的变量(如 CI_MERGE_REQUEST_IIDCI_MERGE_REQUEST_TARGET_BRANCH_NAME), 并可用 only: - merge_requests 或等价的 rules 把代码评审与合并门禁绑在一起。 MR pipeline 让你能在合并前验证“合进去之后会不会炸”,而不是只验证源分支孤立状态。

Push pipeline vs Merge request pipeline Branch push (CI_PIPELINE_SOURCE=push) Validates tip of feature branch after git push feature/x Good for fast feedback on every commit May differ from post-merge result MR pipeline (merge_request_event) GitLab ties checks to the MR object + target context source → target main Use for: required checks, MR-only jobs, “mergeability”
图 2:分支 push 像“单车试骑”;MR pipeline 像“并线彩排”——面向合并结果,更适合做合并门禁。
Fork 与不可信贡献:若允许 fork MR 在 upstream 跑 pipeline,需结合项目设置限制 secrets、使用保护分支、 审批流水线等策略;否则恶意 PR 可能窃取 CI 变量。把“开源协作”与“机密边界”一起设计,是平台工程职责。

5. rules:changes:按路径过滤重任务

对集成测试、镜像构建、文档站发布等“昂贵 job”,可用 changes 限制:仅当某些 glob 变更时才自动运行,否则 when: never 或交给 manual。 注意 changes 在部分 pipeline 类型(如某些 schedule / push 组合)行为会受文档约束,上线前用真实 MR 验证。

heavy_e2e:
  stage: test
  script:
    - npm run e2e
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      changes:
        - src/**/*
        - package.json
    - when: never

6. only / except:遗产语法,建议迁移

仍能在老仓库见到 only: - branchesexcept: - main。 官方长期推荐迁移到 rules:表达能力更强,语义更接近“条件列表”,也减少与 workflow 组合时的意外。 读旧 YAML 时记住:only/exceptrules 不要混在同一 job 上(应统一风格)。

维度 only / except rules
匹配模型 黑白名单分支/标签/MR 有序 if + when,可组合变量
手动/延迟 需额外关键字配合 同一结构内 when: manual
维护性 复杂场景易绕 适合平台统一模板

7. 常用 CI_PIPELINE_SOURCE 心智表

规则条件里最常引用的是 $CI_PIPELINE_SOURCE(以及分支名、tag、MR 变量)。下面是一张简表,便于写 if 时快速对齐。

Source (示例) 典型场景
push 分支或 tag 推送
merge_request_event MR 创建/更新触发的 MR pipeline
schedule 定时流水线
web UI 手动 “Run pipeline”
api / trigger 外部系统或 pipeline 触发
Recipe: start from the noisiest cost center Need pipeline? workflow:rules Per-job rules Add changes: for heavy jobs Protect deploy with manual / protected refs Iterate until runner minutes & alerts look sane
图 3:从“是否创建 pipeline”收敛到“每个 job 的出现条件”,再对重任务加路径过滤——典型治理迭代顺序。

8. 与 GitHub Actions 的对照(触发维度)

Actions 用 on: 绑定事件;GitLab 用 workflow + rules + 内置变量表达相近意图。 概念上可把 workflow:rules 类比为“是否启动 workflow”,把 job rules 类比为 job 级 if:(GitHub 也在 job 层支持条件)。

9. 本章清单

  1. 为仓库加顶层 workflow:rules,拒绝无关分支的 pipeline 创建。
  2. 把所有 only/except 逐步迁移到 rules,统一团队模板。
  3. 区分 MR pipeline 与 push pipeline,合并门禁绑定 merge_request_event
  4. 对昂贵 job 使用 changes 或 manual,并监控 Runner 使用曲线。
  5. 梳理 fork / 外部贡献场景下的流水线信任模型与变量暴露面。
← 上一章:GitLab CI 入门 下一章:缓存与制品 →