Skip to content

ci: add Next.js deploy suite harness#1189

Merged
james-elicx merged 18 commits into
mainfrom
ci/nextjs-deploy-suite-harness
May 14, 2026
Merged

ci: add Next.js deploy suite harness#1189
james-elicx merged 18 commits into
mainfrom
ci/nextjs-deploy-suite-harness

Conversation

@james-elicx
Copy link
Copy Markdown
Collaborator

@james-elicx james-elicx commented May 13, 2026

Summary

Adds the scripts and GitHub Actions workflow for running the Next.js e2e deploy test suite against vinext, structured per the Next.js adapter testing docs.

Extracted from #922 (which also contains the Pages Router compatibility fixes that make the suites pass).

How it works

Next.js ships a test harness (run-tests.js) that creates isolated temp apps, calls an adapter's deploy/logs/cleanup scripts, then runs Playwright tests against the running server. Our scripts wire that harness up to vinext: each test app gets vinext injected as a local dependency, built with vinext build, and served with vinext start.

What's included

Workflow (.github/workflows/nextjs-deploy-suite.yml):

  • build job: builds vinext, prepares Next.js checkout, generates the deploy manifest
  • test job: restores the build cache, shards tests 16 ways via run-tests.js
  • workflow_dispatch with vinext-ref (branch to test), next-ref (Next.js version, default v16.2.6), suite-filter (app/pages/all, default app), test-concurrency
  • Nightly cron at 02:00 UTC against main

Scripts (named per Next.js docs convention):

  • scripts/e2e-deploy.sh — per-test deploy: injects vinext into the test app, builds with vinext build, starts with vinext start, prints URL to stdout
  • scripts/e2e-cleanup.sh — kills the server process, persists debug logs
  • scripts/e2e-logs.sh — replays build/server logs (includes required BUILD_ID: / DEPLOYMENT_ID: / IMMUTABLE_ASSET_TOKEN: markers)
  • scripts/run-nextjs-deploy-suite.sh — convenience wrapper for local runs

Manifest generator (scripts/nextjs-deploy-manifest.mjs):

  • --filter app|pages|all to select which suites to include from the Next.js deploy-tests-manifest.json

Other:

  • .gitignore updated to ignore reports/

pnpm in the scripts

The scripts use pnpm (not vp) in two places, both intentionally:

  • Next.js checkout — Next.js is a pnpm workspace; its build/test tooling requires pnpm
  • Isolated test app temp dirs — throwaway apps created by the Next.js harness, outside the vinext monorepo; vp has no project context here

vp is already used where it should be (building vinext itself).

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 13, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@1189

commit: 34cc26e

@github-actions
Copy link
Copy Markdown

Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original

@james-elicx james-elicx changed the title ci: add Next.js Pages Router deploy suite harness ci: add Next.js deploy suite harness May 13, 2026
@james-elicx
Copy link
Copy Markdown
Collaborator Author

/bigbonk review

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

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

Review: ci: add Next.js deploy suite harness

Overall this is solid work — the scripts are well-structured, the CI workflow is cleanly separated into build/test jobs, and the debug artifact collection is thorough. A few things worth addressing before merge:


Workflow comment vs cron mismatch

.github/workflows/nextjs-deploy-suite.yml:5-6 — The comment says "Nightly at 06:00 UTC" but the cron is 0 2 * * * (02:00 UTC). Pick one.

Cache path includes . (entire workspace)

.github/workflows/nextjs-deploy-suite.yml:84-92 — The actions/cache/save path includes . (the entire vinext checkout). This means the cache key nextjs-deploy-build-${{ github.sha }}-${{ github.run_id }} stores the full workspace + next.js/ + Playwright browsers + the manifest. That's going to be a very large cache entry (Next.js checkout alone is sizable after pnpm build). Consider narrowing the cached paths to just what the test job actually needs:

  • packages/vinext/dist/ (the built plugin)
  • node_modules/ (or just rely on setup-vp caching)
  • next.js/ (the prepared Next.js checkout)
  • ~/.cache/ms-playwright
  • nextjs-deploy-manifest.json

At minimum, caching . means the test job's actions/cache/restore will overwrite the checkout from the restore step, which works but is wasteful and fragile if the workspace has any ephemeral state.

cancel-in-progress: false with nightly cron

.github/workflows/nextjs-deploy-suite.yml:39 — With cancel-in-progress: false, if a nightly run is still going when the next day's cron fires (unlikely with 60min timeout, but possible with manual dispatches), both will run to completion. This is probably intentional for deploy suites (you want full results), but worth confirming that's the intent.

