Skip to content

feat(ci): turbo + affected builds, staging/prod envs, three-workflow split#174

Draft
billwatson017 wants to merge 1 commit intomainfrom
feat/turbo-ci-refactor
Draft

feat(ci): turbo + affected builds, staging/prod envs, three-workflow split#174
billwatson017 wants to merge 1 commit intomainfrom
feat/turbo-ci-refactor

Conversation

@billwatson017
Copy link
Copy Markdown
Contributor

Summary

Replaces the monolithic build-deploy-test.yml + 402-line build-packages.ts with Turborepo-orchestrated builds, env-aware deploys per trigger, and affected-only execution on PRs and main. Based on the pattern established in zephyr-cloud-io.

Behavior after merge

Trigger What builds Deployed to
PR turbo build --affected vs base SHA + per-standalone paths-filter Staging
Merge to main turbo build --affected vs previous commit + per-standalone paths-filter Production
workflow_dispatch / repository_dispatch All workspace + all standalones User-selected env (dev/staging/production)

Infrastructure added

  • turbo.json — Depot remote cache (cache.depot.dev, team l727rgm5x8), globalEnv covers ZE_* + PUBLIC_* for proper per-env cache separation, explicit inputs/outputs per bundler config type.
  • .github/actions/setup-node/action.yml — pnpm 10.6.3 + Node 24 + cached install.
  • .github/actions/turbo-affected/action.yml — runs turbo ls --affected, filters by path, outputs JSON matrix + any_changed flag. Copied verbatim from zephyr-cloud-io.
  • .github/workflows/development.yml — PR flow, staging deploys, affected-only.
  • .github/workflows/release.yml — main flow, production deploys, affected-only, + Playwright validation job.
  • .github/workflows/manual.yml — full-build flow for testing package changes. Preserves the prior repository_dispatch: [build-deploy-test] webhook contract.

Staging vs prod — how it works

ZE_ENV env var is the signal. Same Zephyr account, different deployment target label per env. Turbo's globalEnv includes ZE_ENV, so staging and prod builds land in different cache slots and don't cross-contaminate.

Env ZE_ENV Secret ZE_API ZE_API_GATE
dev development ZE_SECRET_TOKEN_DEV api-dev.zephyr-cloud.io zeapi.zephyrcloudapp.dev
staging staging ZE_SECRET_TOKEN_STAGING zephyr-api-prerelease-… zeapi.zephyrcloudapp.xyz
production production ZE_SECRET_TOKEN_PROD api.zephyr-cloud.io zeapi.zephyrcloud.app

Standalones strategy

4 examples stay standalone because they have their own lockfiles or require pinned dep stacks that would conflict with the root workspace:

  • build-systems/nx-rspack-mf (Nx, own lockfile)
  • build-systems/turborepo-rspack-mf (Turbo, own lockfile)
  • module-federation/airbnb-clone (multi-bundler)
  • module-federation/react-vite-rspack-webpack (multi-bundler)

Each runs in a matrix job with a paths-filter gate so unchanged standalones are skipped on PRs and pushes. On workflow_dispatch, all 4 build unconditionally.

Removed

  • scripts/src/build-packages.ts (402 lines of custom TS replaced by turbo)
  • scripts/package.json scripts: build-packages, build-packages:force, build-affected, build-affected:force, build-affected:list (the latter three pointed at a file that never existed)
  • .github/workflows/build-deploy-test.yml

Secrets / vars required before merge

The workflows reference these — must exist in repo secrets/vars:

Secrets:

  • ZE_SECRET_TOKEN_DEV
  • ZE_SECRET_TOKEN_STAGING
  • ZE_SECRET_TOKEN_PROD
  • TURBO_TOKEN (Depot cache token)

Vars:

  • TURBO_TEAM (value: l727rgm5x8 to share cache with zephyr-cloud-io)

If any are missing, the first workflow run will surface them clearly. Merging without these configured will cause deploys to fail silently-ish (auth errors).

