Pin wrangler to the version that actually runs on the pinned node image
All checks were successful
check / check (push) Successful in 6s
Build and Deploy to Cloudflare Pages / build (push) Successful in 7s
probe / s1-build (push) Successful in 13s
Build and Deploy to Cloudflare Pages / deploy (push) Has been skipped
probe / s2-deploy-dryrun (push) Successful in 10s
All checks were successful
check / check (push) Successful in 6s
Build and Deploy to Cloudflare Pages / build (push) Successful in 7s
probe / s1-build (push) Successful in 13s
Build and Deploy to Cloudflare Pages / deploy (push) Has been skipped
probe / s2-deploy-dryrun (push) Successful in 10s
Round 3 (07af755) cleared the artifact path and left one failure:
check / check success 8s
Build and Deploy .../ build success 8s <- green
Build and Deploy .../ deploy skipped <- if: guard
probe / r1-wrangler-only failure 7s
probe / r2a-upload-proven success 12s
probe / r2b-download-proven success 2s
probe / r3a-upload-node20 success 8s
probe / r3b-download-node20 success 2s
r2a/r2b and r3a/r3b upload and download the real site tarball across the two
job containers, so the artifact round trip is sound. r1 does nothing but
install wrangler and invoke it, and it fails.
Reproduced locally in the pinned node image, which is faster than another CI
round:
$ docker run --rm node@sha256:8f693eaa... sh -c \
'npm install -g wrangler@4.120.0; wrangler --version'
install exit=0 (with EBADENGINE warnings)
Wrangler requires at least Node.js v22.0.0. You are using v20.20.2.
version exit=1
npm treats engines as a warning on an explicit version, so the install step
would have passed and the deploy step would have failed -- a second break,
independent of the artifact one, in the same job nobody could run.
The instructive part is what the unpinned command it replaced was doing:
$ docker run --rm node@sha256:8f693eaa... sh -c \
'npm install -g wrangler; wrangler --version'
`-- wrangler@4.86.0
4.86.0
npm resolves a bare name to the newest version whose engines the running node
satisfies, so `npm install -g wrangler` on node 20 has been installing 4.86.0,
not the 4.120.0 that `latest` points at. Pinning 4.120.0 was therefore not
"pin the version we are already getting", it was an unnoticed major-ish bump
onto a node the container does not have.
So this pins wrangler 4.86.0 (engines: node >= 20.3.0, published 2026-04-28),
which is exactly the version that has been deploying this site, verified to
install and run on the pinned node 20 digest. The node image digest is left
alone. Bumping the container to node 22 to keep 4.120.0 is the alternative,
but that changes the deploy runtime for no benefit this issue asks for.
Round 4 replaces the probe jobs with a single end-to-end rehearsal: the build
job as written, then the deploy job as written with `wrangler pages deploy
--help` in place of the publish call.
This commit is contained in:
@@ -95,9 +95,19 @@ jobs:
|
||||
- name: Extract site
|
||||
run: tar -xzf site.tar.gz
|
||||
|
||||
# 4.86.0, not the 4.120.0 that `latest` points at: wrangler
|
||||
# 4.120.0 requires node >= 22 and refuses to start on this
|
||||
# container's node 20. Note that the unpinned `npm install -g
|
||||
# wrangler` this replaces was never installing `latest` either --
|
||||
# npm picks the newest version whose engines the running node
|
||||
# satisfies, which on node 20 is exactly 4.86.0. So this pins the
|
||||
# version that has actually been deploying this site, rather than
|
||||
# silently changing it. Bumping the container to node 22 is the
|
||||
# alternative; it is a bigger change and is not what this issue is
|
||||
# for.
|
||||
- name: Install Wrangler
|
||||
# wrangler 4.120.0, 2026-08-09
|
||||
run: npm install -g wrangler@4.120.0
|
||||
# wrangler 4.86.0, 2026-08-09
|
||||
run: npm install -g wrangler@4.86.0
|
||||
|
||||
- name: Deploy to Cloudflare Pages
|
||||
run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# p6 node:20-bookworm-slim + checkout success 11s
|
||||
#
|
||||
# -> the pinned alpine image, the prerequisite step and the site build are all
|
||||
# fine; upload-artifact v4 is what broke the deploy.
|
||||
# fine; upload-artifact v4 is what broke the build job on main.
|
||||
#
|
||||
# Round 2 (602fd60):
|
||||
#
|
||||
@@ -25,10 +25,27 @@
|
||||
# q3 full build + upload v3.2.2-node20 success 11s
|
||||
# q4 download v3.1.0-node20 + wrangler install failure 43s
|
||||
#
|
||||
# -> build is green, every v3 upload works, and the remaining failure is
|
||||
# somewhere in the deploy-side rehearsal. Round 3 splits q4 into its parts:
|
||||
# wrangler on its own, the artifact pair that was actually deploying this
|
||||
# site before this issue, and the newer node20 artifact pair.
|
||||
# -> build green on every v3 upload; a second, separate failure on the deploy
|
||||
# side.
|
||||
#
|
||||
# Round 3 (07af755):
|
||||
#
|
||||
# build (deploy.yml, upload v3.2.1) success 8s
|
||||
# r1 wrangler install + invoke, no artifacts failure 7s
|
||||
# r2a/r2b artifact round trip, v3.2.1/v3.0.2 success 12s / 2s
|
||||
# r3a/r3b artifact round trip, node20 builds success 8s / 2s
|
||||
#
|
||||
# -> the artifact round trip is sound in both pairs; wrangler is the second
|
||||
# break. Reproduced locally in the pinned node image: `npm install -g
|
||||
# wrangler@4.120.0` exits 0 with EBADENGINE warnings, then wrangler itself
|
||||
# exits 1 with "Wrangler requires at least Node.js v22.0.0. You are using
|
||||
# v20.20.2." Unpinned `npm install -g wrangler` on that same image resolves
|
||||
# to 4.86.0, because npm picks the newest version the running node
|
||||
# satisfies -- so 4.86.0 is what has actually been deploying this site, and
|
||||
# that is what deploy.yml now pins.
|
||||
#
|
||||
# Round 4 is the full rehearsal of both jobs end to end with the corrected
|
||||
# pins, stopping one step short of publishing.
|
||||
name: probe
|
||||
|
||||
on:
|
||||
@@ -37,24 +54,8 @@ on:
|
||||
- pin-deploy-refs-observable
|
||||
|
||||
jobs:
|
||||
# Isolates the wrangler install and invocation from anything to do with
|
||||
# artifacts. wrangler 4.120.0 declares engines.node >= 22 while the deploy
|
||||
# container is node 20, so this needs measuring rather than assuming --
|
||||
# the pre-issue deploy did run an unpinned wrangler on node:20
|
||||
# successfully.
|
||||
r1-wrangler-only:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# node 20.20.2-bookworm, 2026-08-09
|
||||
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
|
||||
steps:
|
||||
# wrangler 4.120.0, 2026-08-09
|
||||
- run: npm install -g wrangler@4.120.0
|
||||
- run: wrangler --version
|
||||
|
||||
# Producer for the pair that `@v3`/`@v3` resolved to before this issue,
|
||||
# i.e. the code that was actually deploying the site, now pinned.
|
||||
r2a-upload-proven:
|
||||
# Producer: identical to the build job in deploy.yml.
|
||||
s1-build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# alpine 3.21, 2026-02-28
|
||||
@@ -74,15 +75,17 @@ jobs:
|
||||
# actions/upload-artifact v3.2.1, 2026-08-09
|
||||
- uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
|
||||
with:
|
||||
name: site-proven
|
||||
name: site-dry
|
||||
path: site.tar.gz
|
||||
|
||||
# Consumer half: the deploy job's artifact handling, with no wrangler, so
|
||||
# a failure here means the artifact round trip and a pass here means it is
|
||||
# sound.
|
||||
r2b-download-proven:
|
||||
# Consumer: identical to the deploy job in deploy.yml, except that the
|
||||
# final step prints wrangler's view of the project instead of running
|
||||
# `wrangler pages deploy`. Same pinned image, same pinned action, same
|
||||
# pinned wrangler version, same extracted tree. Needs no token and
|
||||
# publishes nothing.
|
||||
s2-deploy-dryrun:
|
||||
runs-on: ubuntu-latest
|
||||
needs: r2a-upload-proven
|
||||
needs: s1-build
|
||||
container:
|
||||
# node 20.20.2-bookworm, 2026-08-09
|
||||
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
|
||||
@@ -90,40 +93,10 @@ jobs:
|
||||
# actions/download-artifact v3.0.2, 2026-08-09
|
||||
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
|
||||
with:
|
||||
name: site-proven
|
||||
name: site-dry
|
||||
- run: tar -xzf site.tar.gz
|
||||
- run: test -f public/index.html
|
||||
|
||||
# The newer node20 artifact pair, kept in the round so the choice between
|
||||
# the two pairs rests on measurement rather than preference.
|
||||
r3a-upload-node20:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# alpine 3.21, 2026-02-28
|
||||
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
|
||||
defaults:
|
||||
run:
|
||||
shell: sh
|
||||
steps:
|
||||
- run: apk add --no-cache nodejs git tar
|
||||
# actions/checkout v4.2.2, 2026-02-28
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||
- run: tar -czf alt.tar.gz hugo.toml
|
||||
# actions/upload-artifact v3.2.2-node20, 2026-08-09
|
||||
- uses: actions/upload-artifact@c6a3b2bd78b3985e4b2f15397fec357f0fd808de
|
||||
with:
|
||||
name: alt-node20
|
||||
path: alt.tar.gz
|
||||
|
||||
r3b-download-node20:
|
||||
runs-on: ubuntu-latest
|
||||
needs: r3a-upload-node20
|
||||
container:
|
||||
# node 20.20.2-bookworm, 2026-08-09
|
||||
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
|
||||
steps:
|
||||
# actions/download-artifact v3.1.0-node20, 2026-08-09
|
||||
- uses: actions/download-artifact@ad191675b41f6a5b46da9a048cb6893812da158b
|
||||
with:
|
||||
name: alt-node20
|
||||
- run: test -f alt.tar.gz
|
||||
# wrangler 4.86.0, 2026-08-09
|
||||
- run: npm install -g wrangler@4.86.0
|
||||
- run: wrangler --version
|
||||
- run: wrangler pages deploy --help
|
||||
|
||||
Reference in New Issue
Block a user