Skip to content

Eval: Add sync-storybook-version harness + --skip-automigrations upgrade flag#34612

Merged
yannbf merged 4 commits into
project/sb-agentic-setupfrom
kasper/eval-sync-storybook-version
Apr 28, 2026
Merged

Eval: Add sync-storybook-version harness + --skip-automigrations upgrade flag#34612
yannbf merged 4 commits into
project/sb-agentic-setupfrom
kasper/eval-sync-storybook-version

Conversation

@kasperpeulen
Copy link
Copy Markdown
Member

@kasperpeulen kasperpeulen commented Apr 22, 2026

Closes #

What I did

This PR adds a helper for updating the benchmark repositories used by the eval suite to a chosen Storybook version.

  • Added scripts/eval/sync-storybook-version.ts, exposed as yarn eval:sync-storybook-version.
  • For each selected benchmark repo, the script clones if needed, verifies the working tree is clean, checks out and fast-forwards the configured branch, installs dependencies, runs the Storybook upgrade, then commits and pushes the resulting dependency updates.
  • The upgrade runs from the repo root so workspace package managers can resolve the correct package.json even when .storybook lives in a subpackage.
  • Added --skip-automigrations to storybook upgrade, which keeps these benchmark-repo commits focused on dependency changes while still running the rest of the upgrade flow.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

scripts/eval/sync-storybook-version.test.ts covers install/upgrade ordering, no-op runs when the target version is already installed, dirty-tree failure, auto-cloning missing repos, and push behavior.

Manual testing

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

  1. Run node scripts/eval/sync-storybook-version.ts --version 0.0.0-pr-34612-sha-d8de7419 --project mealdrop from the repository root.
  2. Inspect $REPOS_DIR/mealdrop and confirm the script updates Storybook dependencies, creates a single upgrade commit, and pushes it.
  3. Optionally rerun without --project mealdrop to apply the same update to the full benchmark set.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Updated scripts/eval/README.md with the new sync workflow.

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-34612-sha-d8de7419. Try it out in a new sandbox by running npx storybook@0.0.0-pr-34612-sha-d8de7419 sandbox or in an existing project with npx storybook@0.0.0-pr-34612-sha-d8de7419 upgrade.

More information
Published version 0.0.0-pr-34612-sha-d8de7419
Triggered by @kasperpeulen
Repository storybookjs/storybook
Branch kasper/eval-sync-storybook-version
Commit d8de7419
Datetime Wed Apr 22 12:56:05 UTC 2026 (1776862565)
Workflow run 24779466678

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=34612

Adds `scripts/eval/sync-storybook-version.ts`, which bumps every
benchmark repo to a given Storybook version (stable or PR canary) in
one pass: clone missing repos, fail fast on dirty trees, run
`npx storybook@<version> upgrade --skip-automigrations` from each
repo root, then commit and push the resulting dep bumps.

To keep those commits free of source rewrites, adds a
`--skip-automigrations` flag to `storybook upgrade` that bypasses
`runAutomigrations` entirely while still producing a clean upgrade
(package.json + lockfile only).
@kasperpeulen kasperpeulen added build Internal-facing build tooling & test updates ci:normal labels Apr 22, 2026
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 22, 2026

View your CI Pipeline Execution ↗ for commit 448d4d4

Command Status Duration Result
nx run-many -t compile,check,knip,test,lint,fmt... ✅ Succeeded 9m 38s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-22 16:18:42 UTC

The default `runUpgrade` and `installProjectDeps` hooks were `const`
arrow expressions declared below the top-level `if (esMain(...))`
block. When the script is invoked via `node`, the CLI path calls
`syncStorybookVersion(...)` while the module body is still executing,
hitting the temporal dead zone. Tests didn't catch this because
`import` evaluates the whole module first.

Switch both to hoisted `async function` declarations so the CLI entry
can reach them regardless of source order.
@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Apr 22, 2026

Package Benchmarks

Commit: 448d4d4, ran on 22 April 2026 at 15:35:11 UTC

The following packages have significant changes to their size or dependencies:

@storybook/builder-webpack5

Before After Difference
Dependency count 186 186 0
Self size 76 KB 76 KB 🎉 -48 B 🎉
Dependency size 32.75 MB 32.78 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

@storybook/angular

Before After Difference
Dependency count 185 185 0
Self size 140 KB 140 KB 0 B
Dependency size 30.41 MB 30.44 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

@storybook/ember

Before After Difference
Dependency count 190 190 0
Self size 15 KB 15 KB 0 B
Dependency size 29.47 MB 29.50 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

@storybook/nextjs

Before After Difference
Dependency count 535 535 0
Self size 651 KB 650 KB 🎉 -240 B 🎉
Dependency size 60.77 MB 60.80 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

@storybook/react-webpack5

