469 Commits

Author SHA1 Message Date
Sebastian "Sebbie" Silbermann 43c1c60bca [16.3] [ci] Use OIDC tokens to read private preview builds (#97258)
Backports https://github.com/vercel/next.js/pull/96919

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-13 14:00:45 -07:00
Hendrik Liebau c00449d52b [ci] Wait for the preview tarballs before running the deploy tests (#96527)
The "Test new and changed tests when deployed" jobs install Next.js from
the preview tarballs built for the commit under test, but nothing made
them wait for those tarballs to exist. Until #96438 the job was ordered
behind `test-prod` and the other new-test jobs, which delayed it long
enough that the tarballs had usually landed by the time it looked for
them. Now that it starts immediately it frequently fails with "Artifacts
not found for commit ...".

The ordering cannot be expressed as a `needs:` entry, because the
tarballs are published by a different workflow and, for pull requests
from branches in this repository, a different event than the
`build-and-test` run that consumes them. We therefore add a
`wait-for-preview-tarball` job that polls for the tarball instead, and
make both deploy test jobs depend on it. Doing the waiting in one cheap
job keeps the deploy test matrices off their 16-core runners until there
is something for them to install.

The new job is also listed in `tests-pass`. A dependency failure skips
the jobs that need it, and a skipped job does not count as a failure, so
without that entry a tarball that never arrives would have let the
required check pass with the deploy tests never having run.

`test-new-tests-deploy-cache-components` gets the same treatment,
dropping the incidental ordering it still inherited from
`test-cache-components-prod` and picking up the docs-only guard that
`test-new-tests-deploy` already had.
2026-08-03 16:27:51 +02:00
Sebastian "Sebbie" Silbermann e89118a0ab [react-sync] Enable auto-merge on PRs (#96442)
Saves a click. These PRs still require approval as per repo settings.

The commit description is empty so that the React PRs aren't mentioned
again in commits. That'd be pretty noisy for the React PRs.
2026-07-31 21:03:23 +00:00
Sebastian "Sebbie" Silbermann 34299ad5d0 [ci] Match the test job summary style to the PR test report comment (#95882) 2026-07-30 08:41:25 -04:00
Sebastian "Sebbie" Silbermann 6ab0dd6fcd [ci] Install Node.js from the official tarball in the native-builder image (#96298)
Fixes e.g.
https://github.com/vercel/next.js/actions/runs/30314671467/job/90137708228#step:12:603

The `native-builder` image (`scripts/native-builder.Dockerfile`), used
by the `build-native` job of `build_and_deploy.yml` to cross-compile
`next-swc`, installed Node.js 20 via the NodeSource setup script. That
script downloads and imports a signing key before configuring the apt
repository. When the key download returns an HTTP 403 from CI runners
the script still exits successfully, so `apt-get install nodejs` falls
back to Ubuntu's stock `nodejs` package, which does **not** bundle
`npm`. The failure only surfaced two layers later when the image ran
`npm i -g @napi-rs/cli` (`npm: not found`, exit 127), breaking the
native build.

This change installs Node.js 20 from the official `nodejs.org` static
tarball instead. The tarball bundles `npm` and `corepack`, is
glibc-linked (matching the previous intent), and does not depend on
NodeSource's apt repository or key server, removing the flaky external
dependency. The install step also asserts `npm --version`, so a future
regression fails at the install layer rather than several layers later.


## test plan

- [x] [full build_and_deploy on this
branch](https://github.com/vercel/next.js/actions/runs/30372888336)
2026-07-28 15:21:20 -04:00
Niklas Mischkulnig b3278b7573 test: Use Turbopack for 'Test new and changed tests when deployed' (#95552) 2026-07-07 16:03:00 +02:00
Sebastian "Sebbie" Silbermann cd3476c3c8 [ci] Add stats comment with partial stats (#95401)
We used to not post a comment when a part of the bundler matrix got
cancelled. Conceptually, a cancelled job is just like a failed on in the
sense of not being able to produce stats.

Now we always aggregate stats and post stats from the bundlers that did
produce them.

The risk here is a race between a run that was cancelled because another
run superseded it and the run that superseded it. Though practically,
aggregating the stats isn't slower than running the full workflow. Not
impossible (especially given how slow the Webpack job is) but incredibly
rare.
2026-07-06 19:13:28 +00:00
Sebastian "Sebbie" Silbermann f656c597c6 [fragment-scroll] Enable new scroll handler by default (#95378) 2026-07-06 18:39:07 +00:00
Sebastian "Sebbie" Silbermann d3169de7e5 Collect modules with browser variants statically (#95200)
Instead of hardcoding the list, we now automatically detect any
`.browser` sibling and create a compiler alias for that module.

Together with a linting rule, we'll ensure no future regressions are
handled automatically (detection of conditional require and missing
.browser sibling).

This isn't the smoothest DX yet. Ideally we'd generate the list at
Next.js compile time (i.e. before publishing) to avoid having to rerun a
script (I'll follow-up). Generating the list during build time (next dev
or next build) is just another tiny cost users would have to pay.
2026-07-03 08:45:23 +02:00
Sebastian "Sebbie" Silbermann 7443e117dc [cd] Replace the release package with our own GitHub release creation (#95352) 2026-07-02 09:07:26 +00:00
Sebastian "Sebbie" Silbermann dcb662c7fb [ci] Add support for auth based preview build registries (#95204)
Follow-up to https://github.com/vercel/next.js/pull/93464 which didn't
consider auth based preview build registries.
2026-06-30 20:59:15 +02:00
Sebastian "Sebbie" Silbermann 1d9b56dad1 [ci] Display correct test commands when Cache Component test fail (#95267) 2026-06-29 12:16:05 +00:00
Sebastian "Sebbie" Silbermann 69acc33f03 [ci] Make automatic native binding install opt-in (#95114)
A `pnpm install` installs native bindings for Next.js by default. This
makes sense for local development where half of the team doesn't work on
native code and just needs the most recent bindings. However, CI almost
exclusively wants to test with bindings that are built from the current
commit. The rest doesn't need native bindings at all.

The only exception is `test_examples` which is likely not functional.
Though we still support it by allowing to opt-into automatically
installing native bindings in CI.

## test plan

- [x] fetch test timings still skips:
https://github.com/vercel/next.js/actions/runs/28087707205/job/83157705446?pr=95114#step:7:228
2026-06-24 22:39:36 +02:00
Sebastian "Sebbie" Silbermann 681940523a [cd] add ad-hoc preview release cut from canary (#95086)
Add a `preview` release type so `@preview` npm releases can be cut
**ad-hoc from `canary`** via the `Trigger Release` workflow, retiring
the dedicated long-lived preview branch. The GitHub environment has been
updated accordingly.

A preview cut produces **two commits**, pushed in a single update:

1. **Bump-to-preview** — all packages set to the computed preview
version, tagged `v…-preview.N`. This tag's build publishes `@preview`
(relies on #95085).
2. **Revert-to-canary** — restores the `-canary.N` versions so `canary`
keeps advancing its own line and isn't stranded on a preview version.

```
B  canary HEAD before cut (e.g. 16.3.0-canary.61)
│
P  v16.3.0-preview.N   ← tag here; tag build publishes @preview
│
R  canary HEAD after cut (versions restored to 16.3.0-canary.61)
```

### Preview version numbering

`base = max(canary major.minor.patch, npm @preview major.minor.patch)`:
- base still on the published preview line → continue it (`n + 1`)
- canary advanced to a higher base (or no `@preview` published) → reset
to `.0`

So if `canary` jumps to `18.0.0-canary.x` since the last
`16.3.0-preview.x`, the next cut is `18.0.0-preview.0`, not a
continuation.

## Test plan

The dry mode of `start-release.js` was extended to intercept the GH
requests and log the relevant data.

```console
$ node ./scripts/start-release.js --release-type preview --dry-run
Dry run: keeping commits locally, skipping git push and GitHub release creation
Running pnpm release-preview...
[...]
> lerna version 16.3.0-preview.4 --force-publish -y --no-push --allow-branch '**'
[...]
Creating GitHub-signed release commit(s) for v16.3.0-preview.4 from local commits 0f5c1e865cc34edb257a16823ed6525d9cd58bfc..0062348c411776271fe7eac64e97b8bad2775b77
[dry-run] GitHub API POST /repos/vercel/next.js/git/blobs [...]
[dry-run] GitHub API POST /repos/vercel/next.js/git/commits {"message":"v16.3.0-preview.4","tree":"0000000000000000000000000000000000000016","parents":["0f5c1e865cc34edb257a16823ed6525d9cd58bfc"]}
[dry-run] GitHub API POST /repos/vercel/next.js/git/commits {"message":"Restore canary version 16.3.0-canary.61 after v16.3.0-preview.4 preview release","tree":"000000000000000000000000000000000000002d","parents":["0000000000000000000000000000000000000017"]}
[dry-run] GitHub API POST /repos/vercel/next.js/git/refs {"ref":"refs/tags/v16.3.0-preview.4","sha":"0000000000000000000000000000000000000017"}
[dry-run] GitHub API PATCH /repos/vercel/next.js/git/refs/heads/sebbie/preview-release-from-canary {"sha":"000000000000000000000000000000000000002e","force":false}
Dry run: skipping local branch sync; would set sebbie/preview-release-from-canary to 000000000000000000000000000000000000002e and tag v16.3.0-preview.4 at 0000000000000000000000000000000000000017
Created GitHub-signed release tag v16.3.0-preview.4 at 0000000000000000000000000000000000000017; branch sebbie/preview-release-from-canary now at 000000000000000000000000000000000000002e
Dry run: skipping GitHub release creation
Release process is finished
```
2026-06-24 16:33:37 +02:00
Sebastian "Sebbie" Silbermann 2aba93f005 [scripts] Write pnpm overrides for pnpm projects in pack/patch helpers (#94747) 2026-06-22 17:12:14 +02:00
Steven b229f6400c [cd] reduce size of npm metadata on publish (#94953) 2026-06-19 01:02:53 +02:00
Sebastian "Sebbie" Silbermann 47c8c6fc92 [cd] Continue release train if @next/swc-wasm-* fails to publish (#94912)
https://github.com/vercel/next.js/pull/94622 tried to be more strict
with when a release is considered healthy. However, `@next/swc-wasm-web`
is not enrolled in Trusted Publishing and blocks the release train.

This PR restores the behavior for `@next/swc-wasm-*` packages prior to
https://github.com/vercel/next.js/pull/94622 i.e. we continue the
release train even if any `@next/swc-wasm-*` fails. Other NAPI bindings
will continue to block the release train if they fail to publish.

The bail vs no-bail behavior is controlled with a repository variable so
that we can mor easily test if `@next/swc-wasm-web` is enrolled in
Trusted Publishing.
2026-06-17 20:49:57 +02:00
Sebastian "Sebbie" Silbermann 618957c166 [cd] More robust publish pipeline (#94622) 2026-06-17 19:44:59 +02:00
Benjamin Woodruff 3caee03f2a [ci] Reduce usage of turborepo cache in build_and_deploy.yml (#94319)
We're consolidating on `actions/cache` now that we got rid of
self-hosted runners. This doesn't remove all of the uses of turborepo's
cache (notably sccache), but this does eliminate the remote turborepo
cache for the native build cache and the docker image.

These build steps use docker so that we're building against an old
pinned glibc (2.31), and so that we can have access to both `aarch64`
and `x86_64` musl sysroots.

## Testing

**Local Build:** `node scripts/docker-native-build.js` still works (this
script just exists for being able to debug these builds locally)

**CI Build:**
- Run an automated-preview CI job, but cancel it before the native build
succeeds to test writing to the docker cache but not the native cache:
https://github.com/vercel/next.js/actions/runs/26986955366/job/79638633136?pr=94319
- Re-run the job with only the docker image cache, see that we get a
cache hit for the docker image:
https://github.com/vercel/next.js/actions/runs/26986955366/job/79639365126?pr=94319
- Re-run the job again and see that we hit the native build cache hit
and don't touch docker at all:
https://github.com/vercel/next.js/actions/runs/26986955366/job/79647324952?pr=94319
- Manually trigger the job to do a full preview build:
https://github.com/vercel/next.js/actions/runs/26989861549
2026-06-10 14:23:18 -07:00
Joseph 867227352b chore: lint-language output only warnings and errors (#94261)
The lint-language script is too verbose, it prints "no issues found" for
all files it touches.
2026-06-02 10:07:28 +02:00
Sebastian "Sebbie" Silbermann c1c33c92f9 [ci] Reserve comments for stats and tests (#93240) 2026-05-26 18:00:46 +02:00
Tobias Koppers a80e0d5668 Fix errors.json merge driver to handle gaps in error codes (#93829)
### What?

Fixes the `errors.json` git merge driver
(`scripts/merge-errors-json/merge.mjs`) so that it allocates new error
ids based on the largest existing numeric key rather than the entry
count. When the current file has gaps in its numeric keys (e.g. retired
error codes), the previous logic produced ids that collided with
existing entries and silently overwrote them during a rebase/merge.

### Why?

The driver computed the next id with:

```js
let nextKey = Object.keys(result).length + 1
```

This only works when ids are dense (`1..N` with no holes).
`packages/next/errors.json` has accumulated gaps over time — for example
missing ids around 1232–1234 and 1246 on `canary`. When a branch was
rebased onto `canary` and the driver replayed a commit that added new
entries, the computed `nextKey` (`length + 1`) pointed at an id that was
already in use higher up in the map. The replayed entries then clobbered
existing canary messages (e.g. "Route encountered %s during the initial
render" and "in a Client Component" at 1244/1245), corrupting
`errors.json` without raising a conflict.

Because the driver writes the result directly and exits 0, this kind of
corruption is invisible at rebase time and only surfaces later when the
displaced messages start producing wrong/duplicate codes at runtime.

### How?

- Introduce a `getMaxNumericKey(map)` helper that scans the keys of the
merged map, parses each as an integer, and returns the largest value (or
`0` if there are no numeric keys).
- Use `getMaxNumericKey(result) + 1` as the starting `nextKey` in
`mergeErrors`, so newly added messages are always appended above the
highest currently-used id, regardless of gaps.

Behavior for the dense / no-gap case is unchanged: `max + 1 === length +
1` when ids are `1..N` contiguous, so all three existing scenarios in
`test/scripts/merge-errors-json/merge-errors-json.test.ts` (basic
conflict, empty base, stacked PRs) continue to pass.

No changes to `errors.json` itself are included here; this PR only fixes
the driver going forward.

<!-- NEXT_JS_LLM_PR -->

Co-authored-by: v-work-app[bot] <262237222+v-work-app[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
2026-05-25 20:29:01 +02:00
Tim Neutkens 685d5b9e93 Fix pr-status job pagination (#94049)
### What?

Lower the GitHub Actions jobs page size used by `scripts/pr-status.js`
and keep walking pages until all jobs are fetched. Reuse the paginated
job fetch for flaky-test detection.

### Why?

The previous `per_page=100&page=1` request for run `26093602659` returns
HTTP 502 from GitHub because the query is too slow.

### How?

Add a shared `JOBS_PAGE_SIZE = 30`, update the pagination stop condition
to match it, and route flaky-test failed job lookup through
`getFailedJobs()`.

### Verification

- `node --check scripts/pr-status.js`
- `pnpm prettier --with-node-modules --ignore-path .prettierignore
--write scripts/pr-status.js`
- `npx eslint --config eslint.config.mjs --fix scripts/pr-status.js`
- `gh api
"repos/vercel/next.js/actions/runs/26093602659/jobs?per_page=30&page=<n>"
--jq ".jobs | length"` across pages 1-5 captured 137 jobs, matching
`total_count: 137`
- Confirmed the old `per_page=100&page=1` request still returns HTTP 502
- Not run: full Next.js test suite (scripts-only helper change)

<!-- NEXT_JS_LLM_PR -->
2026-05-22 15:37:23 +00:00
Tim Neutkens cdd77ac4f3 Add deployable tarballs to pack-next (#93963)
### What?

Adds a `--deployable-tar` option to `pack-next` that writes generated
tarballs into the target project and patches package references to use
relative `file:` paths.

### Why?

Projects that need to deploy with locally packed Next.js packages should
be able to include those tarballs inside the project directory instead
of referencing tarballs from the Next.js checkout.

### How?

Resolves the target project package.json location, writes tarballs to a
sibling `tarballs/` directory, and maps package override paths to
project-relative references when patching package.json. Existing `--tar`
behavior continues to write to the repository tarballs directory.

### Verification

- `git diff --check`
- `git diff --cached --check`
- `pnpm prettier --with-node-modules --ignore-path .prettierignore
--write scripts/pack-next.ts scripts/pack-utils/patch-package-json.ts
contributing/core/testing.md contributing/core/developing.md`
- `npx eslint --config eslint.config.mjs --fix scripts/pack-next.ts
scripts/pack-utils/patch-package-json.ts contributing/core/testing.md
contributing/core/developing.md` (Markdown files were ignored because no
matching ESLint config was supplied)
- `pnpm pack-next --project ../sandbox/nextjs-duplicated-html-repro/
--deployable-tar`

<!-- NEXT_JS_LLM_PR -->
2026-05-20 08:00:56 -07:00
Tim Neutkens 8141dcf12e Convert test/integration to isolated tests (#93247)
### What?

Converts every test under `test/integration/` to an isolated test
running through `nextTestSetup` (under `test/e2e/`, `test/production/`,
`test/development/`, or `test/unit/`), then deletes `test/integration/`
along with the legacy CI orchestration that was specific to it.

- `test/integration/` removed entirely (~327 test suites)
- New isolated suites added across the existing folders:
  - `test/e2e/` — 175
  - `test/production/` — 130
  - `test/development/` — 43
  - `test/unit/` — 1
- `.github/workflows/build_and_test.yml` and `run-tests.js` no longer
have any `integration` branches
- `nextTestSetup` gained a `baseUrl` option on `next.browser()` so a
small number of tests that drive their own proxy/static-export server
can keep using `next.browser(...)` instead of importing `next-webdriver`
directly

### Why?

`test/integration/` predated `nextTestSetup` and ran tests directly
against the source checkout via custom helpers (`launchApp`,
`nextBuild`, `nextStart`, `runNextCommand`, `webdriver`, `fetchViaHTTP`,
…). Each suite hand-rolled its own dev/start/build orchestration,
fixture mutation, and process management.

The isolated test model used by the rest of the repo gives each suite an
isolated working directory containing a packed `next.tgz` install, a
uniform `next.start()` / `next.build()` / `next.fetch()` /
`next.browser()` API, and the same lifecycle for dev, start, and deploy
modes — so a single set of assertions covers all three. Deploy-mode
skips and per-feature gates are expressed declaratively
(`skipDeployment`, `disableAutoSkewProtection`, `if (skipped) return`)
instead of branching on `process.env`.

Removing `test/integration/` lets us:

- Delete the bespoke orchestration code in the CI workflow and
`run-tests.js`
- Run every converted suite consistently in dev, start, and deploy modes
(where applicable)
- Reproduce every test locally with the same `pnpm
test-{dev,start}-{turbo,webpack}` commands; no separate `integration`
path
- Open the door to running `test/production` against deployments in the
future (the converted suites already declare `skipDeployment` so they
can be flipped on)

### How?

Mechanical conversion per suite, with targeted clean-ups:

1. **Per-suite conversion.** Each
`test/integration/<name>/test/index.test.{js,ts}` was rewritten into a
single `<name>.test.ts` under the right folder based on what the
original exercised:
   - `launchApp` / dev-only assertions → `test/development/`
- `nextBuild` + `nextStart` / start-only assertions → `test/production/`
   - Both → `test/e2e/`
- The one pure jsdom render check (`link-without-router`) → `test/unit/`

2. **API mapping.** Custom helpers were replaced by `nextTestSetup`
equivalents: `launchApp` → `next.start()`, `nextBuild` → `next.build()`,
`runNextCommand` → `next.runCommand`, `fetchViaHTTP` → `next.fetch`,
`webdriver(...)` → `next.browser(...)`. Fixture mutations switched from
raw `fs.writeFile`/`fs.rename` to `next.patchFile` (with the 3-arg
`runWithTempContent` callback when the change has a defined scope) and
`next.deleteFile`.

3. **Deploy-mode handling.** Suites that can't run in deploy mode (use
`patchFile` / `next.build()` / depend on local CLI output) declare
`skipDeployment: true` and early-return on the `skipped` boolean. Suites
where Vercel's edge mutates URLs (`&dpl=`, immutable assets) declare
`disableAutoSkewProtection: true`.

4. **`next.browser({ baseUrl })`.** A handful of tests
(`prerender-export`, `cdn-cache-busting`, `preload-viewport`, both
`react-virtualized` suites) need to drive a separate server (a
static-export server or an `http-proxy` instance) rather than the
Next.js process. Instead of importing `next-webdriver` directly, those
tests now pass `{ baseUrl: <port|url> }` to `next.browser()`. For the
proxy cases, the proxy was moved into `server.js` inside the fixture and
`http-proxy` declared via the `dependencies` option of `nextTestSetup`,
so the test runs with a fully isolated dependency graph.

5. **CI clean-up.** With `test/integration` gone, the `test
integration*` jobs and `integration-tests-manifest`-related logic in
`.github/workflows/build_and_test.yml` were removed, and `run-tests.js`
no longer has the `integration` test-folder branch.

6. **Validation.** The PR was iterated against multiple full CI runs;
the remaining failures on the latest run are pre-existing flakes
(segment-cache 60s `act` timeouts in turbopack-prod) or transient
infrastructure issues unrelated to the conversion.
2026-05-11 13:55:47 +02:00
Niklas Mischkulnig ead8013f88 Turbopack: more strict vergen setup (#93541)
Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
Co-authored-by: Sebastian Sebbie Silbermann <sebastian.silbermann@vercel.com>
2026-05-07 08:50:02 +00:00
Sebastian "Sebbie" Silbermann 04294cb47a [ci] Clarify new preview build flow (#93540) 2026-05-06 14:04:19 +00:00
Sebastian "Sebbie" Silbermann 7240c74b23 [ci] Create unique preview build versions for canary previews (#93490) 2026-05-05 15:39:45 +02:00
Sebastian "Sebbie" Silbermann eaad55c518 [ci] Migrate React sync off of RELEASE_BOT_GITHUB_TOKEN (#93456) 2026-05-05 08:50:55 +00:00
Sebastian "Sebbie" Silbermann a9fe66ca2e [ci] Move Turbopack, Rspack and font data workflows off of RELEASE_BOT_GITHUB_TOKEN (#93455)
Co-authored-by: Benjamin Woodruff <github@benjam.info>
2026-05-05 10:23:01 +02:00
Sebastian "Sebbie" Silbermann 818aa24505 [ci] Allow configuring the base URL for preview builds (#93464) 2026-05-04 19:47:07 +02:00
Sebastian "Sebbie" Silbermann 13e83e14e4 [ci] Add support for private preview builds (#93375) 2026-04-30 18:36:25 +02:00
Sebastian "Sebbie" Silbermann b8c3e86156 Speed up native postinstall script (#93312) 2026-04-29 10:26:26 +00:00
Zack Tanner 0ea2845cf9 [ci]: fix release script to not strip newlines (#93302)
The process of signing commits with GH API was stripping newlines. This
configures that step to not strip newlines so lint doesn't fail. x-ref:
https://github.com/vercel/next.js/actions/runs/25007903789/job/73240317094

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-04-28 18:42:19 +00:00
Zack Tanner 012fd7df4b [ci]: trigger signed release commit via API (#93285)
Stacked on https://github.com/vercel/next.js/pull/93245

Commit signing is required for anything that lands on `canary`. Our
previous workflow of using a PAT to push a commit no longer works, since
that would have been an unsigned commit.

In #93245 we switched to an app token for release workflow steps. This
continues by:

- Telling Lerna to bump packages but not commit
- Creating a signed commit with the staged changes via GitHub's API
- Then running the publish flow

Test Plan:
Dry run
[here](https://github.com/vercel/next.js/actions/runs/25001287978/job/73211826479)
Commit
[here](https://github.com/vercel/next.js/commit/3a8456a62b56615e2f8c1d1e6e7b4e14ce89e078)
2026-04-27 16:31:05 +00:00
Zack Tanner e69de2ffaf [ci]: app-based release workflow (#93245)
Moves all release workflows off of a GH PAT and uses an app with a
short-lived token instead.

Test Plan:
Dry run
[here](https://github.com/vercel/next.js/actions/runs/24934593874).

However, this workflow is blocked until we figure out commit signing for
the bot app. Some options:
- The bot account generates a signing key and we use it in CI (not
great, bypasses the app)
- The org bypasses signature verification for the bot user (also not
great, requires an exemption rule)
- We need to rework the commit step so Lerna does not do the push, and
instead trigger it via the app + GH API. This seems like the best
option, will be added in a follow-up PR.

Note: `create-release-branch` workflow is broken in its current form, as
we will not be restoring administrator privileges to adjust environment
settings. This will become a manual step in the future.
2026-04-27 07:55:43 -07:00
Sebastian "Sebbie" Silbermann 5ccc1cc26f [ci] Create test summary comment if job immediately passes (#93236) 2026-04-25 16:27:11 +02:00
Sebastian "Sebbie" Silbermann 8a390fbf76 [ci] Handle namespaced packages in preview builds (#93241) 2026-04-25 12:05:26 +00:00
Sebastian "Sebbie" Silbermann b7aca0c57c [ci] Upload preview builds directly to Vercel Blob (#93207) 2026-04-25 00:03:16 +02:00
Zack Tanner 1849a0d00e [ci]: move stats & CI status comment to workflow (#93220)
- Add a workflow_run reporter that posts PR test/stats comments using
`GITHUB_TOKEN`.
- Upload PR metadata artifacts from `build-and-test` and `Generate
Stats` so the reporter can safely resolve the target PR
- Move stats/test comment posting out of the external webhook/PAT path
while preserving the existing comment format

This means the test comment won't incrementally update as tests fail,
it'll just post once at the end, but that's a reasonable tradeoff to not
having to worry about a webhook.
2026-04-24 14:51:35 -07:00
Sebastian "Sebbie" Silbermann b92745fe16 [ci] replace next-labeler-webhook with in-repo GitHub Action (#93080) 2026-04-24 19:49:25 +00:00
Zack Tanner cabf0a4197 [ci]: pin rust-musl-cross (#93176)
Pins these docker dependencies. Follow-up from:
https://github.com/vercel/next.js/pull/93164#discussion_r3135035714

x-ref: 

https://github.com/rust-cross/rust-musl-cross/pkgs/container/rust-musl-cross/741104753?tag=x86_64-unknown-linux-musl

https://github.com/rust-cross/rust-musl-cross/pkgs/container/rust-musl-cross/741104508?tag=aarch64-unknown-linux-musl
2026-04-24 02:36:18 +00:00
Zack Tanner 82b320addf [ci]: switch to GitHub runners (#93164)
## Summary

Switch CI from self-hosted runners to GitHub-hosted runners and fix the
follow-up issues that showed up once the hosted jobs were exercised.

## Changes

- Move Linux workflows onto `ubuntu-latest-16-core-oss`, Windows
workflows onto `windows-latest-8-core-oss`, and the native mac release
lane onto `macos-15-intel`.
- Update the reusable build workflow to work in hosted environments by
relying on `runner.os` instead of label string matching, and by removing
the hardcoded `/home/runner` `fnm` path.
- Make Turbo/sccache configuration explicit for hosted runners:
  - unify on `vtest314-next-adapter-e2e-tests`
- pass `TURBO_TOKEN` via workflow env/secrets instead of assuming
runner-level env
- switch Turbo cache mode to `local:rw,remote:rw` so jobs still have
local cache behavior when remote cache is unavailable
- Update the `sccache` action defaults/docs to use the hosted-runner
secret setup (`TURBO_TOKEN`) instead of the old self-hosted token
wiring.
- Make Datadog reporting fail open so missing `DATA_DOG_API_KEY` does
not block CI.
- Fix the CLI reserved-port test so it asserts Next’s own `-p 1`
validation instead of failing earlier on hosted Linux due to
privileged-port binding.
- Replace the live `musl.cc` dependency in `native-builder.Dockerfile`
with musl sysroots imported from GHCR-hosted `rust-musl-cross` images,
keeping the existing `/opt/*-cross` layout used by the Linux native
build scripts.
- Fix the macOS native build workaround s so it applies to all
*-apple-darwin targets based on the Cargo target OS rather than the host
architecture, which avoids napi-build injecting the unsupported -Wl
linker arg when @next/swc is linked with rust-lld on hosted mac runners.

Test Plan:
- This PR's CI
- This
[build_and_deploy](https://github.com/vercel/next.js/actions/runs/24865715983/job/72801225722)
job running on every arch
2026-04-23 18:53:07 -07:00
Luke Sandberg 0b08e2f611 Collapse pnpm test scripts into a single helper invocation (#93097)
### What?

Every `pnpm test-*` / `pnpm testonly-*` script in the root `package.json` is now a single direct invocation of a new `scripts/run-jest.sh` helper instead of chaining through several `pnpm run` + `cross-env` layers.

### Why?

Each hop through `pnpm run` / `cross-env` spins up its own Node process and takes a few hundred milliseconds before anything useful happens. For example, `pnpm test-dev-turbo` used to walk through five layers:

```
test-dev-turbo
  -> pnpm run with-turbo pnpm test-dev-inner           (cross-env IS_TURBOPACK_TEST=1)
       -> pnpm test-dev-inner                          (cross-env NEXT_TEST_MODE=dev)
            -> pnpm testheadless                       (cross-env HEADLESS=true)
                 -> pnpm testonly
                      -> jest --runInBand
```

#### Measured overhead (same machine, same stubbed jest invocation — `jest --version`)

| Chain | Layers | Median (ms) | Range (ms) |
|---|---|---|---|
| `jest --version` (baseline, direct) | 1 | 80 | 75–89 |
| `pnpm test-dev-turbo --version` (**new**) | `pnpm → bash → jest` | 448 | 435–493 |
| `pnpm test-dev-turbo --version` (**old**) | `pnpm → cross-env → pnpm → cross-env → pnpm → cross-env → pnpm → jest` | 2494 | 2462–2512 |

That's **~2 seconds per test invocation** shaved off, and ~85% reduction in wrapper overhead (from ~2414 ms to ~368 ms). The remaining ~368 ms is essentially just one `pnpm run` startup, which is unavoidable while we keep the `pnpm test-*` entry points.

Real-world impact: for a ~72 s e2e test run this is ~3%, but for fast unit-test files (often <5 s) this is closer to 30-40%, and it adds up quickly in CI jobs that shell out to these scripts in a loop.

### How?

- New `scripts/run-jest.sh` parses named flags and `exec`s jest directly:
  - `--mode=<dev|start|deploy>` → sets `NEXT_TEST_MODE`
  - `--bundler=<webpack|turbo|rspack>` → sets `IS_WEBPACK_TEST=1` / `IS_TURBOPACK_TEST=1` / `NEXT_RSPACK=1 NEXT_TEST_USE_RSPACK=1`
  - `--experimental` → sets `__NEXT_CACHE_COMPONENTS=true __NEXT_EXPERIMENTAL_APP_NEW_SCROLL_HANDLER=true`
  - `--headless` → sets `HEADLESS=true`
  - `--` terminates flag parsing; everything after is forwarded verbatim to jest so existing workflows like `pnpm test-dev-turbo path/to/foo.test.ts -t "pattern"` keep working.
- Every `test-*` / `testonly-*` entry in `package.json` (including `testheadless`) now reads like `scripts/run-jest.sh --mode=dev --bundler=turbo --headless --`. No more `pnpm run` / `cross-env` indirection at the top level.
- Removed nine unused internal intermediates (`test-dev-inner`, `test-dev-experimental-inner`, `test-start-inner`, `test-start-experimental-inner`, `test-deploy-inner`, `testonly-dev-inner`, `testonly-start-inner`, `testonly-deploy-inner`, `test-inner`). These were only called by other package.json scripts and not referenced anywhere else in the repo.
- Kept `testonly`, `testheadless`, and all public `test-*` / `testonly-*` names so `AGENTS.md`, `contributing/core/testing.md`, `.conductor/`, and `.agents/skills/` work unchanged.
- The `with-webpack`, `with-turbo`, `with-rspack`, and `with-experimental` prefix scripts remain for ad-hoc use; they are just no longer in the hot path of the test scripts.
- `scripts/run-jest.sh` invokes a bare `jest`, which resolves via `$PATH` (pnpm prepends `node_modules/.bin/` when running a package script). The helper is documented as only supported when invoked through a package runner.

### Verification

Ran a small e2e test through the new chain in both dev+turbopack and start+webpack modes. Output confirms env vars propagate correctly (`PASS Turbopack ...` / `PASS webpack ...`, plus `pnpm next --turbopack` vs `pnpm next start` in the logs):

```
pnpm test-dev-turbo test/e2e/app-dir/_allow-underscored-root-directory/...
  -> PASS Turbopack ... 3 passed

pnpm test-start-webpack test/e2e/app-dir/_allow-underscored-root-directory/...
  -> PASS webpack ... 3 passed
```

CI is unaffected: every workflow invokes `node run-tests.js ...` directly, never through these pnpm scripts.

<!-- NEXT_JS_LLM_PR -->
2026-04-21 16:53:16 -07:00
Zack Tanner 129896c2e4 [ci]: remove publish token in favor of OIDC (#93065)
Switches from a long-lived token to trusted publishing OIDC flow. This requires a bump to Node (for feature support). Otherwise just dropping unnecessary envs.
2026-04-20 11:17:33 -07:00
Joseph 3f06973bc9 chore: remote apps/docs (#93041)
We are moving on a different direction here. Removing this app for now.
2026-04-20 11:06:20 -07:00
Matt Mastracci 3e847dfe0b Switch to cargo-binstall and pre-built sccache binaries (#92911)
## What

- Use `cargo binstall` instead of `cargo install` for Rust tools in the
Docker image
- Download pre-built vercel/sccache from GitHub releases instead of
compiling from git

## Why

`cargo install` compiles from source which is slow on cache miss. `cargo
binstall` downloads pre-built binaries in seconds. The vercel/sccache
fork now publishes release binaries, eliminating the need for the
`build-sccache` turbo task (~2-3 min compile).

## Changes

**Dockerfile:**
- Install cargo-binstall at pinned version (1.18.1), use it for
cargo-rustflags
- Remove sccache from Docker image (not needed inside container)

**CI sccache:**
- Download pre-built binary from `vercel/sccache` GitHub releases
(~11MB)
- Cache in `~/.cache/sccache-<version>` on self-hosted runners
- Delete `scripts/build-sccache.js`, remove turbo task and package.json
entry
- `scripts/sccache-version` now contains just the release tag

<!-- NEXT_JS_LLM_PR -->
2026-04-17 17:09:11 +00:00
Zack Tanner 20e51129ff [ci]: fix backport sync script (#92942)
Fixes a few things:

- semver wasn't available because deps weren't being installed
- Fixed it to compare latest release with latest canary -- it was
erroneously marking a backport as not a backport.

Test plan:
Dry run results here:
https://github.com/vercel/next.js/actions/runs/24571828615/job/71846911677

```
should_dispatch=true
reason=Dispatching canary preminor release because stable release 16.2.4 is ahead of 16.2.1-canary.46
released_version=16.2.4
current_canary_version=16.2.1-canary.46
dispatch_input=false
auto_dispatch_enabled=true
```
2026-04-17 17:43:06 +02:00
Matt Mastracci 7c966537d7 [ci] Cache passing test results so CI retries skip them (#92832)
## What

Cache each passing test file's result in turbo's remote cache during CI runs. On retry attempts (`GITHUB_RUN_ATTEMPT > 1`), skip tests that already passed.

## Why

When `retry_test.yml` calls `rerun-failed-jobs`, the entire test shard re-runs from scratch — 20+ minutes to retry one flaky test. With this change, only the failed tests actually re-run on retry.

## How

- Cache key: `sha256(commit + test file + env fingerprint)` where env fingerprint includes `NEXT_TEST_MODE`, `IS_WEBPACK_TEST`, `IS_TURBOPACK_TEST`, etc.
- Cache value: `{"passed": true, "time": N}` (~50 bytes per test)
- On first attempt: all tests run normally, passes are cached
- On retry: cached passes are skipped, failures re-run. Newly passing tests get cached for further retries
- All caching gated on `CI` + `TURBO_TOKEN` + `GITHUB_SHA` — zero impact on local runs
- Uses existing `scripts/turbo-cache.mjs` client, all cache operations are fire-and-forget with try/catch
2026-04-16 17:39:17 -06:00
Zack Tanner a584bb8794 [ci]: add workflow to bump canary after backport (#92801)
This adds an automated path to keep canary semver-ahead after a
successful stable backport publish.

Today, a backport release can produce a stable version that is newer
than the current canary version, which creates confusing version
ordering for tooling. This change adds a follow-up workflow that
evaluates completed backport publishes and, when appropriate, triggers a
canary preminor release on canary.

The `Sync Canary After Backport Release` workflow evaluates whether a
completed `build-and-deploy` run should trigger a canary sync.

The evaluation only triggers when:
- the upstream `Potentially publish release` job succeeded
- the head commit is a stable release commit
- the published stable version is a backport relative to next@latest
- the current canary version is not already semver-ahead
- there is not already a queued or in-progress Trigger Release run on
canary

When all checks pass, the workflow dispatches trigger_release.yml on
canary with:
- releaseType=canary
- semverType=minor
- force=true

(This is currently gated behind an env flag so we can dry-run it)
2026-04-15 23:50:52 +00:00