关于 actions-ci-tuning
用于审计和改进 GitHub Actions 工作流的技能,面向维护 CI 的开发团队。它先处理正确性问题,再检查缓存、并行测试、制品保护、可靠性和安全配置,并提出最小改动。
主要功能
- 01盘点工作流与运行时长
- 02检查依赖缓存和安装方式
- 03审查并行任务与测试分片
- 04检查制品合并保护
- 05核查并发、触发器和版本固定
适用场景
- 01诊断 CI 运行失败或变慢
- 02优化 Playwright 测试分片与报告
- 03降低缓存失效和锁文件漂移风险
- 04审查 GitHub Actions 安全配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mizchi/ skills --skill actions-ci-tuning安装后在 Claude Code 中输入/actions-ci-tuning确认已加载。
附带文件README.md
详细介绍
GitHub Actions CI 调优
审查并改进 GitHub Actions 工作流。优先关注正确性(作业报错而非失败),其次是速度(缓存、并行),最后是可靠性(不稳定性、产物保护)。
工作流
- 盘点 — 列出所有
.github/workflows/*.yml文件及其触发事件、作业和大致耗时(gh run list --workflow <file> --limit 5)。 - 根据清单审查 — 逐项检查下方各部分,并标记所有缺漏。
- 确定优先级 — 按影响分组:正确性缺陷 > 缓存未命中 > 并行优化 > 外观问题。
- 提出更改 — 起草最小差异;不要重构无关部分。
- 验证 — 应用更改后,通过
gh run list确认下一次运行通过且速度更快。
检查清单
包管理器缓存
缓存未命中意味着每次运行都要重新下载数百个包。在大多数仓库中,这是投资回报率最高的单项修复。
pnpm
- uses: pnpm/action-setup@v6
with:
version: latest # or pin to a specific version
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc # or node-version: '24' (current LTS)
cache: 'pnpm' # ← must be present; omitting it silently skips caching
常见错误:调用 corepack enable 而非 pnpm/action-setup。corepack enable 不会设置 pnpm store 缓存 — actions/setup-node cache: 'pnpm' 要求先运行 pnpm/action-setup。
npm
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: 'npm'
yarn(classic / berry)
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: 'yarn'
验证缓存是否生效:在 setup-node 日志中查找 Cache restored successfully。如果没有,可能是缺少 cache: 键,或锁文件路径错误。
依赖安装
- 在 CI 中始终使用
--frozen-lockfile(pnpm)/--ci(npm)/--immutable(yarn berry)。这样可以防止锁文件漂移导致已安装的依赖树悄然变化。 - 在 CI 中绝不要使用不带冻结标志的
npm install或pnpm install。
并行作业与步骤
- 独立作业(lint、typecheck、test)应拆分为不同作业并行运行,而不是作为顺序步骤执行。
- 顺序步骤适合在单个作业中进行设置(安装 → 构建 → 测试)。
- 如果仓库把 lint、typecheck 和单元测试都放在一个作业中,应将它们拆分。
jobs:
lint:
runs-on: ubuntu-latest
steps: [checkout, setup, install, run lint]
typecheck:
runs-on: ubuntu-latest
steps: [checkout, setup, install, run typecheck]
test:
runs-on: ubuntu-latest
steps: [checkout, setup, install, run test]
测试分片(Playwright / Vitest)
使用分片缩短耗时较长的测试套件。每个分片并行运行一部分测试。
Playwright 示例 — 4 个分片:
jobs:
e2e:
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- run: pnpm exec playwright test --shard=${{ matrix.shard }}/4
env:
CI: true
- uses: actions/upload-artifact@v7
if: ${{ !cancelled() }} # ← upload even on test failure
with:
name: blob-report-${{ matrix.shard }}
path: blob-report/
retention-days: 1
注意事项:
- 必须设置
fail-fast: false,否则一个分片失败就会取消其余分片,导致它们无法上传 blob 报告。 - 在上传步骤中设置
if: ${{ !cancelled() }},确保即使测试失败也会上传 blob 报告。否则,merge-reports 作业将收不到任何产物。
merge-reports 中的产物保护
如果分片可能在上传 blob 报告前失败,all-blob-reports 目录可能不存在。为合并命令添加保护:
- name: Merge reports
run: |
if [ -d all-blob-reports ] && [ "$(ls -A all-blob-reports 2>/dev/null)" ]; then
pnpm exec playwright merge-reports --reporter=html ./all-blob-reports
else
echo "No blob reports found, skipping merge"
mkdir -p playwright-report
echo "<html><body><p>No test results available</p></body></html>" > playwright-report/index.html
fi
如果没有此保护,即使整个工作流本应正常报告“无结果”,merge-reports 作业仍会报错:Error: Directory does not exist: ./all-blob-reports。
Playwright Docker 镜像
对于 VRT(视觉回归测试),快照必须在与 CI 相同的环境中生成(Linux + 指定字体)。使用官方 Playwright Docker 镜像,而非普通的 node:* 镜像:
mcr.microsoft.com/playwright:v1.59.1-noble # pin to the same version as @playwright/test
为什么不用 node:24?
node:24需要运行playwright install --with-deps chromium,这会触发apt-get,在 macOS 上的 Docker Desktop 中可能因已知的 QEMU 模拟环境 apt 问题而卡住数小时。mcr.microsoft.com/playwright镜像已预装 Chromium 和所有系统依赖 — 无需 apt-get,几秒内即可启动。
版本固定:确保镜像版本与 package.json 中的 @playwright/test 版本一致。版本不匹配会导致找不到浏览器的错误。
并发控制
取消同一分支/PR 上正在进行的运行,避免队列积压:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
例外:不要取消 main 上的发布/部署工作流。仅对 PR 分支启用:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
定时工作流可靠性
- 如果仓库 60 天内没有活动,GitHub Actions 上的定时工作流可能会悄然停止触发。
- 在
schedule:旁添加workflow_dispatch:触发器,这样无需更改代码即可手动重新触发。 - 对于关键的定时任务(例如每晚运行的 E2E),添加失败通知步骤(创建 GitHub issue、发送 Slack 通知等),以便发现静默失败。
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch: # ← always add this
Action 版本固定
- 将第三方 Action 固定到完整的提交 SHA,而不是标签。标签可能会被移动。
- 使用注释注明易读的版本:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- Dependabot 或 Renovate 可以自动更新 SHA 固定值。检查
.github/dependabot.yml是否包含github-actions生态系统。
Node.js 20 弃用警告:GitHub 于 2025/2026 年开始发出“Node.js 20 actions are deprecated”警告。这指的是 Action 自身的运行时(runs.using: node20),而不是项目的 Node 版本。请升级到首个使用 node24 的主版本:
| action | 首个 node24 主版本 | 当前主版本(2026-09) |
|---|---|---|
actions/checkout | v6.0.0 | v7 |
actions/setup-node | v6.0.0 | v7 |
actions/cache | v5.0.0 | v6 |
actions/upload-artifact | v7.0.0 | v7 |
actions/download-artifact | v8.0.0 | v8 |
aws-actions/configure-aws-credentials | v6.0.0 | v6 |
最新的固定 SHA(已于 2026-09 验证):
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
uses: aws-actions/configure-aws-credentials@cbe3b392738ccf3f987d68400dafcf4b0624a56c # v6.2.4
注意:SHA 会变动——固定之前,务必使用 gh release view --repo <owner>/<action> 进行验证。
环境变量
CI: true应设置在作业或工作流级别,而不仅仅是在单独的运行步骤中。许多工具(Playwright、Vite 等)会根据此标志更改行为。- 密钥应使用
${{ secrets.NAME }}——切勿硬编码令牌。 - 对于受限运行器上的大型构建,有时需要设置
NODE_OPTIONS: --max-old-space-size=4096(7 GB 运行器的默认堆内存约为 1.5 GB)。
快速审计命令
# List recent run durations for a workflow
gh run list --workflow e2e.yml --limit 10 --json databaseId,displayTitle,createdAt,updatedAt,conclusion \
| jq '.[] | {title: .displayTitle, duration: (.updatedAt | fromdate) - (.createdAt | fromdate), conclusion: .conclusion}'
# Find jobs that always time out
gh run list --workflow e2e.yml --status failure --limit 20 --json databaseId \
| jq -r '.[].databaseId' \
| xargs -I{} gh run view {} --json jobs \
| jq '.jobs[] | select(.conclusion == "timed_out") | .name'
# Check cache usage in a run
gh run view <run_id> --log | grep -i "cache"
常见反模式
| 反模式 | 问题 | 修复方法 |
|---|---|---|
仅使用 corepack enable(没有 pnpm/action-setup) | pnpm 存储区不会被缓存 | 在 setup-node 之前添加 pnpm/action-setup@v6 |
pnpm install 未使用 --frozen-lockfile | 锁文件可能在不知情的情况下发生漂移 | 在 CI 中始终使用 --frozen-lockfile |
测试矩阵中设置 fail-fast: true | 分片会在上传制品前取消 | 设置 fail-fast: false |
上传制品时未使用 if: ${{ !cancelled() }} | 测试失败时 Blob 报告会丢失 | 添加 if 条件 |
使用 playwright merge-reports 时未检查目录 | 没有分片上传时作业会报错 | 使用 [ -d all-blob-reports ] 检查进行保护 |
Playwright VRT 使用 node:* 镜像 | 在 macOS 上,Docker Desktop 中的 apt-get 会卡住 | 使用 mcr.microsoft.com/playwright 镜像 |
定时工作流未配置 workflow_dispatch | 无法手动重新触发 | 始终添加 workflow_dispatch: |
| Action 固定到标签而非 SHA | 标签可能会被移动(供应链风险) | 固定到完整的提交 SHA |