GitLab 项目的流水线
gitlab-org/gitlab 项目(以及 dev 实例)的流水线配置在通常的 .gitlab-ci.yml 中,该文件本身包含 .gitlab/ci/ 下的文件以方便维护。
我们正努力尽可能多地“自用”(dogfood)GitLab 的 CI/CD 功能和最佳实践。
不要在 gitlab-org/gitlab 的流水线中使用 CI/CD 组件,除非它们在 dev.gitlab.com 实例上被镜像。CI/CD 组件在不同实例间无法工作,若未存在于该实例上,会导致 dev.gitlab.com 镜像上的流水线失败(参考 导致流水线失败的案例)。
流水线层级
处于积极开发中:更多信息请参见 epic 58。
合并请求通常会运行多个 CI/CD 流水线。根据合并请求在审批流程中的位置,我们会触发不同类型的流水线。我们将这类流水线称为 流水线层级。
目前我们有三个层级:
pipeline::tier-1:合并请求无审批pipeline::tier-2:合并请求至少有一个审批,但仍需更多审批pipeline::tier-3:合并请求已获得所有必需的审批
通常,流水线层级越低,流水线应越快;层级越高,流水线通过运行更多测试来提供更高置信度的能力应越强。
有关实现的更多信息,请参见 合并请求流水线中引入“层级” epic。
合并请求批准前的预测性测试作业
为降低流水线成本并缩短作业时长,在合并请求批准前,流水线将运行一组可能因合并请求变更而失败的 RSpec 和 Jest 测试。
合并请求获批后,流水线将包含完整的 RSpec 和 Jest 测试。这将确保在合并请求合并前所有测试均已运行。
GitLab 项目测试依赖关系概述
要理解预测性测试作业如何执行,需了解 GitLab 代码(前端和后端)与对应测试(Jest 和 RSpec)之间的依赖关系。这种依赖可通过以下图表可视化:
flowchart LR
subgraph frontend
fe["前端代码"]--由-->jest
end
subgraph backend
be["后端代码"]--由-->rspec
end
be--生成-->fixtures["前端 fixture"]
fixtures--用于-->jest
总结来说:
- RSpec 测试依赖于后端代码。
- Jest 测试同时依赖于前端和后端代码(后者通过前端 fixture)。
预测性测试仪表板
detect-tests CI 作业
大多数 gitlab-org/gitlab 的 CI/CD 流水线会在 prepare 阶段运行一个 detect-tests CI 作业,以检测给定 MR 变更的文件为基础,确定应运行哪些后端/前端测试。
detect-tests 作业会创建许多文件,其中包含应运行的测试。这些文件将在流水线的后续作业中被读取,仅执行这些测试。
RSpec 预测性作业
确定合并请求中的预测性 RSpec 测试文件
为识别合并请求中可能失败的 RSpec 测试,我们使用 动态映射 和 静态映射。
动态映射
首先,我们使用了 test_file_finder gem,其动态映射策略来自 Crystalball gem(查看使用位置,以及我们在Crystalball中使用的映射策略)。
除了 test_file_finder 外,我们还添加了多个高级映射来检测更多需运行的测试:
FindChanges(!74003)- 自动检测后端变更时应运行的Jest测试(通过前端fixture)
PartialToViewsMappings(#395016)- 当MR中修改了视图中包含的Rails partial时,运行视图规格测试
JsToSystemSpecsMappings(#386754)- 如果MR中修改了JavaScript文件,运行特定系统规格测试
GraphqlBaseTypeMappings(#386756)- 若GraphQL类型类发生变更,尝试识别可能包含该类型的其他GraphQL类型并运行其规格测试
ViewToSystemSpecsMappings(#395017)- 当视图被修改时,尝试找到能测试该代码区域的特性规格测试
ViewToJsMappings(#386719)- 若JS文件被修改,尝试识别覆盖该JS组件的系统规格测试
FindFilesUsingFeatureFlags(#407366)- 若功能开关被修改,检查哪些Ruby文件包含了该功能开关,并将其加入detect-tests CI作业的变更文件列表。随后作业会基于这些变更文件检测应运行的前端/后端测试。
静态映射
我们使用 test_file_finder gem,并通过 tests.yml 文件 维护静态映射,用于无法通过动态映射处理的特殊情况(查看使用位置)。
test映射 包含源文件到测试文件的映射表,具体取决于源文件。
特殊情况
此外,在以下几种情况下我们会始终运行完整的RSpec测试:
- 当合并请求设置了
pipeline:run-all-rspec标签时。此标签将触发所有RSpec测试,包括在as-if-foss作业中运行的测试。 - 当合并请求设置了
pipeline:mr-approved标签,且代码变更满足backend-patterns规则时。请注意,此标签由审核自动化在合并请求被任意审核人批准时分配,不建议手动应用此标签。 - 当合并请求由自动化创建时(例如Gitaly更新或针对稳定分支的MR)
- 当合并请求创建于安全镜像仓库中
- 当任何CI配置文件被修改时(例如
.gitlab-ci.yml或.gitlab/ci/**/*)
您是否遇到过后端预测测试的问题?
如果是这样,请查看开发分析 RUNBOOK 关于预测测试,了解如何处理预测测试问题。此外,如果您发现了任何测试选择缺口,请告知 @gl-dx/development-analytics,以便我们采取必要步骤优化测试选择。
Jest 预测任务
确定合并请求中的预测性 Jest 测试文件
为了识别在合并请求中可能失败的 jest 测试,我们将所有更改文件的列表传递给 jest,使用 --findRelatedTests 选项。
在此模式下,jest 会解析与更改文件相关的所有依赖项,包括在依赖链中包含这些文件的测试文件。
异常情况
此外,在某些情况下我们会始终运行完整的 Jest 测试:
- 当合并请求上设置了
pipeline:run-all-jest标签时 - 当合并请求由自动化创建时(例如 Gitaly 更新或针对稳定分支的 MR)
- 当合并请求在安全镜像中创建时
- 当相关 CI 配置文件被修改时(
.gitlab/ci/rules.gitlab-ci.yml、.gitlab/ci/frontend.gitlab-ci.yml) - 当任何前端依赖文件被修改时(例如
package.json、yarn.lock、config/webpack.config.js、config/helpers/**/*.js) - 当任何 vendor 的 JavaScript 文件被修改时(例如
vendor/assets/javascripts/**/*)
完整 Jest 测试的 rules 定义位于 .frontend:rules:jest 中,详情见 rules.gitlab-ci.yml。
您是否遇到过前端预测测试的问题?
如果是这样,请查看开发分析 RUNBOOK 关于预测测试,了解如何处理预测测试问题。
Fork 管道
对于 fork 管道,我们仅运行预测性的 RSpec 和 Jest 作业,除非 MR 上设置了 pipeline:run-all-rspec 标签。目标是减少 fork 管道消耗的计算配额。
详见实验问题。
合并请求管道中的快速失败作业
为了在合并请求破坏现有测试时提供更快的反馈,我们实现了快速失败机制。
在合并请求管道中,会并行添加一个 rspec fail-fast 作业到所有其他 rspec 作业中。该作业运行与合并请求变更直接相关的测试。
如果这些测试中有任何一个失败,rspec fail-fast 作业会失败,触发 fail-pipeline-early 作业运行。fail-pipeline-early 作业会:
- 取消当前正在运行的管道及所有进行中的作业。
- 将管道状态设置为
failed。
例如:
graph LR
subgraph "准备阶段";
A["detect-tests"]
end
subgraph "测试阶段";
B["jest"];
C["rspec migration"];
D["rspec unit"];
E["rspec integration"];
F["rspec system"];
G["rspec fail-fast"];
end
subgraph "测试后阶段";
Z["fail-pipeline-early"];
end
A --"工件:测试文件列表"--> G
G --"失败时"--> Z
如果与合并请求相关的测试文件超过 10 个,rspec fail-fast 将不会执行操作。这可以防止 rspec fail-fast 的持续时间超过平均 rspec 作业时长,从而违背其初衷。
此数字可通过设置名为 RSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD 的 CI/CD 变量来覆盖。
在合并请求管道中重新运行之前失败的测试
为了缩短解决合并请求失败测试后的反馈时间,rspec rspec-pg16-rerun-previous-failed-tests 和 rspec rspec-ee-pg16-rerun-previous-failed-tests 作业会运行前一次 MR 管道中失败的测试。
该功能于 2021 年 8 月 25 日引入,详见 https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69053。
如何重新运行失败的测试
detect-previous-failed-tests作业(prepare阶段)会检测与上一个 MR 管道中失败的 RSpec 作业相关的测试文件。rspec rspec-pg16-rerun-previous-failed-tests和rspec rspec-ee-pg16-rerun-previous-failed-tests作业将运行由detect-previous-failed-tests作业收集的测试文件。
graph LR
subgraph "prepare 阶段";
A["detect-previous-failed-tests"]
end
subgraph "测试阶段";
B["rspec rspec-pg16-rerun-previous-failed-tests"];
C["rspec rspec-ee-pg16-rerun-previous-failed-tests"];
end
A --"工件:测试文件列表"--> B & C
合并列车
当前使用情况
目前,合并列车管道不会运行任何测试:它们仅执行在合并列车启用前就已存在的 “合并合并请求” 指南,但我们此前难以强制执行这些规则。
合并列车管道会运行单个 pre-merge-checks 作业,确保合并前的最新管道满足:
我们开启了一个反馈问题 来迭代此方案。
下一步迭代
我们开启了一个专门的问题来讨论合并列车的下一步迭代,以便实际在合并列车管道中运行测试。
启用合并列车运行“完整”测试管道的挑战
为什么需要“稳定”的默认分支?
如果默认分支不稳定(例如,默认分支的 CI/CD 管道频繁失败),那么在故障合并请求管道之后添加的所有合并请求管道都必须被取消并重新加入列车,这会导致合并列车很长时产生大量延迟。
默认分支需要有多稳定?
我们没有具体数字,但需要有更好的关于 flaky 测试失败和基础设施失败的数据(参见主分支故障事件 RCA 仪表板)。
某些合并请求的更快反馈
修复损坏的主分支
当你需要修复损坏的主分支,你可以给合并请求添加 pipeline::expedited 标签以加速运行在该合并请求上的管道。
注意,合并请求还需要设置 master:broken 或 master:foss-broken 标签。
回滚 MR
为了使你的回滚 MR 更快,请在创建合并请求之前使用回滚 MR 模板。它会应用 pipeline::expedited 标签和其他会加速该合并请求上运行的管道的标签。
pipeline::expedited 标签
当此标签被分配时,CI/CD 管道的以下步骤将被跳过:
e2e:test-on-omnibus-ee作业。rspec:undercoverage作业。- 整个评审应用流程。
将标签应用到合并请求,并为 MR 运行新的管道。
测试作业
我们有针对每个测试级别的专用作业,每个作业根据你在合并请求中做出的更改来运行。
如果你想强制运行所有 RSpec 作业而不管你的更改,可以向合并请求添加 pipeline:run-all-rspec 标签。
强制在仅与文档相关的 MR 上运行所有作业会导致缺少前置作业并引发错误
端到端作业
有关更多信息,请参阅端到端测试管道。
可观测性端到端作业
GitLab 可观测性后端 拥有专门的端到端测试,针对 GitLab 实例运行。这些测试旨在确保 GitLab 与可观测性后端的集成正常工作。
GitLab 流水线有专门的作业(参见 observability-backend.gitlab-ci.yml),可以从 GitLab 合并请求(MR)执行。这些作业将触发 GitLab 可观测性后端流水线上的端到端测试,针对从 GitLab MR 分支构建的 GitLab 实例。这些作业有助于确保正在审查的 GitLab 变更不会破坏 GitLab 可观测性后端流水线上的端到端测试。
有两个可观测性端到端作业:
e2e:observability-backend-main-branch:针对 GitLab 可观测性后端的主分支执行测试。e2e:observability-backend:针对与 MR 分支同名的 GitLab 可观测性后端分支执行测试。
可观测性 E2E 作业仅自动触发于涉及相关文件的合并请求,例如 lib/gitlab/observability/ 目录中的文件或与可观测性功能相关的特定配置文件。
要手动运行这些作业,您可以在合并请求中添加 pipeline:run-observability-e2e-tests-main-branch 或 pipeline:run-observability-e2e-tests-current-branch 标签。
在以下示例工作流中,开发者创建一个涉及可观测性代码的 MR 并使用可观测性端到端作业:
- 开发者创建一个涉及可观测性代码的 GitLab MR。该 MR 自动执行
e2e:observability-backend-main-branch作业。 - 如果
e2e:observability-backend-main-branch失败,则意味着要么 MR 破坏了某些东西(需要修复),要么 MR 的变更导致需要更新端到端测试。 - 要更新端到端测试,开发者应:
- 开发者应在 GitLab MR 上添加
pipeline:run-observability-e2e-tests-current-branch标签,并等待e2e:observability-backend作业成功。 - 如果
e2e:observability-backend成功,开发者可以合并这两个 MR。
此外,开发者可以手动添加 pipeline:run-observability-e2e-tests-main-branch 以强制 MR 运行 e2e:observability-backend-main-branch 作业。这在变更未被视为与可观测性相关的文件时很有用。
在某些情况下,开发者可能需要跳过这些测试。要跳过测试:
- 对于 MR,应用
pipeline:skip-observability-e2e-tests标签。 - 对于整个项目,设置 CI 变量
SKIP_GITLAB_OBSERVABILITY_BACKEND_TRIGGER。
评审应用作业
start-review-app-pipeline 子流水线会部署评审应用,并根据变更自动运行端到端测试,在其他情况下则是手动的。有关具体规则列表,请参阅 rules.gitlab-ci.yml 中的 .review:rules:start-review-app-pipeline。
如果您想强制部署评审应用而不考虑您的变更,可以向合并请求添加 pipeline:run-review-app 标签。
有关更多信息,请参阅评审应用专用页面。
模拟开源(FOSS)作业与跨项目下游流水线
为确保相关变更在开源项目中正常工作,在某些情况下我们还会运行:
- 同一流水线中的
* as-if-foss作业 - 跨项目下游开源流水线
* as-if-foss 作业会以“模拟开源”的方式运行 GitLab 测试套件,即仿佛这些作业会在 gitlab-org/gitlab-foss 的上下文中运行。另一方面,跨项目下游开源流水线实际上在开源项目中运行,这应该更接近真实的开源环境。
我们在以下情况运行它们:
- 当合并请求上设置了
pipeline:run-as-if-foss标签时 - 当合并请求创建于
gitlab-org/security/gitlab项目时 - 当 CI 配置文件发生变更时(例如
.gitlab-ci.yml或.gitlab/ci/**/*)
* as-if-foss 作业会额外运行,除了常规的 EE 上下文作业。它们会设置 FOSS_ONLY='1' 变量,并在测试开始前移除 ee/ 文件夹。
跨项目下游开源流水线则模拟将合并请求合并到开源项目的默认分支,同时删除一系列文件。该列表可在 .gitlab/ci/as-if-foss.gitlab-ci.yml 和 merge-train/bin/merge-train 中找到。
其目的是确保变更不会在 gitlab-org/gitlab 同步到 gitlab-org/gitlab-foss 后引发故障。
项目变量中设置的令牌
AS_IF_FOSS_TOKEN:这是一个具有developer角色和write_repository权限的 GitLab 开源(FOSS) 项目令牌,用于推送生成的as-if-foss/*分支。- 注意:安全项目使用相同名称时应使用另一个来自安全开源项目的令牌,这样我们就永远不会将安全变更推送到公共项目。
模拟极狐(JH)跨项目下游流水线
是什么
此流水线也称为 极狐验证流水线,目前允许失败。若发生失败,请遵循 验证流水线失败时该如何处理。
如何运行
start-as-if-jh 作业会触发一个跨项目下游流水线,该流水线以“模拟极狐”的方式运行 GitLab 测试套件,即仿佛流水线会在 GitLab 极狐(JH) 的上下文中运行。这些作业仅在以下情况创建:
- 当对功能标志进行变更时
- 当合并请求上设置了
pipeline:run-as-if-jh标签时
此流水线在 GitLab 极狐验证 项目的生成分支上下文中运行,该项目是 GitLab 极狐镜像 的镜像。
生成分支名称以 as-if-jh/ 为前缀,并包含合并请求中的分支名称。该生成分支基于合并请求分支,此外还添加了从 对应极狐分支 下载的变更,从而使整个流水线模拟极狐环境。
其目的是确保变更不会在 GitLab 同步到 GitLab 极狐(JH) 后引发故障。
何时考虑应用 pipeline:run-as-if-jh 标签
如果一个 Ruby 文件被重命名,并且存在对应的 prepend_mod 行,那么很可能 GitLab 极狐依赖于此,需要相应地重命名它所前置的模块或类。
对应的 JH 分支
你可以在 GitLab JH 上通过在分支名称后附加 -jh 来创建对应的 JH 分支。如果找到了对应的 JH 分支,as-if-jh 流水线会从相应的分支获取文件,而不是从默认分支 main-jh。
目前,CI 会尝试从 GitLab JH 镜像 获取分支,因此新 JH 分支传播到镜像可能需要一些时间。
虽然 GitLab JH 验证 是 GitLab JH 镜像 的镜像,但它除了默认的 main-jh 外,不包含任何对应的 JH 分支。这就是为什么当我们想要获取对应的 JH 分支时,应该从主镜像而不是验证项目获取的原因。
如何配置 as-if-JH 流水线
整个过程如下所示:
我们仅在存在依赖项更改时运行 sync-as-if-jh-branch。
flowchart TD
subgraph "JiHuLab.com"
JH["gitlab-cn/gitlab"]
end
subgraph "GitLab.com"
Mirror["gitlab-org/gitlab-jh-mirrors/gitlab"]
subgraph MR["gitlab-org/gitlab 合并请求"]
Add["add-jh-files 任务"]
Prepare["prepare-as-if-jh-branch 任务"]
Add --"下载产物"--> Prepare
end
subgraph "gitlab-org-sandbox/gitlab-jh-validation"
Sync["(*可选) 在 as-if-jh-code-sync 分支上的 sync-as-if-jh-branch 任务"]
Start["在 as-if-jh/* 分支上的 start-as-if-jh 任务"]
AsIfJH["as-if-jh 流水线"]
end
Mirror --"使用 master 和 main-jh 拉取镜像"--> gitlab-org-sandbox/gitlab-jh-validation
Mirror --"使用 ADD_JH_FILES_TOKEN 下载极狐文件"--> Add
Prepare --"使用 AS_IF_JH_TOKEN 推送 as-if-jh 分支"--> Sync
Sync --"使用 AS_IF_JH_TOKEN 推送 as-if-jh 分支"--> Start
Start --> AsIfJH
end
JH --"使用对应的 JH 分支拉取镜像"--> Mirror
项目变量中设置的令牌
ADD_JH_FILES_TOKEN:这是 GitLab JH 镜像 项目的令牌,具有read_api权限,以便能够下载极狐文件。AS_IF_JH_TOKEN:这是 GitLab JH 验证 项目的令牌,具有developer角色和write_repository权限,以推送生成的as-if-jh/*分支。
我们如何生成 as-if-JH 分支
首先,add-jh-files 任务会从对应的 JH 分支下载所需的极狐文件,并将其保存为产物。接着,prepare-as-if-jh-branch 任务会从合并请求分支创建一个新分支,提交变更,最后将该分支推送到 验证项目。
可选地,如果合并请求有依赖项的更改,我们会额外运行 sync-as-if-jh-branch 任务,以触发验证项目中 as-if-jh-code-sync 分支 的下游流水线。此任务将执行与 极狐代码同步 相同的过程,确保在运行验证流水线之前,依赖项的更改可以应用到 as-if-jh 分支。
如果没有依赖项更改,我们不运行此过程。
我们如何触发和运行 as-if-JH 流水线
在准备好 as-if-jh/* 分支(并可选地进行同步)之后,start-as-if-jh 任务会触发 验证项目 中的跨项目下游流水线来运行。
如何设置 GitLab JH 镜像项目
GitLab JH 镜像 项目是私有的,且 CI 已禁用。
它是一个拉取镜像,从 GitLab JH 拉取,镜像所有分支,覆盖分歧引用,当镜像更新时不触发流水线。
拉取用户是 @gitlab-jh-validation-bot,他是该项目的主要维护者。凭据可在 1password 工程保险库中找到。
由于 GitLab JH 是公开项目,镜像过程中不使用密码。
GitLab JH 验证项目的设置方式
这个 GitLab JH 验证 项目是公开的,且启用了CI,设置了临时项目变量。
它是一个拉取镜像,从 GitLab JH 镜像 拉取,镜像特定的分支:(master|main-jh),覆盖分歧引用(divergent refs),当镜像更新时不触发流水线。
拉取用户是 @gitlab-jh-validation-bot,他是该项目中的维护者,也是 GitLab JH 镜像 的维护者。凭证可在1password工程保险库中找到。
使用来自 @gitlab-jh-validation-bot 且具有 write_repository 权限的个人访问令牌作为密码,从 GitLab JH 镜像拉取更改。用户名设置为 gitlab-jh-validation-bot。
还有一个 流水线调度 用于运行维护流水线,将变量 SCHEDULE_TYPE 设置为 maintenance,每天运行一次,更新缓存。
默认的CI/CD配置文件也设置在 jh/.gitlab-ci.yml 中,因此其运行方式与 GitLab JH 完全一致。
此外,还设置并保护了一个特殊分支 as-if-jh-code-sync。维护者可以推送此分支,开发者可以合并此分支。我们需要这样设置以便开发者能够合并,因为我们希望让开发者能为此分支触发流水线。这是在我们解决 开发级用户无法再在受保护的分支上运行流水线 问题之前的折衷方案。
它用于运行 sync-as-if-jh-branch 来同步依赖项,当合并请求改变了依赖项时。有关其实现细节,请参阅 我们如何生成 as-if-JH 分支。
临时 GitLab JH 验证项目变量
BUNDLER_CHECKSUM_VERIFICATION_OPT_IN被设置为false- 在极狐(JiHu)提交了
jh/Gemfile.checksum后,我们可以移除此变量。更多背景信息可参见:将其设置为false以跳过检查
- 在极狐(JiHu)提交了
为什么我们同时有镜像项目和验证项目?
我们分开设立这两个项目有几个原因。
- 安全性:以前我们只有镜像项目。然而,为了完全缓解安全问题,我们必须将镜像项目设为私有。
- 隔离性:我们希望在完全隔离且独立的项目中运行JH代码。我们不应该在
gitlab-org组(即镜像项目所在位置)下运行它。验证项目是完全隔离的。 - 成本效益:我们不希望每次合并请求都连接到极狐GitLab.com。更划算的方式是将代码从极狐GitLab.com镜像到GitLab.com的某个位置,让我们的合并请求从那里获取代码。这意味着验证项目可以从镜像获取代码,而不是直接从极狐GitLab.com。镜像项目会定期从极狐GitLab.com拉取代码。
- 分支分离/安全性/效率:我们想要镜像所有分支,以便从极狐GitLab.com获取对应的JH分支。但是,我们不想覆盖验证项目中的
as-if-jh-code-sync分支,因为我们用它来控制验证流水线,并且它拥有AS_IF_JH_TOKEN的访问权限。然而,我们不能只排除单个分支进行镜像。详见此问题了解详情。
鉴于这个问题,验证项目被设置为仅镜像master和main-jh。从技术角度来说,我们甚至不需要这些分支,但我们确实希望仓库与所有默认分支保持同步,这样当我们从合并请求推送更改时,只需推送合并请求的变更即可,这会更高效。
- 职责分离:
- 验证项目仅有以下分支:
master和main-jh以保持变更最新。as-if-jh-code-sync用于依赖同步。我们绝不应镜像此分支。- 来自合并请求的
as-if-jh/*分支。我们绝不应镜像这些分支。
- 镜像项目的所有分支均来自极狐GitLab.com。我们从未向镜像项目推送任何内容,它也不会运行任何流水线。镜像项目已禁用CI/CD。
- 验证项目仅有以下分支:
我们可以考虑合并这两个项目以简化设置和流程,但需要确保所有这些原因都不再成为问题。
rspec:undercoverage 作业
rspec:undercoverage 作业运行 undercover 来检测,若合并请求中引入的任何变更存在零覆盖率,则会失败。
rspec:undercoverage 作业从 rspec:coverage 作业获取覆盖率数据。
如果 rspec:undercoverage 作业检测到因EE覆盖CE方法而导致的缺失覆盖率,请给合并请求添加 pipeline:run-as-if-foss 标签并启动新的流水线。
在紧急情况下,或此作业出现误报时,请给合并请求添加 pipeline:skip-undercoverage 标签以允许此作业失败。
排查 rspec:undercoverage 失败问题
rspec:undercoverage 作业存在已知缺陷,可能导致误报失败。如果你正在更新过于古老的数据库迁移,也可能发生此类误报失败。你可以本地测试覆盖率,以确定是否可以安全地应用 pipeline:skip-undercoverage。例如,使用 <spec> 作为导致失败的测试名称:
- 运行
RUN_ALL_MIGRATION_TESTS=1 SIMPLECOV=1 bundle exec rspec <spec>。 - 运行
scripts/undercoverage。
如果这些命令返回 undercover: ✅ 最新变更无缺失覆盖率,则可以应用 pipeline:skip-undercoverage 以绕过流水线失败。
pajamas_adoption 作业
pajamas_adoption 作业在合并请求中运行 Pajamas Adoption Scanner,以防止对 Pajamas 设计系统 采用情况的回归。
如果扫描器检测到由合并请求引起的回归,作业将失败。如果回归无法在合并请求中修复,请给合并请求添加 pipeline:skip-pajamas-adoption 标签,然后重试该作业。
测试套件并行化
我们当前的 RSpec 测试并行化设置如下:
- 在
prepare阶段中的retrieve-tests-metadata作业确保我们有knapsack/report-master.json文件:knapsack/report-master.json文件从最新的运行update-tests-metadata的main流水线中获取(目前是每 2 小时一次的maintenance计划主流水线),如果不存在,我们会用{}初始化该文件。
- 每个
[rspec|rspec-ee] [migration|unit|integration|system|geo] n m作业都使用knapsack rspec运行,并且应该有均匀分布的测试份额:- 这是因为作业可以访问
knapsack/report-master.json,因为"默认会传递所有先前阶段的产物"。 - 作业将自己的报告路径设置为
"knapsack/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json"。 - 如果 knapsack 正常工作,运行的测试文件应列在
Report specs下,而不是Leftover specs下。
- 这是因为作业可以访问
update-tests-metadata作业(仅在计划流水线上为 官方项目 运行)以两种方式更新knapsack/report-master.json:- 默认情况下,它获取所有的
knapsack/rspec*.json文件并将它们合并成一个单一的knapsack/report-master.json文件,保存为产物。 - (实验性)当
AVERAGE_KNAPSACK_REPORT环境变量设置为true时,该作业不会合并报告,而是计算knapsack/report-master.json和knapsack/rspec*.json之间的测试持续时间平均值,以减少潜在随机因素(如规范排序、运行器硬件差异、不稳定测试等)对性能的影响。这种实验性方法旨在更好地预测每个规范文件的持续时间,以便更均匀地在并行作业之间分配负载,使作业能在大致相同的时间完成。
- 默认情况下,它获取所有的
之后,下一个流水线使用最新的 knapsack/report-master.json 文件。
不稳定测试
不稳定测试的自动跳过
我们过去会跳过 已知不稳定的测试,但我们现在不再这样做,因为这实际上可能导致真正的 master 分支损坏。相反,我们引入了 快速隔离流程,主动隔离任何在 #master-broken 事件中报告的不稳定测试。
可以通过将 $FAST_QUARANTINE 变量设置为 false 来禁用此快速隔离流程。
失败测试在新进程中的自动重试
除非 $RETRY_FAILED_TESTS_IN_NEW_PROCESS 变量设置为 false(默认为 true),否则失败的 RSpec 测试会在单独的 RSpec 进程中自动重试一次。目标是消除之前测试可能导致的后续测试失败的大多数副作用。
我们通过 rspec:flaky-tests-report 作业保存为产物的 $RETRIED_TESTS_REPORT_FILE 文件跟踪已重试的测试。
请参阅 实验问题。
兼容性测试
默认情况下,我们使用 GitLab.com 上运行的版本来运行所有测试。
其他版本(通常是一个向后兼容版本和一个向前兼容版本)应该在夜间计划流水线中运行。
对此一般准则的例外情况应有充分理由并记录在案。
Ruby 版本测试
我们在 GitLab.com 以及默认分支上运行 Ruby 3.2。为了准备下一个 Ruby 版本,我们对合并请求运行 Ruby 3.3。有关更多详情,请参阅 Ruby 3.3 史诗 路线图。
为确保所有支持的 Ruby 版本都能正常工作,我们还针对每个支持版本的专用每 2 小时计划流水线运行我们的测试套件。
对于合并请求,您可以添加以下标签来仅运行相应的 Ruby 版本:
pipeline:run-in-ruby3_3
PostgreSQL 版本测试
我们的测试套件针对 PostgreSQL 16 运行,因为 GitLab.com 运行在 PostgreSQL 16 上,且 Omnibus 新安装和升级默认为 PG14。
我们在夜间计划流水线中对 PostgreSQL 14、15、16 和 17 运行测试套件。
注意:随着 PG17 的加入,我们接近了夜间作业的限制,每个流水线有 1946 个作业(共 2000 个)。添加新的作业族可能导致夜间流水线失败。
当前版本测试
| 位置? | PostgreSQL 版本 | Ruby 版本 |
|---|---|---|
| 合并请求(Merge requests) | 16(默认版本) | 3.2(默认版本) |
## 日志记录
- 在 CI 中,默认禁用了对 `log/test.log` 的 Rails 日志记录(出于性能考虑)。若要覆盖此设置,请提供 `RAILS_ENABLE_TEST_LOG` 环境变量。
## CI 配置内部机制
请参阅专门的 [CI 配置内部机制页面](internals.md)。
## 性能
请参阅专门的 [CI 配置性能页面](performance.md)。
---
[返回开发文档](../_index.md)