ci: render catalog previews on PR#262
Conversation
9831180 to
f906ac5
Compare
f906ac5 to
d98ecf3
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Review: ci: render catalog previews on PR
Solid foundation — the script follows the established generate-template-previews.ts patterns well, and the workflow structure is clean. However, the CI run already exposed two real bugs, plus there are a few things worth tightening up before this lands.
Critical (must fix)
1. grep -P lookbehind fails on Ubuntu runner
The CI logs show:
grep: lookbehind assertion is not fixed length
This is the line:
grep -oP '(?<=registry/(blocks|components)/)[^/]+'grep -P with a variable-length lookbehind ((blocks|components) has alternation of different lengths) is not supported by PCRE on the Ubuntu runner's grep. This silently fails, meaning no items are ever detected as changed.
Fix — use sed or awk instead:
sed -n 's|^registry/\(blocks\|components\)/\([^/]*\)/.*|\2|p' | sort -uOr restructure as two greps:
grep -E '^registry/(blocks|components)/' | sed 's|^registry/[^/]*/\([^/]*\)/.*|\1|' | sort -u2. origin/main ref does not exist — shallow checkout
The CI logs also show:
fatal: bad revision 'origin/main...HEAD'
actions/checkout@v4 performs a shallow clone of the PR merge ref by default. origin/main is not fetched. The workflow needs to either:
(a) Add fetch-depth: 0 to checkout (fetches full history — heavier), or
(b) Use ${{ github.event.pull_request.base.sha }} instead of origin/main:
git diff --name-only ${{ github.event.pull_request.base.sha }}...HEAD -- registry/blocks/ registry/components/Option (b) is more precise since it diffs against the actual PR base, not main (the PR's base branch is 04-14-feat_registry_seed_components_..., not main). But it still requires fetching the base SHA. Consider:
- uses: actions/checkout@v4
with:
fetch-depth: 0Or fetch just the base:
- uses: actions/checkout@v4
- run: git fetch origin ${{ github.event.pull_request.base.sha }} --depth=1Both bugs together mean the workflow currently never renders anything — it always falls through to "No block/component changes detected." The CI passed only because the step has continue-on-error: true and the upload step uses if-no-files-found: ignore.
Important (should fix)
3. continue-on-error: true masks all failures
The render step has continue-on-error: true, which means even if the grep/git bugs above were fixed and rendering genuinely fails, the job still reports green. This defeats the purpose of CI feedback.
The script already has per-item try/catch with ::warning:: annotations. Remove continue-on-error: true from the step and let the exit code propagate. If the intent is "don't block merge on preview failures," make the job non-required in branch protection instead.
4. Script hardcodes origin/main as diff base in the workflow
Even after fixing the checkout issue, diffing against origin/main is wrong when the PR targets a feature branch (like this one targets 04-14-feat_registry_seed_components_...). Use the PR base ref:
git diff --name-only $GITHUB_BASE_REF...HEAD -- registry/blocks/ registry/components/or use the base SHA from the event payload.
5. The --type example CLI flag is accepted but has no effect
The PR description and doc comment say the script supports --type example, but the ItemKind type is "block" | "component" and the discovery function only scans blocks/ and components/. Passing --type example would silently return zero items (since "example" fails the kindFilter !== kind check for both block and component).
Either:
- Remove mentions of "example" from the doc comment and PR description, or
- Add a proper error message for invalid
--typevalues (currently only "block" and "component" are validated inparseArgs, so "example" would hit the error — actually wait, I re-read:parseArgsdoes validate andprocess.exit(1)on invalid type. Good. But the doc comment at the top still says "Examples: renders index.html" which is misleading since examples aren't handled by this script.)
Update the doc comment to remove the "Examples" bullet point and clarify this script handles blocks and components only.
Suggestions (nice to have)
6. Pin Chrome and FFmpeg versions
browser-actions/setup-chrome@v1 with chrome-version: stable and FedericoCarboni/setup-ffmpeg@v3 without a version pin mean the rendering environment can change between runs. For reproducible previews, consider pinning to a specific Chrome version or at least latest-stable with a comment.
7. Consider per-item timeout
A single broken HTML file with an infinite animation loop could hang the entire 30-minute job. The producer APIs might handle this, but worth confirming there's a render timeout at the producer level. If not, wrapping each item render in a timeout command in the shell loop would add resilience:
if ! timeout 120 npx tsx scripts/generate-catalog-previews.ts --only "$item" --skip-video; then8. Temp directory cleanup on script crash
If the script crashes between prepareProjectDir and the finally block (e.g., during createFileServer), the temp dir leaks. Not a big deal in CI (ephemeral runners), but for local use the /tmp/hf-catalog-* dirs accumulate. The existing template preview script has the same pattern, so this is consistent — just noting it.
9. Registry-item.json files field access is unvalidated
const compFile = manifest.files?.find(
(f: { type: string }) => f.type === "hyperframes:composition",
);
entryFile = compFile?.path ?? `${e.name}.html`;If manifest.files exists but contains entries without a path property, compFile?.path is undefined and falls back correctly. But manifest.files could also be a non-array (malformed JSON). A quick Array.isArray(manifest.files) guard would be more defensive.
Summary
The two critical bugs (grep PCRE failure + missing git ref) mean the workflow currently does nothing on any PR. These need to be fixed and verified with a re-run before merging. The continue-on-error: true masked both failures, which is why CI shows green despite zero items rendered.
The script itself is well-structured, follows the existing template preview patterns, and the producer API usage looks correct.
PR #259: Scope all GSAP JS selectors in flowchart.html under [data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout retry in data-chart.html. PR #261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src' in SKILL.md description + body, CLAUDE.md skills table + rules. Add data-composition-id to missing-attributes note in snippet guidance. PR #262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base SHA for diff, remove continue-on-error: true, add per-item timeout, reduce artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference. PR #263: Add try/catch around JSON.parse in codegen discovery (prevents partial wipe on malformed manifest). Guard docs.json tabs array existence. PR #269: Fix Three.js CDN in ascii-dashboard (was broken relative path). Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow, x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.
vanceingalls
left a comment
There was a problem hiding this comment.
One additional finding — the entryFile discovery/usage gap means the preview script likely navigates to a directory listing instead of the composition.
|
|
||
| const fileServer = await createFileServer({ projectDir, port: 0 }); | ||
| try { | ||
| const session = await createCaptureSession(fileServer.url, framesDir, { |
There was a problem hiding this comment.
entryFile is discovered per item but never used by either generateThumbnail or generateVideo.
generateThumbnail passes the bare fileServer.url (e.g., http://localhost:PORT/) to createCaptureSession without appending the entry file path. For blocks, the temp directory contains data-chart.html (no index.html), so navigating to / will hit a directory listing or 404 instead of the composition.
For components, the temp dir has both demo.html and the snippet .html — auto-discovery could pick the wrong file.
Suggestion: pass the entry file URL to the capture session:
const entryUrl = `${fileServer.url}/${item.entryFile}`;
const session = await createCaptureSession(entryUrl, framesDir, { ... });And for video, either rename the entry file to index.html in the temp dir or pass it to the render job config.
There was a problem hiding this comment.
Good catch — this was a real bug in the original code. It's been fixed in a subsequent commit on the stack: prepareProjectDir now copies standalone blocks (those with __timelines) directly to index.html, and for items needing a wrapper it generates an index.html that references the entry file via data-composition-src. The entryFile field is used by both code paths now.
miguel-heygen
left a comment
There was a problem hiding this comment.
CI issues are addressed in #270. Approving.
7c0c1d5 to
f805fc8
Compare
PR #259: Scope all GSAP JS selectors in flowchart.html under [data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout retry in data-chart.html. PR #261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src' in SKILL.md description + body, CLAUDE.md skills table + rules. Add data-composition-id to missing-attributes note in snippet guidance. PR #262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base SHA for diff, remove continue-on-error: true, add per-item timeout, reduce artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference. PR #263: Add try/catch around JSON.parse in codegen discovery (prevents partial wipe on malformed manifest). Guard docs.json tabs array existence. PR #269: Fix Three.js CDN in ascii-dashboard (was broken relative path). Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow, x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.
d98ecf3 to
c5e2fec
Compare
Merge activity
|
Adds a CI workflow that auto-renders preview thumbnails for new/changed registry blocks and components on pull requests. - scripts/generate-catalog-previews.ts: Extends the template preview pipeline to handle all three registry item types. Examples use index.html, blocks use their standalone HTML, components use demo.html. Supports --only, --type, and --skip-video flags. - .github/workflows/catalog-previews.yml: Triggers on PRs touching registry/blocks/ or registry/components/. Detects changed items, renders thumbnails, uploads as artifacts.
c5e2fec to
5031369
Compare
PR #259: Scope all GSAP JS selectors in flowchart.html under [data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout retry in data-chart.html. PR #261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src' in SKILL.md description + body, CLAUDE.md skills table + rules. Add data-composition-id to missing-attributes note in snippet guidance. PR #262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base SHA for diff, remove continue-on-error: true, add per-item timeout, reduce artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference. PR #263: Add try/catch around JSON.parse in codegen discovery (prevents partial wipe on malformed manifest). Guard docs.json tabs array existence. PR #269: Fix Three.js CDN in ascii-dashboard (was broken relative path). Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow, x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.
PR heygen-com#259: Scope all GSAP JS selectors in flowchart.html under [data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout retry in data-chart.html. PR heygen-com#261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src' in SKILL.md description + body, CLAUDE.md skills table + rules. Add data-composition-id to missing-attributes note in snippet guidance. PR heygen-com#262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base SHA for diff, remove continue-on-error: true, add per-item timeout, reduce artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference. PR heygen-com#263: Add try/catch around JSON.parse in codegen discovery (prevents partial wipe on malformed manifest). Guard docs.json tabs array existence. PR heygen-com#269: Fix Three.js CDN in ascii-dashboard (was broken relative path). Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow, x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.

What
CI workflow that auto-renders preview thumbnails for new/changed registry blocks and components on pull requests.
New files:
scripts/generate-catalog-previews.ts— catalog preview renderer supporting all three registry item types.github/workflows/catalog-previews.yml— GitHub Actions workflow triggered on PRs touchingregistry/blocks/orregistry/components/Why
Phase B of the catalog plan (PR 8). After this lands, future block/component PRs don't need to manually generate preview images — CI handles it automatically.
How
The preview script discovers items from the registry directory structure:
index.html(same as the existinggenerate-template-previews.ts)data-chart.html)demo.html(the demo.html convention from PR 7)The CI workflow:
git diffOutput goes to
docs/images/catalog/<type>/<name>.{png,mp4}(separate from the existingdocs/images/templates/directory).Supports CLI flags:
--only <name>,--type <example|block|component>,--skip-video.Test plan
lefthook pre-commitran lint + typecheck + format)