Verified locally

  • pnpm install succeeds at root; turbo 2.9.6 installed
  • pnpm exec turbo ls discovers 29 workspace packages
  • pnpm exec turbo build --dry-run plans tasks for all 29 cleanly
  • TURBO_SCM_BASE=origin/main pnpm exec turbo ls --affected returns all packages (expected — we changed root-level files in globalDependencies)

Test plan

  • Depot cache credentials configured in repo secrets/vars
  • ZE_SECRET_TOKEN_STAGING and ZE_SECRET_TOKEN_PROD exist (DEV optional)
  • Open a test PR touching one example — verify only that example + deps build, deploy URL works on staging
  • After merge to main — verify release.yml detects the same set, deploys to prod, Playwright validation passes
  • Run workflow_dispatch with environment: staging — verify all examples build (including standalones)
  • Run workflow_dispatch with plugin_version: next — verify Zephyr plugin upgrade works before build

Related

  • zephyr-cloud-io's turbo.json / development.yml / release.yml — the pattern this PR cribs from

Open questions

  • Standalones in workspace later? Worth a follow-up PR to try folding module-federation/airbnb-clone and module-federation/react-vite-rspack-webpack (no lockfiles, low risk) — gains affected detection for two more examples.
  • build:preview task? zephyr-cloud-io has two turbo tasks (build + build:preview). Skipped here since ZE_ENV alone cleanly separates envs. Add if there's a reason PRs need a distinct task shape.

…split

Replaces the monolithic build-deploy-test.yml + 402-line build-packages.ts
with Turborepo-orchestrated builds, env-aware deploys per trigger, and
affected-only execution on PRs and main.

Infrastructure:

- turbo.json at root — Depot remote cache (cache.depot.dev, team l727rgm5x8),
  globalEnv covers ZE_* + PUBLIC_* for proper cache separation per env,
  build task with explicit inputs/outputs per bundler config file type
- .github/actions/turbo-affected — composite action that runs
  `turbo ls --affected`, filters by path prefix, outputs JSON matrix
  (copied from zephyr-cloud-io)
- .github/actions/setup-node — standard pnpm + node 24 + install step
- pnpm-workspace.yaml — documented why build-systems/** and the two
  multi-bundler standalones stay excluded (own lockfiles / pinned deps)

Workflows:

- development.yml — PR trigger. Runs `turbo build --affected` against
  the PR base SHA, deploys to staging. Standalones run in a matrix, each
  gated on its own paths-filter so unchanged standalones are skipped.
- release.yml — push to main. Same affected pattern vs HEAD^1, deploys
  to production. Adds a validate job (Playwright deployment tests)
  gated on successful builds.
- manual.yml — workflow_dispatch + repository_dispatch. User picks
  environment (dev/staging/production), optional plugin upgrade, force
  rebuild. Builds ALL workspace examples + all standalones for testing
  package changes end-to-end. Preserves the prior webhook contract.

Staging vs prod mechanism:
- ZE_ENV env var switches between `staging` and `production` per trigger
- ZE_SECRET_TOKEN switches between ZE_SECRET_TOKEN_STAGING and _PROD
- ZE_API / ZE_API_GATE point at the correct backend per env
- Since ZE_ENV is in turbo's globalEnv, cache is separated across envs

Removed:
- scripts/src/build-packages.ts — custom concurrency + mtime-based
  caching replaced by turbo
- scripts/package.json — dropped build-packages, build-affected,
  build-affected:force, build-affected:list scripts (the latter three
  pointed at a file that never existed). Kept Playwright test scripts
  and the generate/validate metadata scripts.
- .github/workflows/build-deploy-test.yml — replaced by the three new
  workflows above.

Secrets required for CI (some already exist):
- ZE_SECRET_TOKEN_DEV, ZE_SECRET_TOKEN_STAGING, ZE_SECRET_TOKEN_PROD
- TURBO_TOKEN (Depot cache access)
- TURBO_TEAM (repo var — value l727rgm5x8 to share cache with zephyr-cloud-io)

Verified locally:
- pnpm install succeeds at root; turbo 2.9.6 installed
- pnpm exec turbo ls discovers 29 workspace packages
- pnpm exec turbo build --dry-run plans tasks for all 29 cleanly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant