Ship gate(发布关卡)
这里的每一条规则之所以存在,是因为曾经有显而易见的检查返回了假性通过。请在做出声称之前运行关卡,而不是之后。
请根据你的技术栈调整具体细节;其核心理念——什么会让这个声称成为假的?——才是可移植的部分。
声称规则
关于生产环境的声称必须通过对生产环境的查询来验证。
一个通过的测试不是生产环境。一个合并的 PR 不是生产环境。一个绿色的部署不是生产环境。这些都只是对不同于你所断言系统的其他系统的声称。
如果没有人类亲眼过目结果,就不能算作“已验证”——请直接说明你实际检查了什么。
部署验证
- 了解什么才是真正触发部署的操作。 在基于 Git 集成的宿主平台上,触发部署的是推送,而不是 CLI 调用。如果项目是通过推送部署的,而你用 CLI 来部署,生成的构建将不是用户实际获取的那个。
- 检查拥有项目的账户。 本地登录的 CLI 可能认证为个人账户,该账户并不拥有生产项目——这样每条命令都会静默地对错误目标成功执行。
- 通过提交状态与已部署的 SHA 进行验证,而不是快速看一眼仪表盘。
- 确认当前的部署是当前生产环境,而不仅仅是一个标记为 READY 的部署。多个部署可以同时处于 READY 状态。
- 边缘/无服务器函数与应用程序是分开部署的。 一个合并的 PR 并不会部署边缘函数;请显式检查其版本。
- 纯客户端变更可能无需函数部署——不要等待一个永远不会到来的部署。
- 在断言版本之前,重新获取当前在线清单。并行工作可能会在你不注意时改变版本。
CI 验证
- 对所有必需的上下文都进行把关,而不仅仅是第一个绿色的。
- 永远不要基于管道命令进行把关。
some-check | tail报告的是tail的退出码,从而掩盖了真正的失败。在没有PIPESTATUS(zsh 与 bash 在此处不同)的 shell 中,很容易出错——请检查命令自身的状态。 steps: 0意味着作业从未运行过,而不是通过了。Checks API 可以报告一个没有做任何工作的作业的结论。- 一个疑似很快失败且没有步骤的情况,通常是计费或权限问题,而不是 YAML 问题。
- 只重新运行失败的作业会回放分支的过时快照。请先更新分支,然后再重新运行。
- 检查列表会省略从未创建的作业。 没有失败并不代表通过。
gh pr create需要显式的--base。其周围的链式 heredoc 可能会静默失败。
类型与 lint 关卡
- 大型 TypeScript 项目可能需要增加 Node 堆内存;否则
tsc会以一种看起来像代码错误的方式崩溃。 - 了解你的类型检查器和 linter 实际覆盖了哪些目录。 边缘函数目录经常被两者排除在外。如果它们运行在不同的运行时上,请使用该运行时自己的检查器来检查它们——测试作业不是类型关卡。
- 在工作树或干净的检出环境中构建,而不是在有未提交的变更的工作目录中构建。
数据库
- 绝不要随便对生产环境推送模式或运行迁移。通过项目选择的经过审查的路径,一次性应用模式。
- 在相信新存储过程之前,请针对真实数据库调用它们。 模拟会隐藏仅在真实类型和真实歧义下才会出现的运行时错误。
- 如果测试套件全局模拟了数据库,一个通过的单元测试对数据库毫无证明作用。
- 永远不要在由触发器管理的列上使用比较并设置操作——触发器会在写入时更改该列。
- 在合并之前,衡量变更对生产数据的爆炸半径。 针对本地种子数据看起来范围很窄的过滤器,可能与真实数据行的完全不同部分匹配。
环境陷阱
- 永远不要假设机器的时区——请运行
date。 依赖日期的测试会因偏移量而失败,并且该失败看起来像是代码错误。 - 未设置的 Git 身份可能会阻止部署,并表现为无关的网络错误。
- 从文件而非内联赋值中设置主机环境变量;shell 和 CLI 可能会嵌入不可见的尾随换行符,从而破坏值。
- 计划作业的成功并不等于作业效果的成功:跑步者报告
succeeded意味着调用返回了,而不是工作完成了。请验证其效果。
输出
每个关卡的状态应明确表述为 PASS(证据) 或 NOT CHECKED(原因)。
切勿暗示一个实际上没有运行的关卡已经运行。如果任何关卡失败或未检查,请直接说明该变更未经验证——保留声称是正确的做法。