资讯详情

资讯详情

Turborepo CI/CD 优化实战:基于 --affected 的增量流水线、Git 范围过滤与缓存加速

Turborepo CI/CD 优化实战基于 --affected 的增量流水线、Git 范围过滤与缓存加速【免费下载链接】turboBuild system optimized for JavaScript and TypeScript, written in Rust项目地址: https://gitcode.com/gh_mirrors/tu/turboTurborepo 是面向 JavaScript/TypeScript 仓库的构建系统核心以 Rust 实现其任务图task graph、内容寻址缓存与过滤系统天然为 CI 场景设计。本文围绕仓库文档skills/turborepo/references/ci/patterns.md展开系统讲解如何在 GitHub Actions 中构建高效 CIPR 构建只测受影响任务、主干分支全量验证、用 Git 引用做自定义范围过滤、远程缓存与actions/cache兜底、矩阵与跨 Job 并行、以及按条件跳过昂贵任务。读完本文你将掌握一套可直接落地的 CI 优化模式并能理解这些行为在 Turborepo 源码中的实现依据。一、CI 中的三条铁律在进入具体模式之前先明确 Turborepo 官方在 ci/RULE.md 中强调的三条核心原则它们是所有优化模式的基础CI 中始终使用turbo run。turbo tasks简写只适合开发者在终端里的一次性输入任何写进 CI 或package.json脚本里的命令都应写成turbo run build test lint以保证参数解析与后续新增旗标如--affected的兼容性。启用远程缓存。远程缓存让 CI 运行之间、开发者之间共享缓存产物是 CI 提速的最大杠杆。需要注入两个环境变量TURBO_TOKENVercel 访问令牌与TURBO_TEAM团队 slug。PR 构建使用--affected。该旗标只运行相对基线分支发生变更的包的任务前提是 CI 有足够的 Git 历史详见“Git 历史要求”一节。环境变量速查表来自 ci/RULE.md变量作用TURBO_TOKENVercel 远程缓存访问令牌TURBO_TEAMVercel 团队 slugTURBO_CACHE设为remote:rw可跳过本地缓存TURBO_REMOTE_ONLY已弃用TURBO_LOG_ORDER设为grouped可让 CI 日志按任务分组折叠更易阅读二、PR 构建与主干构建分流最常见的优化是让 PR 构建与主干main构建走不同策略PR 只验证变更内容主干合入时做完整验证保证回归不会被增量模式漏掉。- name: Test (PR) if: github.event_name pull_request run: turbo run build test --affected- name: Test (Main) if: github.ref refs/heads/main run: turbo run build test为什么--affected能做到“只测变更”从源码看--affected本质是一个内置的过滤器快捷方式它等价于--filter...[基线]即“发生变更的包 依赖这些包的所有包”。在 task_filter.rs 的resolve_affected_tasks中Turborepo 构造了一个GitRange选择器并显式设置include_uncommitted: true—— 工作区未提交改动也会纳入变更检测allow_unknown_objects: true—— 某些 Git 对象缺失时仍可继续安全降级merge_base: true—— 自动使用两个引用的合并基点merge base作为比较起点include_dependents: true—— 变更包的所有下游依赖者一并纳入。对应地命令行参数在 cli/args.rs 中定义且 cli/test.rs 的解析测试确认了turbo run build --affected、turbo build --affected乃至turbo ls --affected等形态均可解析。Git 历史要求浅克隆会破坏 --affected--affected需要把当前 HEAD 与基线分支的合并基点做比较因此浅克隆shallow clone会使其失效——当基线提交未被拉取时Turborepo 无法计算差异只能回退为运行全部任务安全但慢。GitHub Actions 中应显式设置拉取深度- uses: actions/checkoutv4 with: fetch-depth: 2 # 满足 --affected 的最小深度 # 若合并基点距离较远建议 fetch-depth: 0 拉取完整历史三、自定义 Git 范围过滤--filter 的 [ref] 语法当内置的--affected无法覆盖复杂场景时例如“从某个提交之后”“两个引用之间”“最近 N 次提交”可用--filter配合方括号 Git 范围# 自提交 abc123 之后发生变更的包及其依赖者 turbo run test --filter...[abc123] # main 与 HEAD 之间以合并基点计算发生变更的包及其依赖者 turbo run test --filter...[main...HEAD] # 最近 3 次提交中发生变更的包及其依赖者 turbo run test --filter...[HEAD~3]语法背后的解析实现Turborepo 的选择器语法为[name_pattern]{directory}[git_range]其解析实现在 target_selector.rs前缀...→ 追加该包的所有依赖者dependents后缀...→ 追加该包的所有依赖dependencies^→ 排除目标包自身...^ui表示只跑 ui 的依赖者不跑 ui前缀!→ 反向排除方括号内[a...b]→from_ref a、to_ref b且merge_base true见 target_selector.rs单引用[a]则只取from_ref。因此上例第一条...[abc123]的实际语义是自abc123起变化的包以及依赖这些包的所有包——这也是 PR 构建最常用的“变更 下游连锁”形态相关模式可对照 filtering/patterns.md。注意[main...HEAD]中的...属于 Git 范围内部语法表示两个引用之间的差异与选择器前后缀的...是两层不同的语义不要混淆。更多可组合的过滤模式Git 范围过滤可以与包名、目录、排除规则自由组合来自 filtering/patterns.md# 只构建 web 包及其依赖 turbo run build --filterweb... # 测试所有依赖 ui 的包但不包括 ui 自身 turbo run test --filter...^ui # 自上次提交以来变更的 apps 目录下的应用 turbo run build --filter{./apps/*}[HEAD^1] # 除 docs 外、且在 main...HEAD 之间有变更的包 turbo run build --filter[main...HEAD] --filter!docs # 只部署发生变更的应用 turbo run deploy --filter{./apps/*}[main...HEAD]多个--filter之间是并集关系若要“目录 ∩ Git 范围”的求交语义须把目录用{}包裹进同一个过滤器中如{./apps/*}[HEAD^1]。部署阶段还有一个值得借鉴的组合turbo run build --filterproduction-app...只对生产应用及其依赖做完整重建。四、缓存策略远程缓存优先actions/cache 兜底缓存是 Turborepo CI 的加速核心。内容寻址缓存保证只要任务的输入源码、环境变量、依赖文件未变任务即可命中缓存并跳过执行。远程缓存推荐远程缓存共享于所有 CI 运行与本地开发者之间是性能最优的方案只需注入令牌与团队标识env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ vars.TURBO_TEAM }}相关说明与更多变量可参考 remote-cache.md 与 ci/RULE.md。actions/cache 兜底方案无法使用远程缓存时可用 GitHub Actions 的actions/cache缓存本地.turbo目录- uses: actions/cachev4 with: path: .turbo key: turbo-${{ runner.os }}-${{ github.sha }} restore-keys: | turbo-${{ runner.os }}-${{ github.ref }}- turbo-${{ runner.os }}-局限性需要明确缓存按分支隔离key 中携带github.ref分支之间不能复用写入PR 只能从基线分支的缓存恢复restore-keys提供前缀回退命中率低于远程缓存整体效率不如远程缓存——远程缓存由 Turborepo 服务端按内容寻址统一调度而actions/cache只能做整包存取的近似复用。并行时的缓存注意事项当多个 Job 并行执行时每个 Job 有独立的缓存写入。远程缓存会自动处理并发而使用actions/cache时必须给每个 Job 使用唯一 key避免冲突覆盖- uses: actions/cachev4 with: path: .turbo key: turbo-${{ runner.os }}-${{ github.job }}-${{ github.sha }}五、矩阵构建跨 Node 版本验证在 monorepo 中同一套任务往往需要横跨多个 Node 版本验证。GitHub Actions 矩阵可以直接与 Turborepo 的任务图叠加strategy: matrix: node: [18, 20, 22] steps: - uses: actions/setup-nodev4 with: node-version: ${{ matrix.node }} - run: turbo run test注意矩阵维度会放大总任务量建议与--affected或--filter组合使用例如仅在 PR 构建中按矩阵跑受影响包的测试否则每个 Node 版本都会全量执行。六、跨 Job 并行化把 lint、test、build 拆分为独立 Job让它们在不同 runner 上并行执行是缩短整体流水线时长的直接手段jobs: lint: runs-on: ubuntu-latest steps: - run: turbo run lint --affected test: runs-on: ubuntu-latest steps: - run: turbo run test --affected build: runs-on: ubuntu-latest needs: [lint, test] steps: - run: turbo run build这里的needs: [lint, test]保证 build 在质量门禁通过后才执行。需要强调的是Turborepo 本身就会在单 Job 内按任务图并行调度任务任务间的dependsOn关系由引擎保证执行顺序跨 Job 拆分是为了利用多个 runner 的计算资源二者互补。缓存注意事项每个 Job 有独立的缓存写入使用远程缓存时无需额外处理自动协调使用actions/cache时为每个 Job 配置唯一 key见上一节避免多个 Job 争用同一缓存条目。七、条件任务跳过昂贵测试对于耗时且与代码变更无强关联的端到端测试等昂贵任务可在工作流层面按条件跳过。草稿 PRdraft阶段通常不需要跑全量 E2E- name: E2E Tests if: github.event.pull_request.draft false run: turbo run test:e2e --affected或者要求打上特定 label 才触发全量测试- name: Full Test Suite if: contains(github.event.pull_request.labels.*.name, full-test) run: turbo run test这两类模式的价值在于把“高频率、低价值”的构建阶段从普通 PR 中剥离仅在真正需要的时机发布前、合入主干时、人工打标后执行从而压低平均 CI 等待时间。八、调试与验证--dry 先行在将上述过滤模式固化进 CI 之前建议先在本地用--dry预览将要执行的任务避免把错误的过滤器写进流水线# 预览 web 及其依赖会被构建的任务 turbo run build --filterweb... --dry # 输出机器可读的 JSON 清单 turbo run build --filter...[HEAD^1] --dryjson--dry不会真正执行命令只打印任务执行计划含缓存命中情况是校验--filter/--affected语义最直接的工具。九、组合示例一套完整的 PR 流水线将以上模式组合即可得到一份可落地的 GitHub Actions PR 流水线骨架融合 patterns.md 与 github-actions.md 的思路name: CI on: pull_request: jobs: checkout-and-cache: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 # 保证 --affected 可计算合并基点 - uses: actions/setup-nodev4 with: node-version: 20 lint: runs-on: ubuntu-latest steps: - run: turbo run lint --affected test: runs-on: ubuntu-latest strategy: matrix: node: [18, 20, 22] steps: - uses: actions/setup-nodev4 with: node-version: ${{ matrix.node }} - uses: actions/cachev4 with: path: .turbo key: turbo-${{ runner.os }}-${{ github.job }}-${{ github.sha }} restore-keys: | turbo-${{ runner.os }}-${{ github.ref }}- turbo-${{ runner.os }}- - run: turbo run test --affected e2e: runs-on: ubuntu-latest if: github.event.pull_request.draft false needs: [lint, test] steps: - run: turbo run test:e2e --affected要点回顾分流PR 用--affected做增量验证主干合入跑全量范围--filter...[main...HEAD]等 Git 范围语法由 target_selector.rs 解析--affected在 task_filter.rs 中等价为“变更包 依赖者”且默认包含未提交改动、以合并基点计算缓存优先远程缓存TURBO_TOKEN/TURBO_TEAM兜底actions/cache时注意分支隔离与多 Job 唯一 key并行矩阵负责版本维度跨 Job 拆分负责资源维度条件draft 跳过 E2E、label 门控全量测试验证任何过滤组合先--dry/--dryjson预览再固化进流水线。【免费下载链接】turboBuild system optimized for JavaScript and TypeScript, written in Rust项目地址: https://gitcode.com/gh_mirrors/tu/turbo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →