feat(cli): schema affected command (WDX-470) - #664
Draft
maoberlehner wants to merge 13 commits into
Draft
Conversation
@storyblok/angular
@storyblok/astro
@storyblok/api-client
storyblok
@storyblok/experiments
@storyblok/js
storyblok-js-client
@storyblok/lint-config
@storyblok/live-preview
@storyblok/management-api-client
@storyblok/migrations
@storyblok/nuxt
@storyblok/react
@storyblok/region-helper
@storyblok/richtext
@storyblok/schema
@storyblok/svelte
@storyblok/vue
commit: |
maoberlehner
commented
Jul 1, 2026
maoberlehner
commented
Jul 1, 2026
maoberlehner
commented
Jul 1, 2026
maoberlehner
commented
Jul 1, 2026
maoberlehner
commented
Jul 1, 2026
maoberlehner
commented
Jul 1, 2026
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
July 3, 2026 08:13
4d13a63 to
c37989c
Compare
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
July 8, 2026 12:38
c37989c to
b1ec7b5
Compare
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
July 8, 2026 12:40
b1ec7b5 to
5fb2198
Compare
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
July 15, 2026 05:59
5fb2198 to
c886d9a
Compare
maoberlehner
force-pushed
the
alpha
branch
2 times, most recently
from
July 15, 2026 09:59
41afe89 to
0c36a25
Compare
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
July 15, 2026 10:07
c886d9a to
579a0f2
Compare
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
July 17, 2026 06:53
579a0f2 to
7704521
Compare
maoberlehner
force-pushed
the
alpha
branch
5 times, most recently
from
July 21, 2026 11:34
060355b to
9f030c6
Compare
maoberlehner
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
August 11, 2026 10:26
7704521 to
a8318d6
Compare
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
force-pushed
the
feat/WDX-470-affected-stories-by-schema-change
branch
from
August 11, 2026 10:45
a8318d6 to
f7ab303
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add
storyblok schema affected <entry-file>: a read-only dry run ofschema pushthat 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
loadSchema(local) thenfetchRemoteSchemathendiffSchemathenanalyzeBreakingChanges(reuses the push pipeline).--include-deletedis set).validateStoryfrom@storyblok/schemafor breakage. Use--localto analyze already-pulled story JSON instead of fetching from the space.--report-enabled).Options
-s/--space(required),-p/--path(global),--local,--include-deleted,--fail-on-break.See
packages/cli/src/commands/schema/affected/README.mdfor the full option table and analysis scope.Notable correctness decisions
--include-deleted, mirroringschema push --delete(a plain push does not delete stale components).usedcomes from the actual content walk, so silent-but-real changes (for exampletexttotextarea) still report usage.contain_componentmatches 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. Afilter_query[component][in]request additionally matches stories that use an impacted component as their root content type with no nested bloks, whichcontain_componentalone misses. Both are unioned by story id.--fail-on-breaksets 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.load-schema,diff-schema,migrations/) moved up toschema/so sibling subcommands no longer import frompush/.Fixes WDX-470