Before After Difference
Dependency count 273 273 0
Self size 23 KB 23 KB 0 B
Dependency size 45.38 MB 45.41 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

@storybook/server-webpack5

Before After Difference
Dependency count 198 198 0
Self size 16 KB 16 KB 🚨 +12 B 🚨
Dependency size 34.01 MB 34.04 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

@storybook/cli

Before After Difference
Dependency count 184 184 0
Self size 819 KB 819 KB 🚨 +286 B 🚨
Dependency size 68.22 MB 68.24 MB 🚨 +24 KB 🚨
Bundle Size Analyzer Link Link

@storybook/codemod

Before After Difference
Dependency count 177 177 0
Self size 32 KB 32 KB 🚨 +36 B 🚨
Dependency size 66.74 MB 66.76 MB 🚨 +24 KB 🚨
Bundle Size Analyzer Link Link

@storybook/preset-react-webpack

Before After Difference
Dependency count 166 166 0
Self size 18 KB 18 KB 0 B
Dependency size 31.75 MB 31.78 MB 🚨 +31 KB 🚨
Bundle Size Analyzer Link Link

When sync-storybook-version is first run with --skip-push, a second run
without that flag should publish the already-created local upgrade
commit instead of reporting a no-op and requiring a manual git push in
every benchmark repo.

Teach the no-diff path to detect when the repo is ahead of origin and,
if pushing is enabled, push that existing commit. Add a regression test
for the two-step skip-push -> push workflow and document it in the eval
README.
@kasperpeulen kasperpeulen changed the title Eval: Add sync-storybook-version script + --skip-automigrations upgrade flag Eval: Add sync-storybook-version harness + --skip-automigrations upgrade flag Apr 22, 2026
@kasperpeulen kasperpeulen marked this pull request as ready for review April 22, 2026 15:24
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

📝 Walkthrough

Walkthrough

This PR adds a --skip-automigrations flag to the CLI upgrade command and introduces a new sync-storybook-version script that upgrades Storybook across multiple benchmark repositories with support for selective project targeting, conditional commit/push, and dirty-repo detection.

Changes

Cohort / File(s) Summary
CLI upgrade command
code/lib/cli-storybook/src/bin/run.ts, code/lib/cli-storybook/src/upgrade.ts
Added --skip-automigrations boolean flag to the upgrade CLI command. Extended UpgradeOptions type with optional skipAutomigrations property and modified upgrade() to conditionally bypass runAutomigrations() when flag is set, logging the skip and initializing empty defaults for automigration results.
Sync Storybook version script
scripts/eval/sync-storybook-version.ts, scripts/eval/sync-storybook-version.test.ts
Implemented new syncStorybookVersion() function for batch upgrading Storybook across benchmark repos. Handles repo cloning, checkout, dependency installation, upgrade execution, file staging, and conditional commit/push. Includes 471-line comprehensive test suite covering multi-project iteration, dirty-repo detection, no-changes scenarios, and resume-on-rerun workflows.
Configuration and utilities
scripts/eval/lib/utils.ts, scripts/package.json
Added exported constant NODE_EVAL_SYNC_STORYBOOK_VERSION_SCRIPT referencing the new sync script path. Added new npm script entry eval:sync-storybook-version to run the sync script.
Documentation
scripts/eval/README.md
Added "Syncing the Storybook version" section documenting the sync-storybook-version.ts workflow, CLI flag usage (--version, --project, --skip-push), and example invocations with stable/canary/latest version specs.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI/User
    participant Sync as syncStorybookVersion
    participant Git as Git Repo
    participant Deps as Dependency Manager
    participant Upgrade as Upgrade Command
    
    CLI->>Sync: sync-storybook-version --version X --project Y
    loop For each selected project
        Sync->>Git: Clone/ensure repo exists
        Sync->>Git: Checkout target branch
        Sync->>Git: Pull origin (--ff-only)
        Sync->>Git: Check for dirty state
        Sync->>Deps: installProjectDeps()
        Sync->>Upgrade: runUpgrade(version, configDir)
        Sync->>Deps: reinstall dependencies
        Sync->>Git: Stage changes
        alt No staged changes
            Sync->>Git: Push if local ahead of origin
        else Changes detected
            Sync->>Git: Commit with version message
            Sync->>Git: Conditionally push to origin
        end
    end
    Sync->>CLI: Return results (commit SHAs, changed status)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
scripts/eval/sync-storybook-version.test.ts (1)

451-453: Consider using Node.js mkdirSync for cross-platform compatibility.

The shell mkdir -p command works on Unix systems but not Windows. Using mkdirSync with the recursive option would be more portable.