run_pnpm build in CI prepare step

.github/workflows/nextjs-deploy-suite.yml:70-74 and scripts/run-nextjs-deploy-suite.sh:40-44 — In the workflow, VINEXT_BUILD=0 is set because the workflow already built vinext with vp run vinext#build. But the run-nextjs-deploy-suite.sh script's build path (line 43) does run_pnpm build which would run the root build script via pnpm. For local development, this should probably be documented — a developer running ./scripts/run-nextjs-deploy-suite.sh locally will need pnpm available and the root build script to work correctly.

YAML catalog parser is fragile

scripts/e2e-deploy.sh:219-246 — The parseCatalog() function does line-by-line YAML parsing with regex. This works for the current pnpm-workspace.yaml format but will break if:

  • Catalog entries use flow syntax (catalog: { foo: ^1.0.0 })
  • Indentation changes (it hardcodes 2-space indent check on line 231)
  • Values are quoted with single quotes
  • There are nested catalogs (catalogName: sections)

This is a known trade-off (avoiding a YAML parser dependency in a throwaway temp dir), and the current workspace file uses the simple format, so it's fine for now. But a comment noting the assumption would help future maintainers.

Port allocation TOCTOU race

scripts/e2e-deploy.sh:68-84find_free_port() binds to port 0, reads the allocated port, then closes the server. Between close and vinext start --port $PORT, another process could grab that port. With -c 2 concurrency (two test apps deploying simultaneously), this race is real. The Node.js net.createServer approach is standard and usually fine, but with 16 shards × 2 concurrency = 32 parallel servers, collisions become more likely.

A mitigation would be to keep the server open until vinext start binds, or retry with a new port on EADDRINUSE. Not a blocker but worth a TODO comment.

Cleanup doesn't remove the PID file

scripts/e2e-cleanup.sh:22-28 — After killing the process, the PID file is left behind. If the Next.js harness reuses the same temp directory (unlikely but possible), a stale PID file could cause confusion. Add rm -f "${PID_FILE}" at the end.

ensure_python_command_for_native_builds PATH mutation

scripts/e2e-deploy.sh:116export PATH="$(pwd)/${shim_dir}:${PATH}" uses a subshell for $(pwd) which is fine, but the shim directory .vinext-native-build-bin is created in the test app's temp directory. If the cwd changes later in the script, the PATH entry still works (absolute path). This is correct, just noting it's intentional.

Hardcoded warning messages for specific test pages

scripts/e2e-deploy.sh:351-356 — These hardcoded warnings for large-page-data and blocking-fallback/[slug] are clearly there because specific Next.js tests assert on these warning strings in build output. This is pragmatic but brittle — if Next.js changes the warning text or threshold, these will silently diverge. A comment explaining why these exist (which Next.js test expects them) would help.

.next/trace empty file creation

scripts/e2e-deploy.sh:358-359 — Creating an empty .next/trace file is presumably because some Next.js test checks for its existence. Same as above — a brief comment would help.

IS_TURBOPACK_TEST=1 in the workflow

.github/workflows/nextjs-deploy-suite.yml:156 — This env var tells the Next.js test harness to treat this as a Turbopack test run. Since vinext uses Vite (not Turbopack), this is presumably set to match the deploy test manifest's expectations or skip webpack-specific assertions. A comment in the workflow explaining why would prevent someone from "fixing" it later.


Minor nits

  • scripts/e2e-deploy.sh:1 and other scripts — all scripts should probably have a brief header comment explaining what they do (like nextjs-deploy-manifest.mjs does). The deploy script especially is 381 lines with no top-level doc comment.
  • scripts/run-nextjs-deploy-suite.sh:7[[ "${1}" != -* ]] uses bash-specific [[ ]] but the rest of the script uses POSIX [ ]. Consistent style would be nice but not blocking.

None of these are blockers — the biggest actionable items are the cache path scope and adding a few comments for the non-obvious compatibility shims (hardcoded warnings, .next/trace, IS_TURBOPACK_TEST). The overall structure is clean and follows the Next.js adapter testing conventions well.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented May 13, 2026

Review posted on PR #1189. Here's a summary of the key findings:

