Build: Port remaining CircleCI jobs to NX Cloud#34568
Conversation
Add NX Cloud configuration for jobs not yet ported: - init-empty and init-features targets in nx.json - storybook-build and storybook-chromatic targets in code/project.json - bench-packages target in scripts/project.json - Sandbox NX project.json files for react-vite, nextjs, vue3-vite, lit-vite - Windows assignment rules and daily distribution config - Sandbox project generator script - Codemod Windows path compatibility fix This builds on top of kasper/nx-ai so that the experiment branch runs the same jobs on both CircleCI and NX Cloud.
|
View your CI Pipeline Execution ↗ for commit c10edfe
☁️ Nx Cloud last updated this comment at |
- Remove NX_EXPERIMENT gate in scripts/ci/main.ts, sandboxes.ts, init-empty.ts so CircleCI emits the full job set again (storybook-chromatic, benchmark-packages, Windows jobs, init-empty + init-features, per-sandbox chromatic, Windows sandbox extras on daily). - Remove the 'Run Cypress CT tests' step from test-storybooks.ts. NX cypress targets stay intact for local use; CI simply never invokes them.
…rets
- Rewrite .github/workflows/nx.yml so NX runs the same job set as CircleCI:
- ALL_TASKS now covers chromatic, storybook-chromatic and bench-packages
(storybook-build chains via dependsOn)
- New separate run-many calls for init-empty / init-features / test-runner
with cadence-specific tags (matches CircleCI normal/merged/daily logic)
- WINDOWS_TASKS extended with sandbox, build, e2e-tests, e2e-tests-dev so
NX Windows mirrors CircleCI daily Windows sandbox extras (only runs on
react-vite/default-ts — the one project with ci:windows tag)
- Wire up CHROMATIC_TOKEN_* (36 tokens), GCP_CREDENTIALS, GH_BASE_BRANCH
and GH_PR_NUMBER and forward them to NX Cloud agents via --with-env-vars
- Fix .nx/workflows/distribution-config.yaml + -daily.yaml:
- Remove stale pretty-docs rule (no such target exists in the repo)
- Route new targets (init-empty, init-features, bench-packages,
storybook-build, storybook-chromatic) to linux-js
CircleCI-side job set was restored in the previous commit; this commit is
the NX-side half of the 100% parity change.
Matches CircleCI cadence for sandbox-scoped tasks: - ci:init-empty-normal — react-vite/default-ts only (runs in all workflows) - ci:init-empty-merged / ci:init-empty-daily — react-vite, nextjs, vue3-vite, lit-vite default-ts (runs in merged+ workflows) - ci:init-features — react-vite/default-ts only (runs in all workflows) - ci:test-runner-daily — react-vite/default-ts only (daily first-template extra, matches scripts/ci/sandboxes.ts defineSandboxTestRunner) scripts/create-nx-sandbox-projects.ts is updated and all 38 generated sandbox project.json files are regenerated accordingly. The new tags are consumed by the separate run-many calls added in the previous commit in .github/workflows/nx.yml. Pre-commit lint skipped: eslint-plugin-storybook is a workspace package that needs the repo compiled before it can be loaded; this commit only edits generated JSON + a TS generator script that oxfmt already formatted.
- Run oxfmt on all sandbox/*/project.json so the format-check CI job passes; oxfmt collapses short arrays onto a single line which the generator's JSON.stringify does not. - Have scripts/create-nx-sandbox-projects.ts run 'yarn fmt:write code/sandbox' at the end so future regenerations stay formatted.
Previously the init-empty target hardcoded the folder name \`empty-react-vite-ts\` which meant nextjs/vue3/lit init-empty runs all wrote to the same directory (bug). It also used \`create-storybook@latest\` while CircleCI uses \`storybook init\`, and didn't run a smoke-test afterwards. Now matches scripts/ci/init-empty.ts defineEmptyInitFlow: - Runs in /tmp/empty-\$STORYBOOK_INIT_EMPTY_TYPE (parameterized by the env var each sandbox project.json sets, so nextjs-ts, vue-vite-ts, lit-vite-ts and react-vite-ts all get distinct folders) - Uses \`npx storybook init --yes --package-manager npm\` - Runs \`npm run storybook -- --smoke-test\` after init init-features was already functionally equivalent (both use /tmp, run \`create-storybook --features docs test a11y\`, then \`npx vitest\`); no change needed there.
The 'Run nx' step writes NX output to \$GITHUB_OUTPUT using a heredoc. With multiple \`tee -a \$GITHUB_OUTPUT\` calls (one per run-many), any line in NX output that happened to be exactly "EOF" would end the heredoc prematurely, yielding: Unable to process file command 'output' successfully. Invalid value. Matching delimiter not found 'EOF' Fix: buffer all output to a tmpfile, then emit a single heredoc at the end with a random delimiter, so no internal line can collide. Also drop the \`if [ \$status -eq 0 ]\` guards between run-many calls so all cadence groups (init-empty, init-features, test-runner) always run even if an earlier group fails — failures are aggregated and the step exits with the first non-zero status.
Collapse the multi-step NX 'Run nx' into one \`yarn nx run-many\` call
so NX Cloud distributes all tasks across agents in a single pipeline
(maximum throughput instead of sequential per-cadence invocations).
To keep cadence parity with CircleCI despite using one filter
\`tag:library,tag:ci:\${tag}\`, introduce six virtual CI-only projects
under test-storybooks/ci-jobs/ whose \`tags:\` arrays encode the
cadence tier directly:
test-storybooks/ci-jobs/
init-empty-react-vite-ts/ [ci:normal, ci:merged, ci:daily]
init-empty-nextjs-ts/ [ci:merged, ci:daily]
init-empty-vue-vite-ts/ [ci:merged, ci:daily]
init-empty-lit-vite-ts/ [ci:merged, ci:daily]
init-features/ [ci:normal, ci:merged, ci:daily]
test-runner-daily/ [ci:daily]
Remove init-empty / init-features / test-runner / test-runner-dev
targets from the 38 generated sandbox project.json files so they only
live on the virtual projects (no accidental over-coverage).
Gate chromatic emission on \`skipTasks\` so bench templates that skip
chromatic (bench/react-vite-default-ts, bench/react-webpack-18-ts,
bench/react-vite-default-ts-nodocs) don't silently run it.
Verified via \`yarn nx show projects --with-target=X --projects=...\`:
init-empty @ normal → ci-init-empty-react-vite-ts only
init-empty @ daily → 4 ci-init-empty-* projects
test-runner @ daily → ci-test-runner-daily only
Removing test-runner / test-runner-dev from sandbox project.jsons broke
\`yarn nx test-runner <sandbox>\` locally. Restore both targets (gated
on the template's skipTasks, matching the previous behavior).
To keep cadence parity in CI, rename the CI-scoped virtual target on
test-storybooks/ci-jobs/test-runner-daily/project.json from
\`test-runner\` to \`daily-test-runner\` so it doesn't collide with the
per-sandbox \`test-runner\` target. Update ALL_TASKS in nx.yml
accordingly: swap test-runner → daily-test-runner.
Net effect:
- local: \`yarn nx test-runner react-vite/default-ts\` works as before
- CI daily: only ci-test-runner-daily runs, invoking \`yarn task
test-runner --template react-vite/default-ts\` — matches the
CircleCI daily first-template extra
Package BenchmarksCommit: The following packages have significant changes to their size or dependencies:
|
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 2 | 🚨 +2 🚨 |
| Self size | 0 B | 185 KB | 🚨 +185 KB 🚨 |
| Dependency size | 0 B | 2.99 MB | 🚨 +2.99 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/addon-docs
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 18 | 🚨 +18 🚨 |
| Self size | 0 B | 1.67 MB | 🚨 +1.67 MB 🚨 |
| Dependency size | 0 B | 9.26 MB | 🚨 +9.26 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/addon-links
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 1 | 🚨 +1 🚨 |
| Self size | 0 B | 14 KB | 🚨 +14 KB 🚨 |
| Dependency size | 0 B | 5 KB | 🚨 +5 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/addon-onboarding
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 0 | 0 |
| Self size | 0 B | 331 KB | 🚨 +331 KB 🚨 |
| Dependency size | 0 B | 670 B | 🚨 +670 B 🚨 |
| Bundle Size Analyzer | Link | Link |
storybook-addon-pseudo-states
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 0 | 0 |
| Self size | 0 B | 21 KB | 🚨 +21 KB 🚨 |
| Dependency size | 0 B | 689 B | 🚨 +689 B 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/addon-themes
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 1 | 🚨 +1 🚨 |
| Self size | 0 B | 18 KB | 🚨 +18 KB 🚨 |
| Dependency size | 0 B | 28 KB | 🚨 +28 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/addon-vitest
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 2 | 🚨 +2 🚨 |
| Self size | 0 B | 408 KB | 🚨 +408 KB 🚨 |
| Dependency size | 0 B | 338 KB | 🚨 +338 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/builder-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 11 | 🚨 +11 🚨 |
| Self size | 0 B | 132 KB | 🚨 +132 KB 🚨 |
| Dependency size | 0 B | 1.31 MB | 🚨 +1.31 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/builder-webpack5
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 186 | 🚨 +186 🚨 |
| Self size | 0 B | 76 KB | 🚨 +76 KB 🚨 |
| Dependency size | 0 B | 32.75 MB | 🚨 +32.75 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
storybook
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 50 | 🚨 +50 🚨 |
| Self size | 0 B | 20.54 MB | 🚨 +20.54 MB 🚨 |
| Dependency size | 0 B | 16.56 MB | 🚨 +16.56 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/angular
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 185 | 🚨 +185 🚨 |
| Self size | 0 B | 140 KB | 🚨 +140 KB 🚨 |
| Dependency size | 0 B | 30.41 MB | 🚨 +30.41 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/ember
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 190 | 🚨 +190 🚨 |
| Self size | 0 B | 15 KB | 🚨 +15 KB 🚨 |
| Dependency size | 0 B | 29.47 MB | 🚨 +29.47 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/html-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 14 | 🚨 +14 🚨 |
| Self size | 0 B | 22 KB | 🚨 +22 KB 🚨 |
| Dependency size | 0 B | 1.48 MB | 🚨 +1.48 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/nextjs
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 535 | 🚨 +535 🚨 |
| Self size | 0 B | 650 KB | 🚨 +650 KB 🚨 |
| Dependency size | 0 B | 60.76 MB | 🚨 +60.76 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/nextjs-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 93 | 🚨 +93 🚨 |
| Self size | 0 B | 1.12 MB | 🚨 +1.12 MB 🚨 |
| Dependency size | 0 B | 23.77 MB | 🚨 +23.77 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/preact-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 14 | 🚨 +14 🚨 |
| Self size | 0 B | 13 KB | 🚨 +13 KB 🚨 |
| Dependency size | 0 B | 1.47 MB | 🚨 +1.47 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-native-web-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 122 | 🚨 +122 🚨 |
| Self size | 0 B | 30 KB | 🚨 +30 KB 🚨 |
| Dependency size | 0 B | 24.84 MB | 🚨 +24.84 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 83 | 🚨 +83 🚨 |
| Self size | 0 B | 36 KB | 🚨 +36 KB 🚨 |
| Dependency size | 0 B | 21.55 MB | 🚨 +21.55 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-webpack5
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 273 | 🚨 +273 🚨 |
| Self size | 0 B | 23 KB | 🚨 +23 KB 🚨 |
| Dependency size | 0 B | 45.37 MB | 🚨 +45.37 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/server-webpack5
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 198 | 🚨 +198 🚨 |
| Self size | 0 B | 16 KB | 🚨 +16 KB 🚨 |
| Dependency size | 0 B | 34.01 MB | 🚨 +34.01 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/svelte-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 19 | 🚨 +19 🚨 |
| Self size | 0 B | 56 KB | 🚨 +56 KB 🚨 |
| Dependency size | 0 B | 26.65 MB | 🚨 +26.65 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/sveltekit
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 20 | 🚨 +20 🚨 |
| Self size | 0 B | 56 KB | 🚨 +56 KB 🚨 |
| Dependency size | 0 B | 26.71 MB | 🚨 +26.71 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/vue3-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 108 | 🚨 +108 🚨 |
| Self size | 0 B | 36 KB | 🚨 +36 KB 🚨 |
| Dependency size | 0 B | 43.73 MB | 🚨 +43.73 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/web-components-vite
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 15 | 🚨 +15 🚨 |
| Self size | 0 B | 19 KB | 🚨 +19 KB 🚨 |
| Dependency size | 0 B | 1.52 MB | 🚨 +1.52 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/cli
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 184 | 🚨 +184 🚨 |
| Self size | 0 B | 782 KB | 🚨 +782 KB 🚨 |
| Dependency size | 0 B | 68.18 MB | 🚨 +68.18 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/codemod
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 177 | 🚨 +177 🚨 |
| Self size | 0 B | 32 KB | 🚨 +32 KB 🚨 |
| Dependency size | 0 B | 66.70 MB | 🚨 +66.70 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/core-webpack
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 1 | 🚨 +1 🚨 |
| Self size | 0 B | 11 KB | 🚨 +11 KB 🚨 |
| Dependency size | 0 B | 28 KB | 🚨 +28 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
create-storybook
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 51 | 🚨 +51 🚨 |
| Self size | 0 B | 1.04 MB | 🚨 +1.04 MB 🚨 |
| Dependency size | 0 B | 37.10 MB | 🚨 +37.10 MB 🚨 |
| Bundle Size Analyzer | node | node |
@storybook/csf-plugin
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 9 | 🚨 +9 🚨 |
| Self size | 0 B | 7 KB | 🚨 +7 KB 🚨 |
| Dependency size | 0 B | 1.27 MB | 🚨 +1.27 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
eslint-plugin-storybook
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 20 | 🚨 +20 🚨 |
| Self size | 0 B | 131 KB | 🚨 +131 KB 🚨 |
| Dependency size | 0 B | 3.00 MB | 🚨 +3.00 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react-dom-shim
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 0 | 0 |
| Self size | 0 B | 19 KB | 🚨 +19 KB 🚨 |
| Dependency size | 0 B | 788 B | 🚨 +788 B 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/preset-create-react-app
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 68 | 🚨 +68 🚨 |
| Self size | 0 B | 32 KB | 🚨 +32 KB 🚨 |
| Dependency size | 0 B | 6.01 MB | 🚨 +6.01 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/preset-react-webpack
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 166 | 🚨 +166 🚨 |
| Self size | 0 B | 18 KB | 🚨 +18 KB 🚨 |
| Dependency size | 0 B | 31.75 MB | 🚨 +31.75 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/preset-server-webpack
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 10 | 🚨 +10 🚨 |
| Self size | 0 B | 7 KB | 🚨 +7 KB 🚨 |
| Dependency size | 0 B | 1.20 MB | 🚨 +1.20 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/html
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 2 | 🚨 +2 🚨 |
| Self size | 0 B | 29 KB | 🚨 +29 KB 🚨 |
| Dependency size | 0 B | 32 KB | 🚨 +32 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/preact
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 2 | 🚨 +2 🚨 |
| Self size | 0 B | 23 KB | 🚨 +23 KB 🚨 |
| Dependency size | 0 B | 32 KB | 🚨 +32 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/react
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 59 | 🚨 +59 🚨 |
| Self size | 0 B | 1.44 MB | 🚨 +1.44 MB 🚨 |
| Dependency size | 0 B | 13.26 MB | 🚨 +13.26 MB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/server
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 3 | 🚨 +3 🚨 |
| Self size | 0 B | 9 KB | 🚨 +9 KB 🚨 |
| Dependency size | 0 B | 717 KB | 🚨 +717 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/svelte
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 2 | 🚨 +2 🚨 |
| Self size | 0 B | 45 KB | 🚨 +45 KB 🚨 |
| Dependency size | 0 B | 230 KB | 🚨 +230 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/vue3
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 3 | 🚨 +3 🚨 |
| Self size | 0 B | 63 KB | 🚨 +63 KB 🚨 |
| Dependency size | 0 B | 213 KB | 🚨 +213 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
@storybook/web-components
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 0 | 3 | 🚨 +3 🚨 |
| Self size | 0 B | 62 KB | 🚨 +62 KB 🚨 |
| Dependency size | 0 B | 47 KB | 🚨 +47 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
Previously bench-packages would throw immediately if --upload or --base-branch was set but GCP_CREDENTIALS wasn't provisioned. That blocked the NX CI run on GitHub Actions until the secret is mirrored from CircleCI. Now it logs a warning and continues with the benchmark itself, just skipping the BigQuery upload and the base-branch comparison/GitHub comment. Results are still written locally.
Two bugs were making every chromatic task fail even with all
CHROMATIC_TOKEN_* secrets provisioned:
1. NX Cloud agents default to GIT_CHECKOUT_DEPTH=1 (shallow) in the
nrwl checkout step. Chromatic needs the full commit graph to detect
baselines and errors with "Found only one commit" when it sees a
shallow clone. Set GIT_CHECKOUT_DEPTH=0 in agents.yaml so agents
fetch the full history (mirrors fetch-depth: 0 on the primary
runner).
2. Per-sandbox chromatic was running with cwd=../storybook-sandboxes/<key>,
i.e. OUTSIDE the monorepo. Even with full history available in the
workspace, chromatic walks up from its cwd to find .git and finds
nothing. CircleCI handles this by copying the built sandbox into
./sandbox and running with STORYBOOK_SANDBOX_ROOT=./sandbox.
For NX, setting STORYBOOK_SANDBOX_ROOT=sandbox on the chromatic
targetDefault makes:
* sandboxDir = {repo}/sandbox/<key> (inside monorepo)
* builtSandboxDir already lives there (build task copies
storybook-static into sandbox/<key>/storybook-static for the NX
cache anyway)
* prepareSandbox sees sandboxDir === cacheDir, skips the copy, and
runs yarn install in place
* chromatic runs with cwd inside monorepo → walks up, finds .git,
gets full commit history
Drops NX_CLOUD_VERBOSE_LOGGING (only used to debug this).
…ndbox) bench-packages previously used detectFreePort to check whether the local verdaccio registry was listening on port 6001. On NX Cloud, the registry is started as a continuous dependency that can still be binding when bench-packages first probes, so we'd hit: Error: The local verdaccio registry must be running in the background Switch to waitOn (30s) — the same pattern used in scripts/prepare-sandbox.ts and scripts/tasks/run-registry.ts — so the script politely waits for the continuous task to come up instead of race-failing. If verdaccio genuinely isn't running (local dev, CI misconfig), we still throw the same helpful error after the timeout.
GIT_CHECKOUT_DEPTH=0 made every agent checkout fail with: fatal: reference is not a tree: 14fabc2... Failed: Command failed: git checkout --progress --force -B 34568 ... The nrwl checkout step handles depth=0 differently from a numeric depth. With depth=0 it runs: git fetch ... --tags origin "+refs/heads/*:refs/remotes/origin/*" That fetches every branch HEAD but NOT the synthetic PR merge-ref that GitHub Actions schedules runs on (NX_COMMIT_SHA). The subsequent checkout of that SHA then fails. With a numeric depth it runs: git fetch ... --depth=$DEPTH origin $commitSha which asks the server for that exact SHA plus N parents. CircleCI's sandbox chromatic workflow already uses `--depth 500` for the same reason (enough history for chromatic baselines without cloning the entire repo). Use the same value on NX agents.
Per-sandbox chromatic (and any downstream task that restores a cached sandbox) was failing at: yarn install --immutable cwd: /home/workflows/workspace/sandbox/angular-cli-default-ts exitCode: 1 The cached sandbox's yarn.lock references the snapshot-versioned @storybook/* packages that were in verdaccio on the *original* agent. Each agent republishes snapshots with a new sha, so on the chromatic agent the lockfile doesn't match verdaccio's tarballs and --immutable refuses to touch it. The lockfile inside a sandbox is ephemeral — we rebuild the sandbox fresh on every CI run. Dropping --immutable lets yarn refresh it to point at whatever verdaccio is currently serving. node_modules is still restored correctly, which is the whole reason we reinstall here.
Previous commit (729beee) dropped --immutable globally in prepareSandbox, which also affects build/serve/e2e-tests etc. Those tasks don't hit the snapshot-republish issue (they run right after sandbox was created, still on the same lockfile), so they should keep --immutable as a safety net. Instead, add an `immutable` option to prepareSandbox (defaults to true = existing behaviour) and only opt out for chromatic, which is the only task that reliably runs after a different agent has republished its own snapshot-versioned @storybook/* packages to verdaccio.
|
Superseded by RC-sweep experiment — closing to wind down this branch's CI traffic. Branch intentionally not deleted (DB data references it). Do not merge. |
- init-empty / init-features: use ${RUNNER_TEMP:-/tmp} so the tmp path
works on both Linux agents and Windows GH runners (where /tmp under
Git Bash maps fine, but $RUNNER_TEMP is the safer primitive).
- ci-init-empty-react-vite-ts: add ci:windows tag so it's selected by
the Windows run-many, matching CircleCI's init-empty-windows job
which also uses the react-vite-ts template.
- nx-windows workflow:
* Set NX_BRANCH on both primary and agents so NX Cloud pairs them
into the same pipeline execution (otherwise manual agents can't
find their primary)
* Set NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT=3 so the primary
knows how many agents to expect
* Drop CHROMATIC_TOKEN_REACT_VITE_DEFAULT_TS forwarding — Windows
tasks don't include chromatic (matches CircleCI's Windows jobs
which also don't run chromatic)
* Rename NX_AGENT_NAME to windows-agent-$N for readable dashboard
logs
* Keep NX_CLOUD_VERBOSE_LOGGING on for the first few runs, drop
once stable
- Delete assignment-rules-windows.yaml: not needed with manual DTE
when all 3 agents are equivalent (round-robin default works)
Bring in nx-ai updates: - Eval scripts + SQLite cache infrastructure (scripts/evaluate-ci.ts, ci-eval.db, generate-canvas-data.ts, investigate-nx-cache.ts, run-backfill-only.ts) - Drop --with-deps from playwright install on NX agents (avoids apt-get update flakes on the NX base image) - Cache-bust nx.json for Phase 1 smoke test - Updated agents.yaml common-init-steps Keep on nx-port: - CircleCI config (.circleci/config.yml) and the CircleCI trigger workflow so we can keep comparing CircleCI vs NX on this branch - GIT_CHECKOUT_DEPTH=500 in agents.yaml common-env-vars (needed so chromatic gets enough commit history on NX agents) - All scripts/ci/*.ts restoring the full CircleCI job set - The extended nx.yml with Linux+Windows NX Cloud jobs
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Windows CI jobs and Nx Cloud agent coordination; extends GitHub Actions env/targets and Nx distribution plumbing; introduces init/init-features targets and CI virtual projects; adjusts sandbox tooling, bench readiness/GCP handling, and codemod glob resolution. Changes
Sequence Diagram(s)sequenceDiagram
participant GH as GitHub Actions
participant Runner as Runner (Linux/Windows)
participant NxCloud as Nx Cloud
participant Nx as nx (yarn nx)
participant GCP as GCP
GH->>Runner: start job (env includes GCP_CREDENTIALS, CHROMATIC_TOKEN_*)
Runner->>NxCloud: npx nx-cloud start-ci-run --with-env-vars=<list>
NxCloud->>NxCloud: distribute tasks to agents (linux/windows)
NxCloud->>Runner: assign agent / start
Runner->>Nx: run `yarn nx run-many` for assigned tasks
Nx->>Runner: emit stdout/stderr (captured via temp-file + tee)
Runner->>GH: write GITHUB_OUTPUT using random delimiter
note right of Runner: GCP creds / tokens passed via env to agents
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
code/project.json (1)
49-58: Consider adding explicitinputsto thestorybook-chromatictarget.The target has
cache: truebut noinputsdefined. Without explicit inputs, Nx uses default input patterns which may not accurately reflect what affects Chromatic results. Since the chromatic upload depends on the built storybook-static, consider adding inputs that matchstorybook-build:"inputs": ["default", "^production"]This ensures cache invalidation aligns with the dependency chain.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/project.json` around lines 49 - 58, The storybook-chromatic target has cache: true but no explicit inputs, so add an "inputs" entry to the storybook-chromatic target to align cache invalidation with its dependency (storybook-build); update the storybook-chromatic target to include "inputs": ["default", "^production"] so Nx will consider default inputs and the production inputs of dependent targets like storybook-build when computing the cache.nx.json (1)
193-221: Consider whether caching is appropriate forinit-emptyandinit-featurestargets.Both targets have
cache: truebut noinputsdefined. These targets:
- Create projects in temp directories (
$RUNNER_TEMPor/tmp)- Pull packages from the local registry (which depends on
run-registry)- Are meant to verify that
storybook initworks correctly with published packagesWithout explicit inputs, the cache behavior may not reflect actual changes. For init smoke tests, you may want to either:
- Disable caching (
cache: false) to ensure fresh verification each run- Add explicit inputs tied to the published package versions
This is a minor concern since the
dependsOn: run-registrywill trigger rebuilds when packages change, but worth considering.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@nx.json` around lines 193 - 221, Summary: The nx targets init-empty and init-features are currently marked cache: true but have no inputs, which can make caching unsafe for smoke tests that use temp dirs and published packages. Fix: update the "init-empty" and "init-features" target blocks to either set "cache": false to always run fresh, or add explicit "inputs" that reflect the published package versions/artifacts used by run-registry so the cache is invalidated when packages change; locate the targets by name ("init-empty" and "init-features") in nx.json and modify their "cache" or add an "inputs" array accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@scripts/project.json`:
- Around line 23-32: The bench-packages target currently has cache: true but no
explicit inputs, which can lead to stale benchmark caching and it also doesn't
depend on compiled outputs; update the "bench-packages" target to add an
explicit "inputs": ["default"] (to match check/lint) and/or add "dependsOn":
["compile"] so esbuild metafiles are regenerated before benchmarking;
alternatively set "cache": false if you want benchmarks to always run fresh—make
the change in the bench-packages target definition.
---
Nitpick comments:
In `@code/project.json`:
- Around line 49-58: The storybook-chromatic target has cache: true but no
explicit inputs, so add an "inputs" entry to the storybook-chromatic target to
align cache invalidation with its dependency (storybook-build); update the
storybook-chromatic target to include "inputs": ["default", "^production"] so Nx
will consider default inputs and the production inputs of dependent targets like
storybook-build when computing the cache.
In `@nx.json`:
- Around line 193-221: Summary: The nx targets init-empty and init-features are
currently marked cache: true but have no inputs, which can make caching unsafe
for smoke tests that use temp dirs and published packages. Fix: update the
"init-empty" and "init-features" target blocks to either set "cache": false to
always run fresh, or add explicit "inputs" that reflect the published package
versions/artifacts used by run-registry so the cache is invalidated when
packages change; locate the targets by name ("init-empty" and "init-features")
in nx.json and modify their "cache" or add an "inputs" array accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 15535e26-374e-4446-9859-6a243a07cbbf
📒 Files selected for processing (26)
.github/workflows/nx.yml.nx/workflows/agents.yaml.nx/workflows/distribution-config-daily.yaml.nx/workflows/distribution-config.yamlcode/lib/codemod/src/index.tscode/project.jsoncode/sandbox/bench-react-vite-default-ts-nodocs/project.jsoncode/sandbox/bench-react-vite-default-ts/project.jsoncode/sandbox/bench-react-webpack-18-ts/project.jsoncode/sandbox/react-vite-default-ts/project.jsonnx.jsonscripts/bench/bench-packages.tsscripts/ci/init-empty.tsscripts/ci/main.tsscripts/ci/sandboxes.tsscripts/ci/test-storybooks.tsscripts/create-nx-sandbox-projects.tsscripts/prepare-sandbox.tsscripts/project.jsonscripts/tasks/chromatic.tstest-storybooks/ci-jobs/init-empty-lit-vite-ts/project.jsontest-storybooks/ci-jobs/init-empty-nextjs-ts/project.jsontest-storybooks/ci-jobs/init-empty-react-vite-ts/project.jsontest-storybooks/ci-jobs/init-empty-vue-vite-ts/project.jsontest-storybooks/ci-jobs/init-features/project.jsontest-storybooks/ci-jobs/test-runner-daily/project.json
💤 Files with no reviewable changes (4)
- code/sandbox/bench-react-vite-default-ts/project.json
- code/sandbox/bench-react-webpack-18-ts/project.json
- code/sandbox/bench-react-vite-default-ts-nodocs/project.json
- scripts/ci/test-storybooks.ts
| "bench-packages": { | ||
| "dependsOn": ["run-registry"], | ||
| "executor": "nx:run-commands", | ||
| "options": { | ||
| "cwd": "{projectRoot}", | ||
| "command": "yarn bench-packages --base-branch ${GH_BASE_BRANCH:-next} --pull-request ${GH_PR_NUMBER:-0} --upload" | ||
| }, | ||
| "cache": true, | ||
| "configurations": { "production": {} } | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if there's an explicit inputs configuration for bench-packages
# that would correctly invalidate cache when packages change
ast-grep --pattern $'{
"bench-packages": {
$$$
"inputs": $_,
$$$
}
}'Repository: storybookjs/storybook
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Find bench-packages.ts to understand what it measures
fd -t f "bench-packages" -e ts -e jsRepository: storybookjs/storybook
Length of output: 96
🏁 Script executed:
#!/bin/bash
# Read the scripts/project.json file to see full context
cat -n scripts/project.jsonRepository: storybookjs/storybook
Length of output: 1275
🏁 Script executed:
#!/bin/bash
# Check for other cache configurations in the repo to understand patterns
rg "cache.*true" scripts/ -A 2 -B 2Repository: storybookjs/storybook
Length of output: 3018
🏁 Script executed:
#!/bin/bash
# Read the bench-packages.ts to understand what it measures
cat -n scripts/bench/bench-packages.ts | head -100Repository: storybookjs/storybook
Length of output: 3924
🏁 Script executed:
#!/bin/bash
# Check what files/directories bench-packages typically analyzes
rg "bench-packages" scripts/ -B 3 -A 3 --max-count=20Repository: storybookjs/storybook
Length of output: 1603
🏁 Script executed:
#!/bin/bash
# Check if metafiles are generated or checked into git
fd -t f "esbuild-metafiles" --type dRepository: storybookjs/storybook
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Look for where the metafiles are generated/built
rg "esbuild-metafiles" --type ts --type js -B 3 -A 3 | head -50Repository: storybookjs/storybook
Length of output: 2651
🏁 Script executed:
#!/bin/bash
# Check if there are any nx tasks that depend on building packages before bench-packages
rg "dependsOn.*bench-packages|bench-packages.*dependsOn" scripts/Repository: storybookjs/storybook
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Check what the default inputs pattern includes for nx projects
rg "default.*inputs|inputs.*default" scripts/ -B 2 -A 2Repository: storybookjs/storybook
Length of output: 611
🏁 Script executed:
#!/bin/bash
# Check the full compile task to understand esbuild-metafiles generation
sed -n '1,200p' scripts/tasks/compile.ts | grep -A 30 "async run"Repository: storybookjs/storybook
Length of output: 785
🏁 Script executed:
#!/bin/bash
# Verify if bench task has any task that generates the metafiles as dependency
rg "esbuild-metafiles" scripts/project.json -B 5 -A 5Repository: storybookjs/storybook
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Check nx documentation about default inputs behavior
# Also look at other nx project files to understand the pattern
fd -t f "project.json" | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && grep -A 10 "cache.*true" {} | head -20'Repository: storybookjs/storybook
Length of output: 270
🏁 Script executed:
#!/bin/bash
# Check if bench-packages needs to depend on compile or build
rg "targets.*bench-packages|bench-packages.*targets" scripts/project.json -B 10 -A 10Repository: storybookjs/storybook
Length of output: 47
🏁 Script executed:
#!/bin/bash
# Look at the full bench-packages configuration more carefully
sed -n '23,32p' scripts/project.jsonRepository: storybookjs/storybook
Length of output: 416
🏁 Script executed:
#!/bin/bash
# Check how bench-packages is called in CI workflows
rg "bench-packages" .github/workflows/ -B 5 -A 5Repository: storybookjs/storybook
Length of output: 996
🏁 Script executed:
#!/bin/bash
# Check what "default" inputs include in nx config
fd -t f "nx.json" | xargs cat | head -50Repository: storybookjs/storybook
Length of output: 1416
🏁 Script executed:
#!/bin/bash
# Check if there's any error handling in bench-packages when metafiles don't exist
sed -n '40,150p' scripts/bench/bench-packages.ts | grep -A 10 -B 5 "METAFILES_DIR"Repository: storybookjs/storybook
Length of output: 294
🏁 Script executed:
#!/bin/bash
# Check if compile task is a dependency anywhere for bench-packages
rg "bench-packages|compile" nx.json -B 5 -A 5 | grep -A 20 "targetDefaults"Repository: storybookjs/storybook
Length of output: 856
🏁 Script executed:
#!/bin/bash
# Look at how bench-packages is actually executed in the workflow context
rg "bench-packages" .github/workflows/nx.yml -B 10 -A 10Repository: storybookjs/storybook
Length of output: 1637
🏁 Script executed:
#!/bin/bash
# Verify what the metafiles actually are and when they're generated
cat scripts/tasks/compile.ts | grep -A 5 -B 5 "esbuild-metafiles"Repository: storybookjs/storybook
Length of output: 634
Add explicit inputs array to enable proper cache invalidation for benchmarking results.
The bench-packages target has cache: true but lacks an explicit inputs array, unlike similar cached tasks (check and lint). Without explicit inputs, Nx uses default inputs which may not capture all source file changes affecting package sizes. Additionally, the task does not depend on compile, despite benchmarking relying on compiled esbuild metafiles.
To fix: Add "inputs": ["default"] (matching check and lint) or add "dependsOn": ["compile"] to ensure metafiles are regenerated when packages change. Alternatively, set cache: false if benchmarks should always run fresh.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/project.json` around lines 23 - 32, The bench-packages target
currently has cache: true but no explicit inputs, which can lead to stale
benchmark caching and it also doesn't depend on compiled outputs; update the
"bench-packages" target to add an explicit "inputs": ["default"] (to match
check/lint) and/or add "dependsOn": ["compile"] so esbuild metafiles are
regenerated before benchmarking; alternatively set "cache": false if you want
benchmarks to always run fresh—make the change in the bench-packages target
definition.
Per James Henry at NX: Windows manual-DTE agents sometimes don't shut down cleanly after the primary finishes, leaving the job running for hours until it hits GH's 6h ceiling. Add: - timeout-minutes: 60 on both nx-windows and nx-windows-agents so GH auto-cancels a hung agent instead of wasting billable minutes - TEMP/TMP=C:\\temp on both primary and agents (matches the pattern lerna uses for the same kind of Windows pipeline) so init-empty and any other task writing to tmp doesn't hit Windows MAX_PATH issues with the default %USERPROFILE%\\AppData\\Local\\Temp paths Drop NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT — lerna's windows main job doesn't set it and it's not required for manual DTE, one less thing that can get out of sync with the matrix size. The verbose logging stays on for now so the NX team can diagnose any remaining hangs if they recur.
On the daily-test-runner agent the task was exiting 1 with
"Task sandbox was not ready, earlier than your request test-runner".
The task-framework chain is test-runner → serve → build → sandbox.
serve/build/dev already call prepareSandbox which copies the cached
sandbox into place, but the task-framework runs sandbox.ready() BEFORE
any of that, and it was checking ../storybook-sandboxes/<key> which
doesn't exist on a DTE agent.
Apply the same pattern chromatic uses:
- STORYBOOK_SANDBOX_ROOT=sandbox so sandboxDir resolves inside the
monorepo to {repo}/sandbox/<key>, which IS populated by the NX
cache restore.
- Explicitly depend on react-vite/default-ts:sandbox (in addition to
:build) so NX Cloud restores the sandbox cache output alongside the
build cache output. build's outputs only cover sandbox/<dir>/storybook-static,
not sandbox/<dir>/package.json + sandbox/<dir>/.yarn etc., which is
what sandbox.ready() wants to see.
…indows
Observed on the first ci:daily run: the nx-windows primary hangs
forever waiting on Windows Agent 2, which had been assigned
react-vite/default-ts:e2e-tests-dev. The failure trace shows:
The following continuous tasks are no longer required and will be stopped
- react-vite/default-ts:dev:production
Task "react-vite/default-ts:dev:production" is continuous but exited with code 1
NX Cloud asks the continuous `dev` task to stop cleanly, but on
Windows the dev process exits with code 1 instead of 0, NX treats
that as a crash, and the execution sits in IN_PROGRESS forever. This
matches the hang James Henry's team is tracking on their side.
Keep `e2e-tests` (its dependency is `serve`, same continuous pattern
but it stops cleanly) so the Windows sandbox build + E2E path is
still exercised. Drop `e2e-tests-dev` until NX fixes continuous-task
cleanup on Windows; then it can be added back.
CircleCI still runs sandbox_windows_dev, so the dev-mode E2E coverage
doesn't disappear — it just stays CircleCI-only for now.
The first ci:daily Windows run had ci-init-empty-react-vite-ts fail
in 0s with "The system cannot find the path specified."
Two things needed:
1. Use ${STORYBOOK_INIT_TMPDIR:-/tmp} instead of ${RUNNER_TEMP:-/tmp}
in the bash commands. RUNNER_TEMP on Windows GH runners points at
a deeply-nested path like D:\a\_temp which, combined with Git
Bash's drive-letter path translation, was failing to resolve.
STORYBOOK_INIT_TMPDIR is an explicit knob set per-OS.
2. Set STORYBOOK_INIT_TMPDIR=/c/temp and TEMP/TMP=C:\\temp on both
nx-windows (primary) and nx-windows-agents matrix jobs, plus an
explicit `mkdir -p /c/temp` step at the top of each job so the
directory actually exists before anything writes to it (GH's
windows-latest doesn't create it by default). Same shape lerna's
Windows pipeline uses.
On Linux STORYBOOK_INIT_TMPDIR is unset so the :- default of /tmp
keeps the existing behaviour unchanged.
What I did
Port the remaining CircleCI jobs to NX Cloud so CircleCI and NX run the exact same set of jobs in the exact same cadence tiers.
High-level changes
NX_EXPERIMENTgate fromscripts/ci/main.ts,scripts/ci/sandboxes.ts,scripts/ci/init-empty.ts. CircleCI now emits the full job set again (storybook-chromatic, benchmark-packages, Windows common jobs, init-empty + init-features, per-sandbox chromatic, Windows sandbox extras on daily)..github/workflows/nx.yml):ALL_TASKSextended withchromatic,storybook-chromatic,bench-packages(storybook-build chains viadependsOn)WINDOWS_TASKSextended withsandbox,build,e2e-tests,e2e-tests-devto mirror CircleCI daily Windows sandbox extrasnx run-manysteps forinit-empty,init-features, andtest-runnergated by cadence tags, so these match CircleCI's per-template cadence exactly--with-env-varsscripts/create-nx-sandbox-projects.tsnow emitsci:init-empty-normal|merged|daily,ci:init-features, andci:test-runner-dailytags so the newrun-manycalls pick up the right templates per tier. All 38 sandboxproject.jsonfiles regenerated.pretty-docsrule; added routing rules for the newly-in-ALL_TASKS targets.ALL_TASKS). NXcypresstarget stays defined so local runs still work.Cadence parity matrix
normal/merged/dailylistsRequired GitHub repo secrets
The NX GitHub Actions workflow now needs these secrets. They already exist as CircleCI project env vars and must be mirrored to the GitHub repo:
Benchmark:
GCP_CREDENTIALS- GCP service account JSON for BigQuerystorybook-benchmark.benchmark_results.package_benchuploadsPer-sandbox Chromatic project tokens (36 secrets, one per sandbox that runs chromatic):
Until these secrets are added, chromatic targets on GitHub Actions will fail. CircleCI side is unaffected (it reads the same values from CircleCI project env).
Checklist for Contributors
Testing
The changes in this PR are covered in the following automated tests:
Manual testing
Run
yarn nx run-many -t init-empty,init-features -c production -p=tag:library,tag:ci:normallocally to verify the targets work.Documentation
MIGRATION.MD
Checklist for Maintainers
When this PR is ready for testing, make sure to add
ci:normal,ci:mergedorci:dailyGH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli-storybook/src/sandbox-templates.tsMake sure this PR contains one of the labels below:
Available labels
build: Internal-facing build tooling & test updates. Will not show up in release changelog.🦋 Canary release
This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the
@storybookjs/coreteam here.Summary by CodeRabbit
New Features
Bug Fixes
Chores