Skip to content

build(versioning): add public API versioning check#8016

Draft
tomdavies73 wants to merge 1 commit into
masterfrom
FE-7690
Draft

build(versioning): add public API versioning check#8016
tomdavies73 wants to merge 1 commit into
masterfrom
FE-7690

Conversation

@tomdavies73

Copy link
Copy Markdown
Contributor

Proposed behaviour

Current behaviour

Checklist

  • Commits follow our style guide
  • Related issues linked in commit messages if required
  • Screenshots are included in the PR if useful
  • All themes are supported if required
  • Unit tests added or updated if required
  • Playwright automation tests added or updated if required
  • Storybook added or updated if required
  • Translations added or updated (including creating or amending translation keys table in storybook) if required
  • Typescript d.ts file added or updated if required
  • Related docs have been updated if required

QA

  • Tested in provided StackBlitz sandbox/Storybook
  • Add new Playwright test coverage if required
  • Carbon implementation matches Design System/designs
  • UI Tests GitHub check reviewed if required

Additional context

Testing instructions

@tomdavies73 tomdavies73 self-assigned this Jun 12, 2026
@tomdavies73 tomdavies73 added DO NOT MERGE Work in progress This is a WIP PR so may not be ready for review labels Jun 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a public API “versioning check” workflow to detect breaking changes in exported component props and public index.ts exports, integrating it into local git hooks and documenting the process for contributors.

Changes:

  • Introduces a type snapshot generator/comparator for public component props (types/carbon-react/types.json) and exposes it via npm run versioning-check.
  • Adds a commit-msg gate that blocks commits with breaking public API changes unless the commit message includes a breaking marker.
  • Updates Husky hooks + documentation, and marks the snapshot file as generated for GitHub diff collapsing.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
scripts/types/public_types_core.mjs Core snapshot generation + prop/type comparison utilities (ts-morph-based).
scripts/types/check_types.mjs CLI to generate/merge types.json and compare against HEAD.
scripts/types/check_breaking_changes.mjs commit-msg hook gate for breaking type snapshot + export removals.
package.json Adds versioning-check npm script.
CONTRIBUTING.md Documents the public API versioning checks and workflow.
.husky/pre-commit Regenerates/stages snapshot before committing (when triggered).
.husky/commit-msg Runs breaking-change gate and (currently) additional checks.
.github/copilot-instructions.md Documents versioning check behavior for Copilot guidance.
.gitattributes Marks the snapshot JSON as linguist-generated.

Comment thread .husky/pre-commit
# Regenerate the public API snapshot before lint-staged.
# Breaking-change validation is handled in commit-msg where the final commit
# message is available. Pre-commit only refreshes and stages the snapshot.
if git diff --cached --name-only | grep -q '^src/components/'; then
Comment thread .husky/pre-commit
Comment on lines +4 to +6
# Regenerate the public API snapshot before lint-staged.
# Breaking-change validation is handled in commit-msg where the final commit
# message is available. Pre-commit only refreshes and stages the snapshot.
Comment thread .husky/commit-msg
Comment on lines +20 to +23
npx lint-staged || {
unstage_types_snapshot
exit 1
}
Comment thread .husky/commit-msg
exit 1
}

npx commitlint --edit $1 || {
Comment on lines +7 to +10
* npm run versioning-check — generate + compare vs committed baseline
* npm run versioning-check -- Button — same, scoped to one component
* node check_types.mjs --update-only — generate silently (used by pre-commit hook)
*/
Comment on lines +56 to +70
// Build map of new snapshots
/** @type {Record<string, ComponentTypeSnapshot>} */
const newComponents = Object.fromEntries(snapshots.map((s) => [s.component, s]));

// Merge with existing types.json so a scoped run doesn't wipe other components
/** @type {Record<string, ComponentTypeSnapshot>} */
let existingComponents = {};
try {
const raw = await fs.readFile(typesFile, "utf8");
existingComponents = JSON.parse(raw).components ?? {};
} catch {
// First generation
}

const merged = { ...existingComponents, ...newComponents };
Comment on lines +106 to +125
let totalBreaking = 0;

for (const snapshot of snapshots) {
const baseline = committedComponents[snapshot.component];
if (!baseline) {
console.log(`[${snapshot.component}] New component.`);
continue;
}

const { breaking, safe: _safe } = compareSnapshots(baseline, snapshot);

if (breaking.length) {
console.error(`[${snapshot.component}] Breaking changes:`);
for (const msg of breaking) {
console.error(` ! ${msg}`);
}
totalBreaking += breaking.length;
}
}

Comment on lines +191 to +195
const typeText = propertyType.getText(
valueDeclaration ?? contextFile,
TypeFormatFlags.NoTruncation |
TypeFormatFlags.UseAliasDefinedOutsideCurrentScope,
);
Comment on lines +335 to +338
const tempProject = new Project({
useInMemoryFileSystem: true,
compilerOptions: { strictNullChecks: true },
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO NOT MERGE Work in progress This is a WIP PR so may not be ready for review

Development

Successfully merging this pull request may close these issues.

2 participants