Actionable items:

  1. Cron comment mismatch — comment says 06:00 UTC but cron is 0 2 * * * (02:00 UTC)
  2. Cache path too broad — caching . (entire workspace) is wasteful; should narrow to just what the test job needs
  3. Missing cleanup of PID filee2e-cleanup.sh kills the process but leaves the PID file behind
  4. Missing comments on compatibility shims — the hardcoded warning messages, .next/trace creation, and IS_TURBOPACK_TEST=1 all exist for specific Next.js test expectations but aren't documented

Non-blocking observations:

  • YAML catalog parser is intentionally simple but fragile — a comment noting the assumption would help
  • Port allocation has a TOCTOU race that becomes more likely with 32 parallel servers (16 shards × 2 concurrency)
  • Minor style inconsistency ([[ ]] vs [ ] in the same script)

Overall the PR is well-structured and follows the Next.js adapter testing conventions correctly.

github run

@james-elicx
Copy link
Copy Markdown
Collaborator Author

/bigbonk re-review

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

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

Re-review: ci: add Next.js deploy suite harness

All actionable items from the previous review have been addressed in e203abf:

Previous feedback Status
Cron comment mismatch (said 06:00, cron was 02:00) Fixed — comment now says 02:00 UTC
Cache path too broad / undocumented Documented — comment at lines 87-90 explains why . is intentional
Missing PID file cleanup in e2e-cleanup.sh Fixedrm -f "${PID_FILE}" added at line 30, before the kill
IS_TURBOPACK_TEST=1 unexplained Fixed — comment at lines 158-159 explains manifest keying
Hardcoded warning messages undocumented Fixed — comment block at lines 366-368 explains the test assertions
.next/trace creation undocumented Fixed — comment at lines 376-377
YAML catalog parser assumptions undocumented Fixed — comment at lines 230-233
[[ ]] vs [ ] inconsistency Fixedrun-nextjs-deploy-suite.sh line 20 now uses [ ] consistently
Scripts missing header comments Fixed — all scripts have header doc comments

The new report job (lines 186-320) looks solid — recursive result file discovery, graceful handling of missing artifacts, summary table capped at 100 failures, and a JSON artifact for programmatic consumption. The core.setFailed() call correctly propagates failure to the workflow status.

One minor observation on the report job that's not blocking: the ${{ inputs.vinext-ref || github.ref }} expressions on lines 300-302 are interpolated by GitHub Actions into the JS string at workflow parse time, not at runtime. If any input value contains a single quote, it would break the JS string literal. This is unlikely for branch names and version refs, and github-script doesn't have a great escape hatch for this, so it's fine as-is.

LGTM — ready to merge.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented May 13, 2026

Review posted. All 9 actionable items from the previous review have been addressed in the latest commit (e203abf). The PR is approved and ready to merge.

github run

@james-elicx james-elicx marked this pull request as draft May 13, 2026 16:37
@james-elicx
Copy link
Copy Markdown
Collaborator Author

/bigbonk re-review

Comment thread .github/workflows/nextjs-deploy-suite.yml Outdated
@james-elicx james-elicx marked this pull request as ready for review May 14, 2026 12:29
@james-elicx james-elicx force-pushed the ci/nextjs-deploy-suite-harness branch from 9c72242 to 49ebd59 Compare May 14, 2026 12:32
Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

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

Re-review: ci: add Next.js deploy suite harness

