跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
  • 世界
  • 用户
  • 群组
皮肤
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(不使用皮肤)
  • 不使用皮肤
折叠

乐达

  1. 主页
  2. 团队公告
  3. 下游触发分支规则(FANOUT_BRANCH 单原则)

下游触发分支规则(FANOUT_BRANCH 单原则)

已定时 已固定 已锁定 已移动 团队公告
2 帖子 2 发布者 6 浏览 1 关注中
  • 从旧到新
  • 从新到旧
  • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • Z 离线
    Z 离线
    zhongfangxiong
    写于 最后由 zhongfangxiong 编辑
    #1

    下游触发分支规则(FANOUT_BRANCH 单原则)

    1. 背景

    在多仓库、多级触发(A -> B -> C)的场景中,如果每一跳都“按当前项目的运行分支”去触发下游,很容易发生分支漂移。

    本规则的目标:

    • 200+ 项目尽量不改各自的 .gitlab-ci.yml
    • 不使用 GitLab API Token
    • 触发链路稳定、可预测

    2. 唯一原则:FANOUT_BRANCH 贯穿

    我们定义一个变量:FANOUT_BRANCH,表示“本次触发链路从最上游开始的分支”。

    生成/继承规则:

    • 若上游已传入 FANOUT_BRANCH,则下游沿用该值
    • 否则默认 FANOUT_BRANCH = CI_COMMIT_BRANCH

    每次触发下游时,都必须继续传递 FANOUT_BRANCH,从而保证多级触发不会漂移。

    3. 下游触发分支的决定规则

    3.1 显式指定优先(最重要)

    如果项目在 variables: 中显式写了 DOWNSTREAM_BRANCH,例如:

    variables:
      DOWNSTREAM_PROJECT: platform/deploy/blazor-app
      DOWNSTREAM_BRANCH: master
    

    则表现为:

    • 永远触发下游的 master 分支
    • 即使当前上游在 feature/LT-49、bugfix/* 等分支上运行,也不会触发同名分支
    • FANOUT_BRANCH 仍会被传递到下游,但仅用于链路追踪/后续再触发,不参与本次分支选择

    3.2 未显式指定时的默认行为

    如果未显式设置 DOWNSTREAM_BRANCH,则默认:

    • DOWNSTREAM_BRANCH = FANOUT_BRANCH

    即:上游在 feature/LT-49 运行时触发下游 feature/LT-49;上游在 master 运行时触发下游 master。

    4. 关于 master/main

    在“不使用 Token、不调用 API”的前提下,我们无法在触发前自动判断下游默认分支是 master 还是 main。

    治理建议:

    • 公司内尽量统一主干命名为 master
    • 若少数仓库历史上使用 main,建议一次性调整为 master,之后无需在 200+ 项目侧维护差异

    5. 适用范围

    • NuGet / IIS / Docker 等流水线,只要通过 common-ci 的 downstream trigger 模板触发下游,本规则均适用。

    6. 常见问题(FAQ)

    6.1 上游是 develop(或 feature/*),下游只有 master,会怎么样?

    在未显式配置 DOWNSTREAM_BRANCH 的情况下,默认行为是:

    • DOWNSTREAM_BRANCH = FANOUT_BRANCH
    • FANOUT_BRANCH 默认等于当前上游的 CI_COMMIT_BRANCH

    因此:

    • 上游在 develop 跑时,会尝试触发下游的 develop
    • 若下游仓库没有 develop 分支(只有 master),则 trigger: 作业会失败
    • 因为我们使用 strategy: depend,上游流水线会在“触发下游”阶段失败

    治理方式(二选一):

    • 方式 A(推荐,稳定)
      • 对“只有主干分支”的下游仓库,在上游项目显式配置 DOWNSTREAM_BRANCH: master
      • 这样不管上游在哪个分支跑,下游都只触发 master
    • 方式 B(统一分支体系)
      • 在下游仓库创建对应分支(例如创建 develop),保证分支存在
      • 适用于需要严格“同分支联动”的仓库
    1 条回复 最后回复
    0
    • A 离线
      A 离线
      admin
      写于 最后由 编辑
      #2

      下游触发分支选择:现象、根因与最终方案(仅 develop/master)

      背景与目标

      我们在 NuGet 组件发布流水线中使用下游触发(trigger downstream pipeline)来联动发布/同步多个项目。

      核心目标是:

      • 让下游触发分支选择可预测、可维护、可审计。
      • 避免因为 GitLab Token 权限差异导致的“误判分支不存在”“偶发失败”等不稳定行为。
      • 适配跨项目、跨实例同步(common-ci 同步到多个 GitLab 实例)的场景。

      现象(问题表现)

      在 trigger_downstream_pipeline 作业中出现以下典型问题:

      • 现象 A:作业过早触发

        • 流水线还未完成 push/update 等步骤,下游就被触发。
      • 现象 B:下游明明存在分支,却提示分支不存在

        • 例如下游有 develop,但 job 日志显示“分支不存在”。
      • 现象 C:HTTP 401 Unauthorized

        • 使用 CI_JOB_TOKEN 调用 GitLab API 触发下游 pipeline 时返回 401。
        • 说明默认情况下 CI_JOB_TOKEN 不具备跨项目触发的权限。
      • 现象 D:Reference not found / downstream pipeline can not be created

        • trigger 使用的 branch 变量为空或未按预期注入,导致 GitLab 认为 ref 不存在。

      根因分析

      1. GitLab 原生 trigger: 的能力边界

      • 原生 trigger: 只能触发一个确定的 project + branch。
      • 它不会做“分支不存在则 fallback”这种动态选择。

      因此,如果要做“某项目没有分支就改触发另一个分支、后续再恢复原分支”的行为,必须:

      • 预先知道下游是否存在该分支(需要 API),或
      • 直接尝试触发并解析失败原因(需要 API),或
      • 人工/静态配置规则(每项目一个开关),或
      • 制定组织规范(所有项目都具备统一分支)。

      2. 跨项目权限与 Token 复杂度

      如果使用 API 触发下游(/api/v4/projects/:id/pipeline):

      • CI_JOB_TOKEN 在多数场景下对跨项目 API 权限不足(401)。
      • 使用 GITLAB_API_TOKEN(Project/Group/Personal Access Token)可以解决,但引入:
        • Token 分发与轮换成本
        • 安全风险与合规审计成本
        • 多实例同步时的配置复杂度

      3. 变量注入顺序与 artifacts 依赖

      我们使用 dotenv artifacts 在 setup 阶段写入变量(如 FANOUT_BRANCH、DOWNSTREAM_BRANCH)。

      如果 trigger job 没有正确 needs 对应的 setup job(且 artifacts: true),就可能拿不到变量,导致:

      • $DOWNSTREAM_BRANCH 为空
      • trigger 触发时报 Reference not found

      方案对比(做过的选择)

      方案 1:智能分支(API + fallback)

      • 思路:优先触发“根分支”,失败再 fallback 到 develop/master。
      • 优点:理论上能实现更复杂的链路行为。
      • 缺点:
        • 需要跨项目 API 权限,CI_JOB_TOKEN 往往不够(401)
        • Token 配置与安全治理成本高
        • 失败原因多样(401/404/网络/权限策略),可维护性差

      方案 2:自建服务(分支查询/代理触发)

      • 思路:将 GitLab token 收拢到内部服务,CI 只调用内部服务。
      • 优点:可控、安全面可收敛。
      • 缺点:引入额外系统:
        • 部署与运维成本
        • 高可用/限流/审计等需求
        • 增加链路复杂度

      方案 3(最终采用):最简单方案(无 API,仅 develop/master)

      结论:采用方案 3。

      • 只在 develop/master 两者之间选择分支。
      • 在 setup 阶段一次性确定“触发链根分支”,并通过 dotenv 跨项目传递。
      • trigger 使用 GitLab 原生 trigger:,不使用 API,不依赖 token。

      该方案的关键前提:所有参与链路的项目必须同时存在 develop 和 master 分支。

      这项前提换来的是:

      • 不需要任何额外权限与 token
      • 行为稳定、可预测
      • 维护成本最低

      最终方案设计

      1. 根分支归一化(setup 阶段)

      在 setup_version(.version_setup)阶段:

      • 读取触发源:FANOUT_BRANCH(上游传递)或 CI_COMMIT_BRANCH(当前)
      • 归一化为:
        • master/main/hotfix/* → master
        • 其他 → develop
      • 写入 dotenv:
        • FANOUT_BRANCH=<develop|master>
        • DOWNSTREAM_BRANCH=<develop|master>(如果用户未显式指定)

      2. 下游触发(trigger 阶段)

      在 .trigger-downstream 中:

      • 使用 GitLab 原生:
        • trigger.project: $DOWNSTREAM_PROJECT
        • trigger.branch: $DOWNSTREAM_BRANCH
      • 同时向下游继续传递:
        • FANOUT_BRANCH
        • FANOUT_FROM
        • STOP_FANOUT

      并通过 needs 确保拿到 setup 阶段的 dotenv:

      • needs: setup_global_var (artifacts: true)

      代码改动点(common-ci)

      • shared/version-setup.yml

        • 在 version.env 中写入归一化后的 FANOUT_BRANCH,并默认填充 DOWNSTREAM_BRANCH。
      • nuget/7-trigger-downstream.yml

        • 恢复为原生 trigger:
        • needs 增加 setup_global_var(带 artifacts: true)以确保 DOWNSTREAM_BRANCH 可用

      使用与约束

      • 组织规范(必须执行)

        • 所有参与链路的仓库必须同时存在 develop 与 master 分支。
      • 项目侧配置(可选)

        • 在 .gitlab-ci.yml 中配置:
          • DOWNSTREAM_PROJECT:下游项目路径
        • 一般无需配置 DOWNSTREAM_BRANCH,默认由上游归一化规则决定。

      常见问题(FAQ)

      Q1:为什么不继续做“智能分支 + fallback”?

      因为需要 API 触发或分支判断,而跨项目 token 权限与安全治理成本过高,且多实例同步场景下不可控因素更多。

      Q2:为什么会出现 Reference not found?

      多数情况下是 trigger job 没有拿到 setup 阶段的 dotenv(变量未注入),导致 branch 为空/错误。

      Q3:这个方案还能实现“某项目只有 master,但后续又想回到 develop”吗?

      不能。

      不使用 API 的前提下无法判断下游是否存在某分支,因此无法对“每一跳”做动态选择。

      要支持这种行为,必须回到 API 方案或引入项目级配置。

      1 条回复 最后回复
      0
      回复
      • 在新帖中回复
      登录后回复
      • 从旧到新
      • 从新到旧
      • 最多赞同


      • 登录

      • 登录或注册以进行搜索。
      • 第一个帖子
        最后一个帖子
      0
      • 版块
      • 最新
      • 标签
      • 热门
      • 世界
      • 用户
      • 群组