自动化CI/CD流水线设置。在设置或修改构建和部署流水线时使用。在需要自动化质量门禁、配置CI中的测试运行器或建立部署策略时使用。
CI/CD与自动化
概述
自动化质量门禁,确保任何变更在通过测试、代码检查、类型检查和构建之前不会进入生产环境。CI/CD是其他所有技能的强制执行机制——它能捕捉人类和智能体遗漏的问题,并且在每次变更时都一致地执行。
左移: 尽可能在流水线早期发现问题。代码检查中捕获的bug只需几分钟;同样的bug在生产环境中捕获则需要数小时。将检查向上游移动——静态分析在测试之前,测试在预发布环境之前,预发布环境在生产环境之前。
更快更安全: 更小的批次和更频繁的发布能降低风险,而不是增加风险。包含3个变更的部署比包含30个变更的部署更容易调试。频繁发布能增强对发布过程本身的信心。
使用时机
- 设置新项目的CI流水线
- 添加或修改自动化检查
- 配置部署流水线
- 当变更需要触发自动验证时
- 调试CI失败
质量门禁流水线
每个变更在合并前都要经过以下门禁:
拉取请求已打开
│
▼
┌─────────────────┐
│ 代码检查 │ eslint, prettier
│ ↓ 通过 │
│ 类型检查 │ tsc --noEmit
│ ↓ 通过 │
│ 单元测试 │ jest/vitest
│ ↓ 通过 │
│ 构建 │ npm run build
│ ↓ 通过 │
│ 集成测试 │ API/数据库测试
│ ↓ 通过 │
│ 端到端测试(可选)│ Playwright/Cypress
│ ↓ 通过 │
│ 安全审计 │ npm audit
│ ↓ 通过 │
│ 包体积检查 │ bundlesize check
└─────────────────┘
│
▼
准备审查
任何门禁都不能跳过。 如果代码检查失败,修复代码检查——不要禁用规则。如果测试失败,修复代码——不要跳过测试。
GitHub Actions 配置
基本CI流水线
# .github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 代码检查
run: npm run lint
- name: 类型检查
run: npx tsc --noEmit
- name: 测试
run: npm test -- --coverage
- name: 构建
run: npm run build
- name: 安全审计
run: npm audit --audit-level=high
带数据库集成测试
integration:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: testdb
POSTGRES_USER: ci_user
POSTGRES_PASSWORD: ${{ secrets.CI_DB_PASSWORD }}
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- name: 运行迁移
run: npx prisma migrate deploy
env:
DATABASE_URL: postgresql://ci_user:${{ secrets.CI_DB_PASSWORD }}@localhost:5432/testdb
- name: 集成测试
run: npm run test:integration
env:
DATABASE_URL: postgresql://ci_user:${{ secrets.CI_DB_PASSWORD }}@localhost:5432/testdb
注意: 即使是仅用于CI的测试数据库,也应使用GitHub Secrets存储凭据,而不是硬编码值。这有助于养成良好的习惯,并防止测试凭据在其他上下文中被意外重用。
端到端测试
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- name: 安装Playwright
run: npx playwright install --with-deps chromium
- name: 构建
run: npm run build
- name: 运行端到端测试
run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
将CI失败反馈给智能体
CI与AI智能体结合的力量在于反馈循环。当CI失败时:
CI失败
│
▼
复制失败输出
│
▼
将其提供给智能体:
"CI流水线失败,错误信息如下:
[粘贴具体错误]
修复问题并在本地验证,然后再次推送。"
│
▼
智能体修复 → 推送 → CI再次运行
关键模式:
代码检查失败 → 智能体运行 `npm run lint --fix` 并提交
类型错误 → 智能体读取错误位置并修复类型
测试失败 → 智能体遵循调试与错误恢复技能
构建错误 → 智能体检查配置和依赖
部署策略
预览部署
每个PR都会获得一个预览部署,用于手动测试:
# 在PR上部署预览(Vercel/Netlify等)
deploy-preview:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: 部署预览
run: npx vercel --token=${{ secrets.VERCEL_TOKEN }}
功能开关
功能开关将部署与发布解耦。将不完整或有风险的功能部署在开关后面,这样你可以:
- 在不启用的情况下发布代码。 尽早合并到主分支,准备好时再启用。
- 无需重新部署即可回滚。 禁用开关,而不是回退代码。
- 灰度发布新功能。 先对1%的用户启用,然后10%,最后100%。
- 运行A/B测试。 比较启用和未启用功能时的行为。
// 简单的功能开关模式
if (featureFlags.isEnabled('new-checkout-flow', { userId })) {
return renderNewCheckout();
}
return renderLegacyCheckout();
开关生命周期: 创建 → 启用测试 → 灰度 → 全面发布 → 移除开关和死代码。长期存在的开关会成为技术债务——创建时设定清理日期。
分阶段发布
PR合并到主分支
│
▼
预发布环境部署(自动)
│ 手动验证
▼
生产环境部署(手动触发或预发布后自动)
│
▼
监控错误(15分钟窗口)
│
├── 检测到错误 → 回滚
└── 正常 → 完成
回滚计划
每次部署都应该是可逆的:
# 手动回滚工作流
name: Rollback
on:
workflow_dispatch:
inputs:
version:
description: '要回滚到的版本'
required: true
jobs:
rollback:
runs-on: ubuntu-latest
steps:
- name: 回滚部署
run: |
# 部署指定的先前版本
npx vercel rollback ${{ inputs.version }}
环境管理
.env.example → 提交(开发者模板)
.env → 不提交(本地开发)
.env.test → 提交(测试环境,无真实密钥)
CI密钥 → 存储在GitHub Secrets/保险库中
生产密钥 → 存储在部署平台/保险库中
CI永远不应拥有生产密钥。为CI测试使用单独的密钥。
超越CI的自动化
Dependabot / Renovate
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
构建守护者角色
指定某人负责保持CI绿色。当构建失败时,构建守护者的工作是修复或回退——而不是导致变更的人。这可以防止在每个人都认为别人会修复的情况下,失败的构建不断累积。
PR检查
- 必需审查: 合并前至少1个批准
- 必需状态检查: 合并前CI必须通过
- 分支保护: 禁止强制推送到主分支
- 自动合并: 如果所有检查通过且已批准,自动合并
CI优化
当流水线超过10分钟时,按影响顺序应用以下策略:
CI流水线慢?
├── 缓存依赖
│ └── 使用actions/cache或setup-node缓存选项缓存node_modules
├── 并行运行作业
│ └── 将代码检查、类型检查、测试、构建拆分为独立的并行作业
├── 仅运行有变更的部分
│ └── 使用路径过滤器跳过无关作业(例如,仅文档变更的PR跳过端到端测试)
├── 使用矩阵构建
│ └── 将测试套件分片到多个运行器上
├── 优化测试套件
│ └── 将慢速测试从关键路径中移除,改为按计划运行
└── 使用更大的运行器
└── GitHub托管的更大运行器或自托管运行器用于CPU密集型构建
示例:缓存和并行
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '22', cache: 'npm' }
- run: npm ci
- run: npm run lint
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '22', cache: 'npm' }
- run: npm ci
- run: npx tsc --noEmit
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '22', cache: 'npm' }
- run: npm ci
- run: npm test -- --coverage
常见借口
| 借口 | 现实 |
|---|---|
| "CI太慢了" | 优化流水线(见下方CI优化),不要跳过它。5分钟的流水线可以防止数小时的调试。 |
| "这个变更很小,跳过CI" | 小变更也会破坏构建。而且CI对小变更来说很快。 |
| "测试不稳定,重新运行就好" | 不稳定的测试会掩盖真正的bug并浪费每个人的时间。修复不稳定性。 |
| "我们以后再添加CI" | 没有CI的项目会积累损坏状态。从第一天就设置它。 |
| "手动测试就够了" | 手动测试无法扩展且不可重复。尽可能自动化。 |
危险信号
- 项目中没有CI流水线
- CI失败被忽略或静默处理
- 测试在CI中被禁用以使流水线通过
- 生产部署未经预发布环境验证
- 没有回滚机制
- 密钥存储在代码或CI配置文件中(而非密钥管理器)
- CI时间长且未进行优化
验证
设置或修改CI后:
- [ ] 所有质量门禁均已存在(代码检查、类型检查、测试、构建、审计)
- [ ] 流水线在每个PR和推送到主分支时运行
- [ ] 失败会阻止合并(已配置分支保护)
- [ ] CI结果反馈到开发循环中
- [ ] 密钥存储在密钥管理器中,而非代码中
- [ ] 部署具有回滚机制
- [ ] 流水线在10分钟内运行测试套件