Reviewed at 9c72242. Previous review items are resolved, pull_request trigger removed. CI Check failure is a pre-existing oxlint false positive on client-reference-runtime-map.browser.spec.ts (rules-of-hooks on Playwright's use fixture), unrelated to this PR.

Actionable

1. vinext:jsx-in-js double-transforms every .js file

packages/vinext/src/index.ts — The vinext:jsx-in-js plugin runs transformWithOxc with lang: "jsx" on every .js/.mjs file outside node_modules, even files that contain zero JSX. OXC is fast enough that this is unlikely to be a latency problem in practice, but it means every .js module in a project gets an extra transform pass (parse → emit → sourcemap) that does nothing. A cheap early bail-out would avoid this:

// Skip files that don't contain any JSX syntax
if (!code.includes('<') || (!code.includes('/>') && !code.includes('</'))) return;

The heuristic doesn't need to be perfect — false positives just mean a no-op transform, which is what happens today anyway. But for large codebases with hundreds of .js utility files, skipping the transform entirely is a measurable win. Not blocking, but worth doing.

2. CJS-to-ESM converter misses const { a, b } = require('mod') (destructured imports)

scripts/e2e-deploy.sh:~458-490 — The converter handles const X = require('mod') and const X = require('mod')(args) but doesn't handle destructured requires like const { withContentlayer } = require('next-contentlayer'). The regex \b(const|let|var)\s+(\w+)\s*= only matches a single identifier, not { ... } destructuring patterns.

This matters because Next.js config files commonly use destructured requires (plugins, config helpers). If a test app's next.config has one, it will be left as CJS require() in an ESM context and fail at runtime. The third regex (remaining require()await import()) would partially catch it, but const { a } = (await import('mod')).default is not equivalent to const { a } = require('mod') — the destructuring would target the default export object, which may or may not have those properties.

For the deploy suite harness this is probably fine since the subset of test apps is controlled, but worth a TODO comment noting the limitation.

3. cleanup_on_error uses $PORT but it's not guaranteed to be set

scripts/e2e-deploy.sh:~184 — The cleanup_on_error trap references ${PORT} in the lsof fallback, but the PORT variable is set on line ~212. If the script fails before that line (e.g., during find_free_port), PORT is unset and lsof -ti "tcp:" would match nothing (harmless but messy). The trap already checks [ -f "${PORT_FILE}" ], which is sufficient — but it reads the port from the file contents, not from $PORT. This is fine because the file won't exist if PORT was never set. Just noting the inconsistency — consider reading PORT from PORT_FILE in the trap for correctness.

Non-blocking observations

nextjs-deploy-manifest.json cached but also in .
The cache path includes both . and nextjs-deploy-manifest.json. Since the manifest is written to $GITHUB_WORKSPACE/nextjs-deploy-manifest.json which is inside the workspace (.), the explicit path entry is redundant. Not harmful — actions/cache deduplicates — but could be cleaned up for clarity.

Report job JS string interpolation
Lines 300-302 of the workflow interpolate ${{ inputs.vinext-ref || github.ref }} etc. directly into JS string literals. As noted in the previous review, a branch name containing a single quote would break the JS syntax. This is extremely unlikely for the expected inputs (branch names, semver tags) and github-script doesn't offer a clean escape mechanism, so it's fine.

wait_for_http accepts any non-000 status
e2e-deploy.sh:~139 — The function treats any HTTP response (including 500, 502) as "server is ready." This is intentional per the deploy harness contract (the test runner handles response validation), but it means a crashing server that serves 500s will appear "ready." The 2-minute timeout is the backstop. Fine for the harness.


Previous review items all verified as fixed. The PR is in good shape. The CJS converter limitation (#2) is the most likely thing to cause a real failure in practice if a test app has destructured requires in next.config, but it's scoped to the test harness and easy to extend later.

LGTM — approve.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented May 14, 2026

Review posted on PR #1189. Here's a summary of the findings:

Actionable items (3):

  1. vinext:jsx-in-js double-transforms every .js file — The plugin runs transformWithOxc on all .js/.mjs files even when they contain no JSX. A cheap heuristic check for < could skip no-op transforms.

  2. CJS-to-ESM converter misses destructured importsconst { a, b } = require('mod') patterns aren't handled by the converter regexes. The fallback regex partially catches it but produces semantically different code ((await import()).default vs direct module exports). Worth a TODO comment.

  3. cleanup_on_error references $PORT before it's set — Harmless in practice (the PORT_FILE check gates it), but the trap should read port from the file rather than the variable for consistency.

Non-blocking observations:

  • Redundant nextjs-deploy-manifest.json in cache paths (already inside .)
  • JS string interpolation in report job (branch names with single quotes could break, but extremely unlikely)
  • wait_for_http accepts any HTTP status as "ready" (intentional per harness contract)

The PR is approved — all previous review items are verified fixed, and the remaining findings are minor.

github run

Comment thread .github/workflows/nextjs-deploy-suite.yml Outdated
Add the workflow, scripts, and manifest generator for running the
Next.js Pages Router deploy test suite against vinext.

Triggers:
- Nightly cron (06:00 UTC) against main
- Manual dispatch with configurable vinext-ref, next-ref, and concurrency

Extracted from #922.
- Rename scripts to match Next.js convention: e2e-deploy.sh, e2e-logs.sh,
  e2e-cleanup.sh
- Split workflow into build + test jobs (build once, shard 16 ways) per
  the documented adapter testing pattern
- Generalize workflow from pages-only to configurable: add suite-filter
  input (pages/app/all, defaults to pages)
- Add --filter flag to manifest generator (replaces the pages-hardcoded
  version)
- Accept ADAPTER_DIR (Next.js docs convention) alongside VINEXT_DIR
- Rename workflow file to nextjs-deploy-suite.yml
- Use matrix.group strings ("1/16") instead of shard integers, matching
  the docs example
… shims

- Add a report job that aggregates .results.json across all shards into
  a GitHub Actions summary (pass/fail/skip counts, failed test details,
  passed suite list) and uploads a JSON report artifact
- Upload test results from every shard (not just on failure)
- Remove redundant next.js/ from cache paths (already under .)
- Add comment explaining why IS_TURBOPACK_TEST=1 is needed
- Clean up stale PID file in e2e-cleanup.sh
- Add header comments to all scripts explaining their purpose and contract
- Document the hardcoded warning messages and .next/trace shim
- Document the YAML catalog parser assumptions
- Fix [[ ]] -> [ ] inconsistency in run-nextjs-deploy-suite.sh
Bugs found and fixed:

- IMMUTABLE_ASSET_TOKEN marker renamed to NEXT_SUPPORTS_IMMUTABLE_ASSETS
  to match what next-deploy.ts parseIdsFromCliOuput() actually parses.
  Without this, every test fails with 'Failed to get supportsImmutableAssets'.

- Deploy script now injects "type": "module" into test app package.json
  and generates a vite.config.ts. Without type:module, Rolldown emits .mjs
  files but the RSC plugin's cross-environment imports expect .js. This
  mirrors what `vinext init` does (steps 3 and 5).

- Added vp (Vite+) fallback to run_pnpm() for environments where pnpm
  and corepack are not available but vp is.

- Cleanup script now uses process group kills (kill -TERM -PID) and a
  port-based lsof fallback to handle orphaned child processes from
  vp/pnpm exec wrappers.

- Error cleanup trap now dumps the last 80 lines of the build log and
  last 40 lines of the server log to stderr, so failures are visible
  in CI output (previously only showed file sizes).

- Test job uses run-install: false since the workspace is already built
  in the cache from the build job.

Tested locally: deploy script succeeds, curl returns valid HTML, logs
script outputs all three required markers (BUILD_ID, DEPLOYMENT_ID,
NEXT_SUPPORTS_IMMUTABLE_ASSETS), cleanup kills the server.
…me list

Replace the manual type:module / vite.config.ts / CJS rename logic in
e2e-deploy.sh with a single `vinext init --skip-check --force` call.
This runs after pnpm install (so deps are available) and before
vinext build.

Also add next.config.js to the CJS_CONFIG_FILES list in project.ts.
Without this, vinext init adds type:module but doesn't rename CJS
next.config.js files, causing 'module is not defined in ES module
scope' errors. This was the root cause of the CI failures — Next.js
test fixtures use module.exports in next.config.js.

All 61 init tests pass.
Next.js doesn't support next.config.cjs, so we can't rename it. Instead,
convert module.exports/require() to export default/import in-place after
vinext init adds "type": "module".

Also revert adding next.config.js to CJS_CONFIG_FILES — vinext init
should not rename it since it's not a generic config file.

Tolerate pnpm 10+ ERR_PNPM_IGNORED_BUILDS exit code 1 on install (the
install completes, packages are in node_modules, but pnpm exits non-zero
due to unapproved build scripts). Verify node_modules/vinext exists
as a safety check.

Tested against the real Next.js actions-streaming fixture: CJS
next.config.js converted, app builds, server starts, HTTP 200.
v16.2.x parses IMMUTABLE_ASSET_TOKEN, canary renamed it to
NEXT_SUPPORTS_IMMUTABLE_ASSETS. Emit both for cross-version compat.
Add vinext:jsx-in-js transform plugin to handle JSX in plain .js files.
Next.js allows JSX in .js files (Babel/SWC handle it transparently),
but Vite 8's built-in vite:oxc plugin excludes .js files by default
(exclude: /\.js$/) AND infers lang: 'js' from the extension (which
disables JSX parsing). Neither can be fixed via config alone.

The plugin runs with enforce: 'pre' before vite:oxc, transforming .js
files with OXC using lang: 'jsx' so JSX is compiled before vite:oxc
sees the code. This unblocks ~60 test suites in the deploy suite.

Also extend the deploy script's CJS-to-ESM config converter to handle
next.config.ts files (not just .js), fixing ~6 more test failures.

Tested: 1284 tests pass (jsx-in-js + shims + routing + app-router),
zero regressions.
The naive regex converter missed two patterns:
- require('mod')(args) produced invalid ESM (import X from 'mod'(args))
- require() calls inside function bodies were not converted

New converter handles:
- module.exports = X → export default X
- const X = require('mod') → import X from 'mod'
- const X = require('mod')(args) → import _X from 'mod'; const X = _X(args)
- require('mod') in expressions → (await import('mod')).default

Tested against bundle-analyzer, path, and inline require patterns.
@james-elicx james-elicx force-pushed the ci/nextjs-deploy-suite-harness branch from 52ad8d1 to a70748b Compare May 14, 2026 12:50
Comment thread .github/workflows/nextjs-deploy-suite.yml Outdated
…le in cleanup

- Add pattern for const { a, b } = require('mod') → import { a, b } from 'mod'
- Read port from PORT_FILE in cleanup_on_error trap instead of using $PORT
  variable which may be unset if the script fails before port allocation
- Add TODO noting remaining CJS edge cases (dynamic require, require.resolve)
@james-elicx
Copy link
Copy Markdown
Collaborator Author

/bigbonk review

Comment thread tests/e2e/fixtures.ts
Comment thread tests/e2e/fixtures.ts Outdated
Co-authored-by: James Anderson <[email protected]>
Comment thread packages/vinext/src/init.ts Outdated
Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk Bot left a comment

Choose a reason for hiding this comment

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

Re-review: ci: add Next.js deploy suite harness

Reviewed at e9fca14. All prior review items verified as addressed.

Changes since last review (9c72242e9fca14)

Change Status
pull_request trigger removed from workflow Applied (via suggestion commits)
tests/e2e/fixtures.ts lint suppress reverted to original location Applied — file is now unchanged from main, so the CI Check oxlint failure should be resolved
Destructured require handling in CJS converter Already in at 40838c1
cleanup_on_error reads port from PORT_FILE Already in at 40838c1

Current state

The PR adds 8 files (workflow, 4 scripts, manifest generator, .gitignore entry, init.ts doc comment). All previous actionable items across three review rounds have been addressed. The fixtures.ts change has been fully reverted — the file is identical to main.

CI status: Check job is queued for e9fca14. The previous failure was the oxlint rules-of-hooks false positive on the moved suppress comment, which this commit fixes by reverting fixtures.ts entirely.

Remaining observations (non-blocking)

1. e2e-cleanup.sh does not clean up PORT_FILE

The cleanup script removes PID_FILE (line 30) but not PORT_FILE. The deploy script's cleanup_on_error also does not remove either file. Since the Next.js harness uses isolated temp directories that are discarded, this is harmless in practice — but for local development reruns in the same directory, stale files could cause confusion.

2. CJS converter regex ordering

The regex for const X = require('mod') (step 2) would match the LHS of const X = require('mod')(args) if step 1 did not run first. The current ordering is correct, but it is implicit — the regexes depend on execution order for correctness. A comment noting this dependency would prevent a future reordering from introducing a subtle bug.

3. Report job string interpolation

Lines 302-304 of the workflow embed ${{ inputs.vinext-ref || github.ref }} directly into a JS string literal. As noted in the previous review, a single quote in a branch name would break the JS. This remains extremely unlikely and there is no clean workaround in github-script, so it is fine.


None of the above are blockers. The PR is well-structured, all review feedback has been addressed across the iterations, and the CI failure path is clear.

LGTM — approve.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented May 14, 2026

Review posted on PR #1189. Here's a summary:

All prior review items are resolved. The latest commit (e9fca14) applied the suggestion comments — the pull_request trigger was removed from the workflow and the fixtures.ts change was fully reverted (file is now identical to main), which should fix the CI Check oxlint failure.

3 non-blocking observations:

  1. e2e-cleanup.sh doesn't clean up PORT_FILE (harmless since test apps use isolated temp dirs)
  2. CJS converter regex ordering has an implicit dependency (step 1 must run before step 2)
  3. Report job JS string interpolation vulnerability with single quotes in branch names (extremely unlikely)

PR approved — ready to merge once CI passes on the latest commit.

github run

@james-elicx james-elicx enabled auto-merge (squash) May 14, 2026 12:57
@james-elicx james-elicx merged commit 747bb0e into main May 14, 2026
35 checks passed
@james-elicx james-elicx deleted the ci/nextjs-deploy-suite-harness branch May 14, 2026 13:01
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