Skip to content

feat: Storybook hosting POC — SDK auto-upload#1290

Draft
Sriram567 wants to merge 1 commit into
masterfrom
feat/storybook-hosting-poc
Draft

feat: Storybook hosting POC — SDK auto-upload#1290
Sriram567 wants to merge 1 commit into
masterfrom
feat/storybook-hosting-poc

Conversation

@Sriram567
Copy link
Copy Markdown

Summary

POC: after a successful directory-mode `percy storybook ./storybook-static` run, zip the directory and POST it to percy-api's new bundle endpoint. Companion PR to the API + Web PRs.

Plan: `docs/plans/2026-04-24-001-feat-storybook-hosting-poc-plan.md` (status: completed)

Companion PRs

  • API: percy/percy-api/pull/5806 (Units 1–4 — defines the endpoint this PR uploads to)
  • Web: percy/percy-web `feat/storybook-hosting-poc` (Unit 6 — renders the link)

Changes

`f23199b` adds:

  1. `src/upload-bundle.js` — `uploadStorybookBundle({ percy, log, directory, buildId })`:
    • Streams the directory into a Buffer via `archiver` (zip, level 9)
    • Wraps as multipart/form-data via `form-data`, POSTs via `axios.post` (NOT `percy.client.post` which is JSON-only — see plan rationale)
    • Reuses `percy.client.apiUrl` + `percy.client.token` so behavior tracks the rest of the SDK
    • Logs `info` on 2xx, `warn` on any failure, never throws (best-effort)
  2. `src/storybook.js` — wires the upload at the end of the directory-mode flow:
    • Only when `args.serve` is set (URL mode has no on-disk bundle to upload — explicit non-goal)
    • Calls `yield* percy.yield.flush()` first to drain the snapshot queue and ensure `createBuild` has resolved (otherwise `percy.build?.id` is racy under `delayUploads: true`)
  3. New deps: `archiver@7.0.1`, `form-data@4.0.5`. `axios@1.13.5` was already present.
  4. `test/upload-bundle.test.js` — 7 jasmine specs covering: success path, 4xx, 5xx, network error, missing buildId, missing directory, missing client config.

What this does NOT do

  • Does not support URL mode (`percy storybook https://...`) — the SDK doesn't have the static assets in that flow
  • Does not introduce a new CLI flag — auto on directory input, no opt-in needed
  • Does not retry on failure — best-effort matches the POC's "snapshot run is the source of truth" decision

Testing

  • 7/7 jasmine specs pass via `yarn test:env jasmine --filter=uploadStorybookBundle`
  • ESLint clean on changed files

Post-Deploy Monitoring & Validation

`No additional operational monitoring required: this is opt-in by client SDK upgrade. Customers running an older @percy/storybook version do not get the upload. Productionization (Phase 2) adds Honeycomb instrumentation on upload latency + Sentry capture on swallowed failures above a threshold; that work has its own plan.`


🤖 Generated with Claude Code via Compound Engineering v2.54.0
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

… run

After a successful `percy storybook ./storybook-static` run completes its
snapshot capture, the SDK now zips the directory and POSTs it to
/api/v1/builds/:id/storybook_bundle on percy-api.

Wired in src/storybook.js:
- Only when args.serve is set (directory mode); URL mode has no on-disk
  bundle to upload.
- After yield* takeStorybookSnapshots, yield* percy.yield.flush() drains
  the snapshot queue and resolves createBuild before reading
  percy.build.id (guard against the delayUploads: true race).
- Best-effort: failure swallowed via uploadStorybookBundle's try/catch;
  the snapshot run remains the source of truth for build success.

src/upload-bundle.js:
- archiver streams the directory into a Buffer (form-data multipart needs
  the full body length, so we collect in memory; POC bundles are 30-80 MB).
- axios.post (instead of percy.client.post — that's JSON-only) reusing
  percy.client.apiUrl + token. maxContentLength/Infinity for headroom.
- log.info on 2xx; log.warn + return on any 4xx/5xx/network error.

7 jasmine specs cover happy path, 4xx, 5xx, network failure, and three
gate conditions (missing buildId / directory / client config).

New deps: archiver 7.0.1, form-data 4.0.5. axios 1.13.5 was already
present.

Plan: docs/plans/2026-04-24-001-feat-storybook-hosting-poc-plan.md (Unit 5)
@Sriram567
Copy link
Copy Markdown
Author

Verified end-to-end (2026-04-28)

After uploading a test fixture via curl to the new percy-api endpoint (PR #5806), the bundle is served from http://localhost:9090/storybook/<build-id>/ and the percy-web review page (PR #5510) renders a "View Storybook" link in the metadata sidebar:

Storybook row rendered

Click → new tab opens the hosted bundle:

Hosted bundle tab

The SDK side (this PR) was unit-tested in isolation with axios stubbed (7/7 jasmine specs pass). For a full live SDK e2e, link the local @percy/storybook into a customer-style project that has its own Storybook (Chakra/MUI/Polaris), then run percy storybook ./storybook-static — the upload step kicks in after takeStorybookSnapshots completes.

Tracked at PER-7873.

@Sriram567
Copy link
Copy Markdown
Author

End-to-end with the SDK's own test stories

Built test/.storybook via storybook build --config-dir=./test/.storybook (this repo's test fixtures: Snapshot, Skip, Args, Mixed, Options stories). 13 MB output, uploaded to a fresh build via curl against the new percy-api endpoint. Hosted bundle renders the full Storybook UI:

Hosted Storybook UI

And on the percy-web review page:

Storybook row in review page

For the "live SDK" path (where this PR's actual code path runs end-to-end), yarn link @percy/storybook into a customer project and run percy storybook ./storybook-static. Coverage in this PR's tests stubs axios to keep specs hermetic.

@github-actions
Copy link
Copy Markdown

This PR is stale because it has been open for more than 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions Bot added the 🍞 stale Closed due to inactivity label May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🍞 stale Closed due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant