Skip to content

feat: Storybook component diff notifications via GitHub Issues#3708

Open
AnaTBTB wants to merge 4 commits intomainfrom
feat/storybook-component-diff-notifications
Open

feat: Storybook component diff notifications via GitHub Issues#3708
AnaTBTB wants to merge 4 commits intomainfrom
feat/storybook-component-diff-notifications

Conversation

@AnaTBTB
Copy link
Copy Markdown

@AnaTBTB AnaTBTB commented Mar 19, 2026

Summary

  • Adds a script (scripts/storybook-diff.mjs) that fetches the live Storybook index and diffs it against a committed snapshot to detect when components are added or removed
  • Adds a baseline snapshot (scripts/storybook-snapshot.json) of 314 components
  • Extends the existing CI workflow (.github/workflows/build-and-deploy-storybook.yaml) with a new notify-storybook-changes job that runs after each successful Storybook deploy, opens a GitHub Issue if components changed, and auto-commits the updated snapshot with [skip ci]

Why

The design system team needs to stay informed of structural changes to the F0 component library without manually checking Storybook. This automates that signal with low noise — only component-level additions/removals trigger a notification, not story-level changes within existing components.

How it works

  1. After every deploy to https://ds.factorial.dev, the notify-storybook-changes job runs
  2. It fetches https://ds.factorial.dev/index.json and extracts the list of unique component names
  3. It compares against the committed storybook-snapshot.json
  4. If components were added or removed, it opens a GitHub Issue listing the diff
  5. It updates the snapshot and commits it back to main with [skip ci] to avoid a loop

Notes

  • Uses the built-in GITHUB_TOKEN — no additional secrets required
  • No Slack or external webhooks needed

Adds an automated system that detects when components are added or
removed from Storybook and opens a GitHub Issue with the summary.

- scripts/storybook-diff.mjs: fetches ds.factorial.dev/index.json,
  diffs against a local snapshot, and opens a GitHub Issue when new
  or removed components are detected
- scripts/storybook-snapshot.json: baseline snapshot of 314 components
- build-and-deploy-storybook.yaml: new job that runs after deploy,
  uses GITHUB_TOKEN (no extra secrets needed)
@AnaTBTB AnaTBTB requested a review from a team as a code owner March 19, 2026 16:26
Copilot AI review requested due to automatic review settings March 19, 2026 16:26
@github-actions github-actions bot added the feat label Mar 19, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automated detection of Storybook component additions/removals after each successful deploy and notifies the team via a GitHub Issue, while keeping a committed baseline snapshot in-sync.

Changes:

  • Add scripts/storybook-diff.mjs to fetch /index.json, extract component inventory, diff against a snapshot, and open a GitHub Issue on changes.
  • Add scripts/storybook-snapshot.json as the initial committed baseline (314 components).
  • Extend .github/workflows/build-and-deploy-storybook.yaml with a post-deploy job that runs the diff, opens an Issue, and auto-commits the updated snapshot.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 6 comments.

