Skip to content

Commit 91a87cb

Browse files
authored
ci: do not block PRs on broken Next.js canary publishes (#16408)
When Vercel publishes `next@<canary>` to npm but its peer packages (`@next/env`, `@next/eslint-plugin-next`) are missing for the same version, `pnpm create next-app@canary` fails with `ERR_PNPM_NO_MATCHING_VERSION`, which used to fail every `int-* (1/3)` shard on every PR for reasons unrelated to the PR. A new `probe-next-canary` job checks the registry up front: - If the canary is incomplete, `tests-int` skips the `Canary` variants in `test/create-payload-app/int.spec.ts` via Vitest's `-t` filter (`^(?!.*Canary).*$`). The latest variants still run and remain strict. - A new `notify-next-canary-broken` job posts a sticky PR comment via `marocchino/sticky-pull-request-comment` explaining the upstream issue, making clear it does not block the PR, and asking the author to open an issue at vercel/next.js. The comment is removed automatically once a healthy canary lands on npm. The job is intentionally not part of `all-green` so an upstream Next.js breakage cannot block a Payload PR. Implementation is YAML-only; the test file is unchanged. <!-- Thank you for the PR! Please go through the checklist below and make sure you've completed all the steps. Please review the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository if you haven't already. ## Which branch should this PR target? - **`main`** — Payload v4 development. New features, enhancements, and v4 bug fixes go here. - **`3.x`** — Payload v3 maintenance. Bug fixes only. **New features are not accepted against v3.** If this PR adds a feature to v3, please retarget it at `main` (v4) instead. The following items will ensure that your PR is handled as smoothly as possible: - PR Title must follow conventional commits format. For example, `feat: my new feature`, `fix(plugin-seo): my fix`. - Minimal description explained as if explained to someone not immediately familiar with the code. - Provide before/after screenshots or code diffs if applicable. - Link any related issues/discussions from GitHub or Discord. - Add review comments if necessary to explain to the reviewer the logic behind a change ### What? ### Why? ### How? Fixes # --> --------- Co-authored-by: German Jablonski <GermanJablo@users.noreply.github.com>
1 parent af250cf commit 91a87cb

2 files changed

Lines changed: 140 additions & 2 deletions

File tree

.github/workflows/main.yml

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,53 @@ jobs:
5656
echo "needs_tests: ${{ steps.filter.outputs.needs_tests }}"
5757
echo "templates: ${{ steps.filter.outputs.templates }}"
5858
59+
# Detects upstream Next.js canary publishes that are missing `@next/env` or
60+
# `@next/eslint-plugin-next` for the same version (would break
61+
# `pnpm create next-app@canary` with `ERR_PNPM_NO_MATCHING_VERSION`).
62+
probe-next-canary:
63+
name: probe-next-canary
64+
runs-on: ubuntu-24.04
65+
needs: changes
66+
if: needs.changes.outputs.needs_tests == 'true'
67+
outputs:
68+
healthy: ${{ steps.probe.outputs.healthy }}
69+
next_version: ${{ steps.probe.outputs.next_version }}
70+
steps:
71+
- name: Probe registry for complete canary publish
72+
id: probe
73+
run: |
74+
retry_npm_view() {
75+
local spec="$1"
76+
for attempt in 1 2 3; do
77+
if npm view "$spec" version >/dev/null 2>&1; then
78+
return 0
79+
fi
80+
sleep $((attempt * 2))
81+
done
82+
return 1
83+
}
84+
85+
NEXT_VERSION=""
86+
for attempt in 1 2 3; do
87+
NEXT_VERSION="$(npm view next@canary version 2>/dev/null || true)"
88+
if [ -n "$NEXT_VERSION" ]; then
89+
break
90+
fi
91+
sleep $((attempt * 2))
92+
done
93+
echo "Resolved next@canary version: ${NEXT_VERSION:-<empty>}"
94+
echo "next_version=${NEXT_VERSION}" >> "$GITHUB_OUTPUT"
95+
if [ -z "$NEXT_VERSION" ]; then
96+
echo "healthy=unknown" >> "$GITHUB_OUTPUT"
97+
exit 0
98+
fi
99+
if retry_npm_view "@next/env@${NEXT_VERSION}" \
100+
&& retry_npm_view "@next/eslint-plugin-next@${NEXT_VERSION}"; then
101+
echo "healthy=true" >> "$GITHUB_OUTPUT"
102+
else
103+
echo "healthy=false" >> "$GITHUB_OUTPUT"
104+
fi
105+
59106
lint:
60107
runs-on: ubuntu-24.04
61108
steps:
@@ -152,7 +199,7 @@ jobs:
152199
153200
tests-int:
154201
runs-on: ubuntu-24.04
155-
needs: [changes, build, int-matrix]
202+
needs: [changes, build, int-matrix, probe-next-canary]
156203
if: needs.changes.outputs.needs_tests == 'true'
157204
name: int-${{ matrix.database }}${{ matrix.total-shards > 1 && format(' ({0}/{1})', matrix.shard, matrix.total-shards) || '' }}
158205
timeout-minutes: 45
@@ -193,13 +240,19 @@ jobs:
193240
database: ${{ matrix.database }}
194241

195242
- name: Integration Tests
196-
run: pnpm test:int --shard=${{ matrix.shard }}/${{ matrix.total-shards }}
197243
env:
198244
NODE_OPTIONS: --max-old-space-size=8096
199245
PAYLOAD_DATABASE: ${{ matrix.database }}
200246
POSTGRES_URL: ${{ steps.db.outputs.POSTGRES_URL }}
201247
MONGODB_URL: ${{ steps.db.outputs.MONGODB_URL }}
202248
MONGODB_ATLAS_URL: ${{ steps.db.outputs.MONGODB_ATLAS_URL }}
249+
run: |
250+
if [ "${{ needs.probe-next-canary.outputs.healthy }}" = "false" ]; then
251+
echo "::warning::Next.js canary publish is incomplete on npm (next@${{ needs.probe-next-canary.outputs.next_version }}); skipping Canary tests for this run."
252+
pnpm test:int --shard=${{ matrix.shard }}/${{ matrix.total-shards }} -t '^(?!.*Canary).*$'
253+
else
254+
pnpm test:int --shard=${{ matrix.shard }}/${{ matrix.total-shards }}
255+
fi
203256
204257
# Generate the E2E test matrix from TypeScript config
205258
e2e-matrix:
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
name: notify-next-canary
2+
3+
# Runs on `pull_request_target` so the sticky comment also works on PRs from
4+
# forks (regular `pull_request` workflows have a read-only GITHUB_TOKEN on
5+
# fork PRs and cannot post comments). This is safe because the probe only
6+
# calls `npm view` and never checks out or executes PR code.
7+
on:
8+
pull_request_target:
9+
types: [opened, reopened, synchronize]
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
# Detects upstream Next.js canary publishes that are missing `@next/env` or
17+
# `@next/eslint-plugin-next` for the same version (would break
18+
# `pnpm create next-app@canary` with `ERR_PNPM_NO_MATCHING_VERSION`).
19+
probe:
20+
runs-on: ubuntu-24.04
21+
outputs:
22+
healthy: ${{ steps.probe.outputs.healthy }}
23+
next_version: ${{ steps.probe.outputs.next_version }}
24+
steps:
25+
- name: Probe registry for complete canary publish
26+
id: probe
27+
run: |
28+
retry_npm_view() {
29+
local spec="$1"
30+
for attempt in 1 2 3; do
31+
if npm view "$spec" version >/dev/null 2>&1; then
32+
return 0
33+
fi
34+
sleep $((attempt * 2))
35+
done
36+
return 1
37+
}
38+
39+
NEXT_VERSION=""
40+
for attempt in 1 2 3; do
41+
NEXT_VERSION="$(npm view next@canary version 2>/dev/null || true)"
42+
if [ -n "$NEXT_VERSION" ]; then
43+
break
44+
fi
45+
sleep $((attempt * 2))
46+
done
47+
echo "Resolved next@canary version: ${NEXT_VERSION:-<empty>}"
48+
echo "next_version=${NEXT_VERSION}" >> "$GITHUB_OUTPUT"
49+
if [ -z "$NEXT_VERSION" ]; then
50+
echo "healthy=unknown" >> "$GITHUB_OUTPUT"
51+
exit 0
52+
fi
53+
if retry_npm_view "@next/env@${NEXT_VERSION}" \
54+
&& retry_npm_view "@next/eslint-plugin-next@${NEXT_VERSION}"; then
55+
echo "healthy=true" >> "$GITHUB_OUTPUT"
56+
else
57+
echo "healthy=false" >> "$GITHUB_OUTPUT"
58+
fi
59+
60+
notify:
61+
runs-on: ubuntu-24.04
62+
needs: probe
63+
permissions:
64+
pull-requests: write
65+
steps:
66+
- name: Post sticky PR comment about Next.js canary breakage
67+
if: needs.probe.outputs.healthy == 'false'
68+
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
69+
with:
70+
header: next-canary-broken
71+
message: |
72+
## Heads-up: Next.js canary publish is incomplete on npm
73+
74+
CI detected that the current `next@canary` (`${{ needs.probe.outputs.next_version }}`) is missing one of its peer packages (`@next/env` or `@next/eslint-plugin-next`) for the same version on the npm registry, so `pnpm create next-app@canary` would fail with `ERR_PNPM_NO_MATCHING_VERSION`. This is unrelated to this PR.
75+
76+
**This will not block your PR.** The `Canary` variants of `test/create-payload-app/int.spec.ts` are being skipped for this run via Vitest's `-t` filter; the rest of the suite still runs normally and this comment is purely informational.
77+
78+
Please open an issue in [vercel/next.js](https://github.com/vercel/next.js/issues/new/choose) as soon as possible so the upstream team can republish a complete canary, then re-run CI on this PR once a new canary is out to confirm the fix.
79+
80+
- name: Remove sticky PR comment when canary is healthy again
81+
if: needs.probe.outputs.healthy == 'true'
82+
uses: marocchino/sticky-pull-request-comment@773744901bac0e8cbb5a0dc842800d45e9b2b405 # v2.9.4
83+
with:
84+
header: next-canary-broken
85+
delete: true

0 commit comments

Comments
 (0)