♻️ Proposed refactor
+import { mkdirSync } from 'node:fs';
+
 function mkdirSyncRecursive(path: string) {
-  execFileSync('mkdir', ['-p', path]);
+  mkdirSync(path, { recursive: true });
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/eval/sync-storybook-version.test.ts` around lines 451 - 453, The
helper function mkdirSyncRecursive currently shells out with
execFileSync('mkdir', ['-p', path]) which is not cross-platform; update the
function mkdirSyncRecursive to use Node's fs.mkdirSync(path, { recursive: true
}) instead and ensure fs is imported (require or import fs) so the function
works on Windows and Unix without invoking a shell.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code/lib/cli-storybook/src/upgrade.ts`:
- Around line 417-427: The signal handler closure handleInterruption captures
the outer automigrationResults/detectedAutomigrations but the inner block
redeclares them with let, causing shadowing and empty telemetry; fix by removing
the inner declarations and assigning into the outer variables instead (either
change the outer declaration to let so you can reassign the result of
runAutomigrations(storybookProjects, options) to automigrationResults and
detectedAutomigrations, or keep outer const and mutate it with Object.assign
into automigrationResults and set detectedAutomigrations accordingly), and
ensure the code path that skips automigrations still leaves the outer variables
in the correct state so handleInterruption sees the real results.

---

Nitpick comments:
In `@scripts/eval/sync-storybook-version.test.ts`:
- Around line 451-453: The helper function mkdirSyncRecursive currently shells
out with execFileSync('mkdir', ['-p', path]) which is not cross-platform; update
the function mkdirSyncRecursive to use Node's fs.mkdirSync(path, { recursive:
true }) instead and ensure fs is imported (require or import fs) so the function
works on Windows and Unix without invoking a shell.
🪄 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: f657669c-c6de-446a-8c5d-52595a951ab0

📥 Commits

Reviewing files that changed from the base of the PR and between 8ed4332 and 448d4d4.

📒 Files selected for processing (7)
  • code/lib/cli-storybook/src/bin/run.ts
  • code/lib/cli-storybook/src/upgrade.ts
  • scripts/eval/README.md
  • scripts/eval/lib/utils.ts
  • scripts/eval/sync-storybook-version.test.ts
  • scripts/eval/sync-storybook-version.ts
  • scripts/package.json

Comment on lines +417 to +427
// Run automigrations for all projects (unless explicitly skipped)
let automigrationResults: Record<string, AutomigrationResult> = {};
let detectedAutomigrations: AutomigrationCheckResult[] = [];
if (options.skipAutomigrations) {
logger.log('Skipping automigrations (--skip-automigrations).');
} else {
({ automigrationResults, detectedAutomigrations } = await runAutomigrations(
storybookProjects,
options
));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Variable shadowing causes signal handler to always see empty automigration results.

Line 341 declares const automigrationResults in the outer scope, which is captured by the handleInterruption closure (line 348). The new let automigrationResults at line 418 creates a shadowing variable in the inner scope.

If a user interrupts (SIGINT/SIGTERM) after automigrations complete, the signal handler will send telemetry with empty automigrationResults because it references the outer empty object, not the inner populated one.

🐛 Proposed fix: Remove shadowing by reassigning the outer variable
-    // Run automigrations for all projects (unless explicitly skipped)
-    let automigrationResults: Record<string, AutomigrationResult> = {};
-    let detectedAutomigrations: AutomigrationCheckResult[] = [];
-    if (options.skipAutomigrations) {
+    // Run automigrations for all projects (unless explicitly skipped)
+    let detectedAutomigrations: AutomigrationCheckResult[] = [];
+    if (options.skipAutomigrations) {
       logger.log('Skipping automigrations (--skip-automigrations).');
     } else {
-      ({ automigrationResults, detectedAutomigrations } = await runAutomigrations(
+      const result = await runAutomigrations(
         storybookProjects,
         options
-      ));
+      );
+      Object.assign(automigrationResults, result.automigrationResults);
+      detectedAutomigrations = result.detectedAutomigrations;
     }

Also change line 341 from const to let to allow reassignment, or use Object.assign as shown above to mutate the existing object in place.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/lib/cli-storybook/src/upgrade.ts` around lines 417 - 427, The signal
handler closure handleInterruption captures the outer
automigrationResults/detectedAutomigrations but the inner block redeclares them
with let, causing shadowing and empty telemetry; fix by removing the inner
declarations and assigning into the outer variables instead (either change the
outer declaration to let so you can reassign the result of
runAutomigrations(storybookProjects, options) to automigrationResults and
detectedAutomigrations, or keep outer const and mutate it with Object.assign
into automigrationResults and set detectedAutomigrations accordingly), and
ensure the code path that skips automigrations still leaves the outer variables
in the correct state so handleInterruption sees the real results.

@yannbf yannbf merged commit fbf3baa into project/sb-agentic-setup Apr 28, 2026
103 of 105 checks passed
@yannbf yannbf deleted the kasper/eval-sync-storybook-version branch April 28, 2026 07:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Internal-facing build tooling & test updates ci:normal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants