Skip to content

feat(cli): schema affected command (WDX-470) - #664

Draft
maoberlehner wants to merge 13 commits into
mainfrom
feat/WDX-470-affected-stories-by-schema-change
Draft

feat(cli): schema affected command (WDX-470)#664
maoberlehner wants to merge 13 commits into
mainfrom
feat/WDX-470-affected-stories-by-schema-change

Conversation

@maoberlehner

@maoberlehner maoberlehner commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Add storyblok schema affected <entry-file>: a read-only dry run of schema push that reports which stories a pending schema change affects and which would break, with a terminal summary and an optional non-zero exit for CI gating.

How it works

  1. loadSchema (local) then fetchRemoteSchema then diffSchema then analyzeBreakingChanges (reuses the push pipeline).
  2. Compute impacted components (breaking updates, plus removed components when --include-deleted is set).
  3. Fetch only the stories that use an impacted component, then run validateStory from @storyblok/schema for breakage. Use --local to analyze already-pulled story JSON instead of fetching from the space.
  4. Walk each story's content for usage, and aggregate per-component and per-field totals.
  5. Print the summary. The full per-story and per-field detail is written to the standard command report file when reporting is enabled (--report-enabled).

Options

-s/--space (required), -p/--path (global), --local, --include-deleted, --fail-on-break.

See packages/cli/src/commands/schema/affected/README.md for the full option table and analysis scope.

Notable correctness decisions

  • Breakage is diffed against old and new schema, so only errors the change introduces count, and pre-existing invalid content is not misattributed.
  • Removed-component impact is gated behind --include-deleted, mirroring schema push --delete (a plain push does not delete stale components).
  • Per-field used comes from the actual content walk, so silent-but-real changes (for example text to textarea) still report usage.
  • Per-story fetch failures are logged and counted, not silently dropped, and the progress bar reaches 100%.
  • Story fetching combines two MAPI filters. contain_component matches nested-blok usage, and it has AND/superset semantics for a comma-separated list (confirmed via manual QA against a live space and storyrails source: components @> [...]), so we issue one request per impacted component and de-dupe refs by story id. A filter_query[component][in] request additionally matches stories that use an impacted component as their root content type with no nested bloks, which contain_component alone misses. Both are unioned by story id.
  • --fail-on-break sets a non-zero exit code when any story would break, and misconfiguration or operational failures (empty entry file, missing --space, fetch errors) also exit non-zero so a broken run never reads as a green CI gate.
  • Shared pipeline helpers (load-schema, diff-schema, migrations/) moved up to schema/ so sibling subcommands no longer import from push/.

Fixes WDX-470

@pkg-pr-new

pkg-pr-new Bot commented Jul 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@storyblok/angular

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/angular@664

@storyblok/astro

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/astro@664

@storyblok/api-client

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/api-client@664

storyblok

npm i https://pkg.pr.new/storyblok/monoblok/storyblok@664

@storyblok/experiments

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/experiments@664

@storyblok/js

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/js@664

storyblok-js-client

npm i https://pkg.pr.new/storyblok/monoblok/storyblok-js-client@664

@storyblok/lint-config

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/lint-config@664

@storyblok/live-preview

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/live-preview@664

@storyblok/management-api-client

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/management-api-client@664

@storyblok/migrations

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/migrations@664

@storyblok/nuxt

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/nuxt@664

@storyblok/react

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/react@664

@storyblok/region-helper

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/region-helper@664

@storyblok/richtext

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/richtext@664

@storyblok/schema

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/schema@664

@storyblok/svelte

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/svelte@664

@storyblok/vue

npm i https://pkg.pr.new/storyblok/monoblok/@storyblok/vue@664

commit: f7ab303

Comment thread packages/cli/src/commands/schema/affected/index.ts Outdated
Comment thread packages/cli/src/commands/schema/affected/index.ts Outdated
Comment thread packages/cli/src/commands/schema/affected/index.ts Outdated
Comment thread packages/cli/src/commands/schema/affected/index.ts Outdated
Comment thread packages/cli/src/commands/schema/affected/index.ts Outdated
Comment thread packages/cli/src/commands/schema/affected/index.ts Outdated
Base automatically changed from feat/WDX-419-schema-content-shapes to alpha July 3, 2026 05:54
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from 4d13a63 to c37989c Compare July 3, 2026 08:13
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from c37989c to b1ec7b5 Compare July 8, 2026 12:38
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from b1ec7b5 to 5fb2198 Compare July 8, 2026 12:40
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from 5fb2198 to c886d9a Compare July 15, 2026 05:59
@maoberlehner
maoberlehner force-pushed the alpha branch 2 times, most recently from 41afe89 to 0c36a25 Compare July 15, 2026 09:59
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from c886d9a to 579a0f2 Compare July 15, 2026 10:07
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from 579a0f2 to 7704521 Compare July 17, 2026 06:53
@maoberlehner
maoberlehner force-pushed the alpha branch 5 times, most recently from 060355b to 9f030c6 Compare July 21, 2026 11:34
Base automatically changed from alpha to main July 21, 2026 11:42
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from 7704521 to a8318d6 Compare August 11, 2026 10:26
Add `storyblok schema affected <entry-file>` (alias `impact`): diffs a
local schema against a remote space, determines which components a push
would change or remove, walks story content for usage, and runs
`@storyblok/schema`'s validateStory to report which stories are affected
and which would break.

