feat: bundle action with ncc and add E2E workflow#1
Merged
DeDuckProject merged 20 commits intomainfrom Mar 11, 2026
Merged
Conversation
- Switch packages/action build from tsc to @vercel/ncc, producing a self-contained dist/index.js that CI can run without pnpm install - Commit packages/action/dist/ (standard practice for GitHub Actions) - Add @actions/artifact as devDep to packages/core to fix tsc types - Create examples/simple-app (plain-JS server, no build step) for E2E - Replace demo.yml with a real E2E workflow: starts the example app, installs Playwright Chromium, then invokes ./packages/action locally Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ore) Add !examples/**/*.js exception so the plain-JS example server is committed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
!packages/action/dist/ only un-ignores the directory itself. Change to !packages/action/dist/** to un-ignore all files within it, including the critical index.js bundle. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
esbuild was --external so wasn't bundled, but also not installed on the CI runner. ncc handles esbuild's native binaries fine (same as fsevents.node), so just include it in the bundle. Also fix .gitignore: need both !packages/action/dist/ (directory) and !packages/action/dist/** (contents) to fully un-ignore the dist folder. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ncc was generating ESM (due to "type": "module"), but bundled Playwright
code uses CJS constructs like __dirname. Add a post-build step that
resets dist/package.json to {} so Node treats the bundle as CJS, which
is the GitHub Actions standard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Playwright can't be bundled by ncc (native deps + ESM/CJS conflicts). Mark it external and restore pnpm install so it's available at runtime. Bundle size drops from 8.7MB → 2.3MB as a bonus. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… field) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ncc always outputs ESM when source has "type": "module", causing __dirname errors in bundled Playwright and module-not-found errors for external packages. esbuild with --format=cjs produces proper CJS regardless of source module type, solving both issues definitively. - Remove @vercel/ncc, patch-dist.cjs hack, and all ncc artifacts - Bundle is now a single dist/index.js (CJS, "use strict") - @playwright/test, playwright-core, esbuild remain external (from pnpm install) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Node treats .js as ESM when package.json has "type": "module", causing require() to fail even though esbuild outputs valid CJS. Removing the field lets Node default to CJS for dist/index.js. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pnpm's strict isolation only symlinks packages for direct dependencies. Since @playwright/test was only a dep of @git-glimpse/core, it wasn't accessible from packages/action/dist/ at runtime. Adding it as a direct dep ensures pnpm creates the symlink in packages/action/node_modules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Node can't natively import .ts files. When the config path ends in .ts, use esbuild to bundle-transpile it to a temp .mjs file, import that, then clean up. .js/.mjs configs use the original dynamic import path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The default 1 MB buffer was too small for the diff between commits in CI, causing spawnSync to throw ENOBUFS. Raise the limit to 10 MB. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
execFileSync has a maxBuffer cap; large PRs with committed dist bundles easily exceed it. Switch to a spawn-based streaming helper that has no buffer limit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🎬 UI Demo PreviewChanges detected in: What changed: A new example 'Product Page' web app has been added, featuring a wireless headphones listing with an Add to Cart counter and a Virtual Try-On modal. This serves as the live demo target for the GitGlimpse end-to-end workflow. Demo script (auto-generated)import type { Page } from '@playwright/test';
export async function demo(page: Page): Promise<void> {
await page.setViewportSize({ width: 1280, height: 720 });
// Navigate to the home page
await page.goto('http://localhost:3000');
await page.waitForLoadState('networkidle');
await page.waitForTimeout(1500);
// Show the product page with the Wireless Headphones card
await page.waitForSelector('text=Wireless Headphones');
await page.waitForTimeout(1000);
// Click 'Add to Cart' several times to show the counter incrementing
const addToCartButton = page.locator('button', { hasText: 'Add to Cart' });
await addToCartButton.click();
await page.waitForTimeout(700);
await addToCartButton.click();
await page.waitForTimeout(700);
await addToCartButton.click();
await page.waitForTimeout(1000);
// Pause to show the counter at 3
await page.waitForTimeout(1500);
// Click the green 'Virtual Try-On' button to open the modal overlay
const tryOnButton = page.locator('button', { hasText: 'Virtual Try-On' });
await tryOnButton.click();
await page.waitForTimeout(1500);
// Modal should now be visible
await page.waitForSelector('text=See how these headphones look on you');
await page.waitForTimeout(1500);
// Close the modal using the X button
const closeButton = page.locator('button[aria-label="Close"]');
await closeButton.click();
await page.waitForTimeout(1500);
// Final pause on the product page
await page.waitForTimeout(1000);
}Generated by git-glimpse |
Local file paths were being passed directly as URLs to postPRComment, causing 404s when GitHub rendered them relative to the compare page. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The /artifacts path doesn't exist on GitHub — the correct URL
is the run page itself (/actions/runs/{runId}).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The uploadArtifact response includes an id field that can be used
to build the direct URL: /actions/runs/{runId}/artifacts/{artifactId}.
Falls back to the run page URL if no id is returned.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also update action build script to always build @git-glimpse/core first, preventing stale dist from being bundled when building action in isolation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Upload screenshots via GitHub release assets (browser_download_url) instead of Actions artifacts, so the URL is publicly accessible and can be embedded as an image in the comment with . Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oads Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

Summary
packages/actionwith@vercel/nccinto a self-containeddist/index.js— nopnpm installneeded in CIexamples/simple-app(plain-JS server, zero build step) as the E2E test targetdemo.ymlwith a real E2E workflow that starts the example app, installs Playwright Chromium, and invokes./packages/actionlocallyTest plan
<!-- git-glimpse-demo -->marker containing a GIF or screenshot fallbackrecording-url,comment-url,success) are populated in the workflow logs🤖 Generated with Claude Code