持续集成配置
确定在推送时和每次变更请求时运行什么,然后以项目代码托管平台能理解的语法编写。此文件中的决策与平台无关:检测生态系统,决定需要运行什么,选择矩阵,决定缓存。表达这些决策的语法并非平台无关,因此它存在于 references/github-actions.md(针对 GitHub Actions)和 references/gitlab.md(针对 GitLab CI/CD)中。在编写任何配置之前,请阅读相应的参考文件;不要通过翻译另一个平台的关键词来编写一个平台的语法,因为它们在触发器、矩阵和缓存方面有不同结构。
范围
此技能拥有运行什么:哪些检查执行,在哪些触发器上,跨哪些版本,使用什么缓存。它与其他两个技能共享它所编写的工作流和流水线文件,它们之间的边界是规则领域,而不是文件描述。
下面的 CI 规则(R-CI-*)属于此处。SEC 规则,即同一文件的安全态势(例如固定的操作 SHA、最小权限、依赖更新器、分支保护和固定镜像),属于 oss-harden。REL 规则,即使用受信任发布、来源证明和审批门将构建的工件发布到注册表,属于 oss-publish。在此技能工作时,不要添加 permissions: 块、固定 SHA、配置分支保护或编写发布作业;请注意项目需要这些,并将工作交给拥有它的技能。
将构建的静态站点部署到平台自己的 Pages 托管也是推送时运行的内容,因此它留在此处,而不是由 oss-publish 负责,后者拥有注册表发布。没有规则要求部署:项目因拥有站点而发布它,因此仅当仓库构建站点且用户要求部署时才编写。
原则
在添加步骤、密钥或配置值之前,务必验证所有内容:阅读实际仓库而不是猜测其形状。当不确定时询问,而不是编造一个合理的答案。
调用项目自己的自动化,而不是在流水线内部编写 shell 逻辑。运行 npm test 而不是 jest --coverage --ci 的步骤确保流水线和贡献者的笔记本电脑运行相同的命令,这正是 R-CI-02 所检查的。当不存在此类自动化时,询问是将其添加到项目还是回退到内联命令。
即使仓库已经包含测试、Dockerfile 或流水线,也要提出策略选择,而不是猜测它们。变更请求上运行什么、什么触发发布构建以及部署如何发生是用户做出的决定;代码只告诉你什么是可能的,而不是什么是想要的。
流程
步骤 1:检测平台
查找现有的 .github/workflows/ 目录或 .gitlab-ci.yml 文件,检查 git 远程是否有 github.com 或 gitlab 主机,如果两者都不存在,则直接询问。这决定了哪个参考文件管辖步骤 6 和 7。如果用户明确说明了平台,请信任该信息而不是仓库中找到的任何信号。
步骤 2:分析仓库
从源文件和包清单中识别语言和运行时,并记下项目声称支持的版本范围;步骤 4 中的矩阵必须覆盖所有这些版本,包括最旧和最新支持的版本,根据 R-CI-03 规定。
查找项目已经定义的每个适用的 lint、test、typecheck 和 build 命令,无论是包管理器脚本、Makefile、Rakefile 还是诸如 tox 或 just 之类的工具,并仔细阅读它们以了解其参数和副作用。不要编造缺失的检查类别:文档仓库可能没有构建,小型脚本可能没有 linter。如果仓库有 CONTRIBUTING 指南,则其命令和项目自动化必须一致;在将任一命令复制到 CI 之前解决任何冲突。
在更改现有的 CI 配置之前先阅读它,以便知道是扩展还是替换它。
识别项目提交的每个锁文件,例如 package-lock.json、Gemfile.lock、poetry.lock 或 Cargo.lock,以及每个 install 命令可以安全重用的包管理器下载缓存。不要假设已安装的依赖目录是缓存。
找到 .env.example 并在源代码中搜索所需的环境变量,以便在生成之前而不是在运行失败之后识别需要密钥的步骤。
步骤 3:提出发现并询问
总结步骤 2 的发现,然后询问仅凭代码无法回答的选择:拉取或合并请求上应运行什么,什么应触发发布构建,以及是否应扩展或替换现有的 CI。只询问适用于此项目的问题;没有 Dockerfile 的项目不会得到关于注册表的问题。
如果步骤 2 发现构建产生静态站点,询问它是否也应部署,以及部署到哪里。站点可以仅作为检查构建而从不发布,因此将静态构建视为问题而不是同意部署。
步骤 4:选择矩阵
根据步骤 2 中确定的受支持发布行构建版本矩阵,而不是从单个固定版本开始。包括项目声称支持的每个维护的主要或次要发布行。没有规定支持范围的项目将获得单版本流水线,而不是编造的矩阵;不要制造清单未做出的支持声明。如果范围是连续的并且包括项目不打算支持的发布行,则修正声明的范围,而不是静默测试子集。
步骤 5:决定缓存
仅缓存包管理器下载数据或该工具的官方文档说明可安全重用的其他目录。当受支持的包管理器支持且已对锁文件进行哈希处理时,首选平台的官方运行时设置操作。否则,基于锁文件以及每个更改其内容的兼容性边界(例如操作系统、架构、运行时和包管理器)来显式设置缓存键。回退键是可选的,并且不得跨越这些边界之一。没有锁文件或没有可重用下载缓存的项目不会获得缓存步骤。
步骤 6:编写配置
打开步骤 1 中选择的平台对应的参考文件,并严格遵循其语法。两个参考文件都涵盖了在默认分支上的推送和每次变更请求时的触发(R-CI-01)、每个作业的超时以及同一分支上被取代运行的取消(R-CI-05),以及步骤 5 中的缓存决策(R-CI-04)。两者还包含 Pages 部署部分,仅在步骤 3 确定项目需要时才使用。两个参考文件都不涵盖权限、SHA 固定或发布;这些内容需保留在您在此编写的文件之外。
步骤 7:在展示前验证
在存在对应验证器的情况下,使用平台自己的验证器确认配置在语法上有效,并确认其调用的每个命令在本地以相同顺序存在并成功执行。对于 GitLab,使用 CI Lint(包含展开的配置)。对于 GitHub,在 Actions 编辑器中检查工作流,或当用户已授权该外部更改时将其推送到分支;通用的 YAML 解析器无法验证 GitHub 表达式或工作流语义。列出流水线所需的任何密钥,以及添加每个密钥的命令,但不要运行该命令。确认矩阵匹配每个受支持的发布行,并且每个作业都有超时,并在安全的情况下参与取消被取代的运行。
步骤 8:展示结果
显示生成的文件、已检测和已决定的内容的简短摘要、要配置的密钥列表,以及用户在仓库或项目级别需要设置的任何内容(例如分支保护或环境审批者),并注明拥有它的技能名称,而不是在此尝试设置。
此技能拥有的规则
R-CI-01:CI 在每次推送到默认分支时和每次变更请求时运行
R-CI-02:CI 运行与贡献指南向人类提供的相同的 lint、test 和 build 命令
R-CI-03:测试矩阵覆盖项目声称支持的每个运行时版本
R-CI-04:依赖缓存基于锁文件设置键
R-CI-05:每个作业都有超时,并且同一分支的被取代运行会被取消