Breakage is diffed against both the old and new schema so only errors the
change introduces are counted (pre-existing invalid content is ignored).
Removed-component impact is gated behind `--delete`, mirroring
`schema push --delete`. Per-field usage is driven by the actual content
walk, and per-story fetch failures are logged and counted instead of
silently dropped.

Move the shared schema pipeline helpers (load-schema, diff-schema,
migrations) up to the parent `schema/` directory so sibling subcommands
no longer import from `push/`.

Fixes WDX-470
MAPI's `contain_component` filter has AND (superset) semantics for a
comma-separated list — it returns only stories containing every listed
component (confirmed against storyrails: `components @> [...]`). Joining
impacted component names into a single request silently under-fetched on
any multi-component run.

Issue one list request per impacted component and de-duplicate the refs
by story id before fetching content. Over-fetch is harmless since
analyzeStory recomputes usage from each story's own content. The
multi-component test now mirrors MAPI's AND filtering so a regression to
a single joined request fails.

Fixes WDX-470
- loadSchema: guard entry-file existence before jiti so a missing file
  reports "Entry file not found: <path>" instead of jiti's raw
  "Cannot find module … Require stack:" dump (benefits schema push too).
- schema affected summary: phrase per-field usage as "present in N
  story(s)" so a `required_added` row (field absent by design, used=0)
  no longer reads as a contradiction against the break count.

Fixes WDX-470
Resolve PR review feedback and tester findings on `schema affected`:

- Drop the redundant `-p, --path` redeclaration from affected/push/rollback
  (it is an inherited global option).
- Remove `--component`, `--list`, and `--output`; the full per-story detail
  now rides along in the standard report via `reporter.addMeta`.
- Rename `--stories <path>` to `--local` (reads the default stories dir) and
  `--delete` to `--include-deleted` (matches `push --delete` wording).
- Add opt-in `--fail-on-break` to exit non-zero for CI gating.
- Guard `--local` with an actionable "run `stories pull` first" message
  instead of a raw filesystem error.
- Reword the totals line so "across N component(s)" qualifies the affected
  count rather than the break count.
- Fix the has-stories QA seed: blog-index was both `is_folder: true` and a
  `page` with a headline. Storyblok never content-indexes folders, so
  `contain_component` (remote) correctly skipped it while `--local` counted
  it. Reduced to a proper folder so both paths agree.

Fixes WDX-470
…al errors

Resolve tester findings on the `--fail-on-break` CI framing:
- Guard an empty resolved entry-file (typo/wrong export): warn and exit
  non-zero instead of diffing nothing and reporting a false all-clear,
  mirroring `schema push`.
- Set a non-zero exit code on all operational error paths (missing space,
  schema load failure, remote fetch failure, missing local stories) so a
  failed run is never a green CI gate. Scoped to `affected`; the CLI-wide
  `handleError` exit-0 convention is left as a separate follow-up.
- Document the analysis scope in `--help`: field-structural changes and
  component deletion, not nested allow-list/reference constraints.

Fixes WDX-470
`contain_component` matches a component used as a nested blok, and a root
component only when the story also has nested bloks. A story that uses an
impacted component solely as its root content type — with no nested bloks —
was never fetched, so its breakage was silently dropped (a false all-clear
under --fail-on-break). analyzeRemoteStories now also issues one
`filter_query[component][in]` request (matches by root content type) and
unions it with the per-component `contain_component` results.

Fixes WDX-470
Two terminal-output fixes for `schema affected`:
- Flush the progress bar before printing the summary. A bare `progress.stop()`
  leaves the MultiBar's async renderer alive, so its final 100% frame flushed
  after the summary lines. Use `ui.stopAllProgressBars()` like every other
  progress-bar command.
- Pluralize story/component counts based on n (`1 story` / `3 stories`) via a
  small `pluralize` helper instead of the `story(s)` placeholder.

Fixes WDX-470
analyzeRemoteStories and analyzeLocalStories built a byte-identical Writable
collector inline, differing only in the source stream. Extract
createAnalyzeCollector(ctx, results) so the analyze-and-collect logic lives in
one place and each function supplies just its source stream to pipeline().

Fixes WDX-470
Documents the `schema affected` command, its registered options (--space,
--local, --include-deleted, --fail-on-break), and analysis scope, following the
stories subcommand README pattern.

Fixes WDX-470
The command is invoked as `schema affected`; the `impact` alias is unnecessary.

Fixes WDX-470
The affected-command test mock predates the block-folders feature (#690)
now on alpha; loadSchema returns a SchemaData with a folders array, and
diffSchema reads local.folders, so the mock must include it.
Rebase fallout: main moved the CLI's UI module from src/utils/ui to src/lib/ui
and dropped konsola, so the command imports getUI from ../../../lib/ui and the
tests spy on the UI instance handleError writes through.
@maoberlehner
maoberlehner force-pushed the feat/WDX-470-affected-stories-by-schema-change branch from a8318d6 to f7ab303 Compare August 11, 2026 10:45
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