File Description
scripts/storybook-diff.mjs New script to compute component-level diffs and create a GitHub Issue.
scripts/storybook-snapshot.json Baseline snapshot used for future diffs.
.github/workflows/build-and-deploy-storybook.yaml Adds CI job to run the diff post-deploy and commit updated snapshot.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +133 to +156
function buildIssueBody(changes, commitSha, repo) {
const { added, removed } = changes
const commitUrl = `https://github.com/${repo}/commit/${commitSha}`
const lines = []

if (added.length > 0) {
lines.push("## New components\n")
for (const c of added) {
lines.push(`- \`${c.name}\` — \`${c.category}\``)
}
lines.push("")
}

if (removed.length > 0) {
lines.push("## Removed components\n")
for (const c of removed) {
lines.push(`- \`${c.name}\` — \`${c.category}\``)
}
lines.push("")
}

lines.push("---")
lines.push(`Triggered by [${commitSha.slice(0, 7)}](${commitUrl}) · [View Storybook](https://ds.factorial.dev)`)

Comment on lines 10 to 13
permissions:
contents: read
contents: write
pages: write
id-token: write
Comment on lines +29 to +51
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20

- name: Run Storybook diff and open GitHub Issue
run: |
node scripts/storybook-diff.mjs \
--storybook-url https://ds.factorial.dev \
--snapshot scripts/storybook-snapshot.json \
--github-token "${{ secrets.GITHUB_TOKEN }}" \
--github-repo "${{ github.repository }}" \
--commit-sha "${{ github.sha }}"

- name: Commit updated snapshot
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add scripts/storybook-snapshot.json
git diff --staged --quiet || git commit -m "chore: update storybook component snapshot [skip ci]"
git push
Comment on lines +46 to +77
function fetchJson(url, options = {}) {
return new Promise((resolve, reject) => {
const parsed = new URL(url)
const reqOptions = {
hostname: parsed.hostname,
path: parsed.pathname + parsed.search,
method: options.method ?? "GET",
headers: options.headers ?? {},
}

let body = null
if (options.body) {
body = JSON.stringify(options.body)
reqOptions.headers["Content-Type"] = "application/json"
reqOptions.headers["Content-Length"] = Buffer.byteLength(body)
}

const req = https.request(reqOptions, (res) => {
let data = ""
res.on("data", (chunk) => (data += chunk))
res.on("end", () => {
try {
resolve(JSON.parse(data))
} catch (e) {
resolve(data)
}
})
})
req.on("error", reject)
if (body) req.write(body)
req.end()
})
Comment on lines +46 to +63
function fetchJson(url, options = {}) {
return new Promise((resolve, reject) => {
const parsed = new URL(url)
const reqOptions = {
hostname: parsed.hostname,
path: parsed.pathname + parsed.search,
method: options.method ?? "GET",
headers: options.headers ?? {},
}

let body = null
if (options.body) {
body = JSON.stringify(options.body)
reqOptions.headers["Content-Type"] = "application/json"
reqOptions.headers["Content-Length"] = Buffer.byteLength(body)
}

const req = https.request(reqOptions, (res) => {
Comment on lines +88 to +98
for (const entry of Object.values(entries)) {
const title = entry.title ?? ""
const parts = title.split("/")
const name = parts[parts.length - 1]
const category = parts.slice(0, -1).join("/")

if (!components[name]) {
components[name] = { category, stories: [] }
}
components[name].stories.push(entry.name ?? entry.id)
}
Copilot AI review requested due to automatic review settings March 19, 2026 16:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds automated detection and notification of Storybook component inventory changes by diffing the deployed Storybook index against a committed snapshot, and reporting additions/removals via GitHub Issues.

Changes:

  • Add scripts/storybook-diff.mjs to fetch index.json, compute a diff vs a snapshot, and open a GitHub Issue.
  • Add a baseline snapshot at scripts/storybook-snapshot.json.
  • Extend the Storybook deploy workflow to run the diff after deploy and auto-commit snapshot updates.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 6 comments.

File Description
scripts/storybook-diff.mjs New Node script to extract components from Storybook, diff against snapshot, and create an issue.
scripts/storybook-snapshot.json Baseline committed snapshot of Storybook “components” inventory.
.github/workflows/build-and-deploy-storybook.yaml New post-deploy job to run the diff script and commit updated snapshots back to the repo.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +65 to +70
res.on("data", (chunk) => (data += chunk))
res.on("end", () => {
try {
resolve(JSON.parse(data))
} catch (e) {
resolve(data)
Comment on lines +88 to +101
for (const entry of Object.values(entries)) {
const title = entry.title ?? ""
const parts = title.split("/")
const name = parts[parts.length - 1]
const category = parts.slice(0, -1).join("/")

if (!components[name]) {
// Store the first story id to build a direct Storybook URL later
components[name] = {
category,
tags: entry.tags ?? [],
storyId: entry.id ?? "",
}
}
Comment on lines +163 to +165
// Convert story id to docs id: strip the trailing story variant
// e.g. "components-f0button--default" → "components-f0button--docs"
const docsId = storyId.replace(/--[^-]+$/, "--docs")
Comment on lines +251 to +267
lines.push("## 🔴 Breaking Changes")
lines.push(
"_Componentes `stable` eliminados o marcados como `deprecated`. Revisa tus diseños — pueden estar usando algo que ya no existe._\n"
)
for (const c of breaking) {
const reason = degraded.includes(c) ? "degraded to `deprecated`" : "removed"
lines.push(`- **[${c.name}](${c.url})** \`${c.category}\` — ${reason}`)
}
lines.push("")
}

// ── 2. Visual Tweaks (Foundations) ──────────────────────────────────────
if (visual.length > 0) {
lines.push("## 🎨 Visual Tweaks — Foundations")
lines.push(
"_Cambios en tokens de diseño (colores, espaciado, tipografía, bordes, sombras, iconos). Impacto directo en todos los diseños._\n"
)
Comment on lines +302 to +305
)
for (const c of lowImpact) {
const direction = added.includes(c) ? "added" : "removed"
lines.push(`- **[${c.name}](${c.url})** \`${c.category}\` — ${direction}`)
Comment on lines 10 to 13
permissions:
contents: read
contents: write
pages: write
id-token: write
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants