Skip to content

feat(cli): add schema diff command with unified diff model - #667

Draft
maoberlehner wants to merge 6 commits into
mainfrom
feat/WDX-469-schema-diff
Draft

feat(cli): add schema diff command with unified diff model#667
maoberlehner wants to merge 6 commits into
mainfrom
feat/WDX-469-schema-diff

Conversation

@maoberlehner

Copy link
Copy Markdown
Contributor

What

Adds storyblok schema diff --from <spaceId|file> --to <spaceId|file>, a read-only command that exposes the schema classification schema push computes internally. Each side auto-resolves a numeric space ID (fetched remotely) or a file path (loaded via jiti); authentication is required only when a side is a space.

The driving use case is translating schema changes between spaces: compute what changed, then run downstream operations from that diff.

How

  • Unified diff model. diffSchema is now symmetric over a new NormalizedSchema (name-keyed maps) that both a space and a local file resolve to. Every EntityDiff carries field-level FieldChange[] (added/removed/modified with before/after) plus raw before/after snapshots, replacing the old text patch. This single model backs both push and the new command.
  • push renders from the structured model. formatDiffOutput uses the shared renderFieldChanges helper instead of createTwoFilesPatch; push wording and behavior are preserved. The create|update|unchanged|stale action vocabulary is kept internally so migrations/analyze.ts and changeset code need no change.
  • Shared code relocated per the no-sibling-imports rule: diff-schema.ts and load-schema.ts move from push/ up to the parent schema/ directory. cleanComponent/cleanDatasource are extracted in serialize.ts so diffing reuses the exact push normalization.
  • Output. Human stdio by default (added/changed/removed relative to --to, with per-entity field changes). The full structured diff rides the existing reporter via addMeta('diff', ...) + addSummary, gated by the global --report-enabled flag, so downstream space-to-space tooling reads meta.diff. No bespoke --format/--output flags.

Testing

  • Unit: symmetric diffSchema (create/update/unchanged/stale + field-change added/removed/modified, defaults, group escape hatch), isSpaceRef, buildDiffReport, formatSchemaDiff.
  • Integration (msw + memfs): schema diff space↔space, file↔space, and the meta.diff report payload.
  • Regression: existing push/migrations tests remain green (guards the formatDiffOutput refactor).
  • pnpm run test:types, pnpm run lint:fix, and full vitest run all pass.

Note: based on feat/WDX-419-schema-content-shapes, not main.

Fixes WDX-469

@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@667

@storyblok/astro

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

@storyblok/api-client

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

storyblok

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

@storyblok/experiments

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

@storyblok/js

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

storyblok-js-client

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

@storyblok/lint-config

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

@storyblok/live-preview

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

@storyblok/management-api-client

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

@storyblok/migrations

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

@storyblok/nuxt

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

@storyblok/react

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

@storyblok/region-helper

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

@storyblok/richtext

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

@storyblok/schema

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

@storyblok/svelte

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

@storyblok/vue

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

commit: fb4e12d

Base automatically changed from feat/WDX-419-schema-content-shapes to alpha July 3, 2026 05:54
@maoberlehner
maoberlehner force-pushed the feat/WDX-469-schema-diff branch from 5c9a05b to 6ce183b Compare July 3, 2026 08:09
@maoberlehner
maoberlehner force-pushed the feat/WDX-469-schema-diff branch from 6ce183b to 8ea7a9a Compare July 3, 2026 08:10
@maoberlehner
maoberlehner force-pushed the feat/WDX-469-schema-diff branch from 8ea7a9a to da527bd Compare July 8, 2026 12:38
@maoberlehner
maoberlehner force-pushed the feat/WDX-469-schema-diff branch from da527bd to ee67e5f Compare July 8, 2026 12:40
@maoberlehner
maoberlehner force-pushed the feat/WDX-469-schema-diff branch from ee67e5f to 188567f Compare July 14, 2026 14:35
@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-469-schema-diff branch from 188567f to af418c6 Compare July 15, 2026 10:07
@maoberlehner
maoberlehner force-pushed the feat/WDX-469-schema-diff branch from af418c6 to 20758fe Compare July 17, 2026 06:53
@maoberlehner
maoberlehner force-pushed the alpha branch 4 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-469-schema-diff branch from 20758fe to 195dee2 Compare August 11, 2026 10:22
Add `storyblok schema diff --from <spaceId|file> --to <spaceId|file>`,
exposing the classification `schema push` computes internally as a
read-only command. Each side auto-resolves a numeric space ID (fetched
remotely) or a file path (loaded via jiti); authentication is required
only when a side is a space.

Unify the diff into a single structured model shared by both commands.
`diffSchema` is now symmetric over a NormalizedSchema (name-keyed maps)
and every EntityDiff carries field-level FieldChange[] (added/removed/
modified with before/after) plus raw before/after snapshots, replacing
the old text patch. `push` renders from this model via the shared
renderFieldChanges helper. Shared modules (diff-schema, load-schema)
move to the parent schema/ directory per the no-sibling-imports rule.

Human stdio is the default; the machine-readable diff rides the existing
reporter (addMeta('diff', ...) + addSummary), gated by --report-enabled,
so downstream space-to-space tooling reads meta.diff.

Fixes WDX-469
…formatter

Address review findings on the schema diff command.

- diffSchema now takes an explicit compareGroupUuid option (default false).
  Component group UUIDs are per-space identifiers, so comparing two spaces
  flagged every grouped block as changed with a spurious component_group_uuid
  diff that also polluted meta.diff. push opts in (target is the local DSL);
  the diff command only opts in for file-to-file comparisons.
- Extract a shared formatDiff renderer taking label sets so schema push and
  schema diff share one layout instead of duplicating the scaffold.
- Omit unchanged entities from the diff command's terminal output (kept in the
  summary count and meta.diff) to keep space-to-space comparisons readable.

Fixes WDX-469
… listing

Address QA follow-ups on the schema diff command.

- resolveSource now names the failing side (--from/--to) and whether it was a
  file or space, so opaque "Cannot find module" / "Not Found" errors become
  actionable. The file-side hint also covers the module-resolution expectation
  (run it where the schema package is installed).
- reports list no longer prints space "undefined" when invoked without --space;
  it drops the space clause and surfaces space-less reports (e.g. file-to-file
  schema diff) from the base reports directory.
- Document the machine-readable meta.diff enums in the diff README, since the
  entity action vocabulary (create/update/stale/unchanged) differs from the
  human wording (added/changed/removed).

Fixes WDX-469
…nsion

Reports are written as .json (the reporter default), but reports list and
reports prune passed .jsonl (the logger extension), so both matched nothing:
list always reported no files and prune deleted none, for every space.

Drop the explicit .jsonl argument so both fall back to the reporter's .json
default, and correct the test fixtures from .jsonl to .json so the tests
exercise the real code path instead of passing against the wrong extension.
Rebase fallout: main moved the CLI's UI module from src/utils/ui to src/lib/ui
and routes ui.info through console.error, and this branch moved load-schema up
to the schema command directory.

- schema diff imports getUI from ../../../lib/ui, which unblocks the build
- the reports list assertions target console.error, the stream ui.info writes to
- the schema push test imports load-schema from ../load-schema
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