Skip to content

docker: redeclare ARG PnpmVersion inside the build stages that use it (fixes #8210) - #8320

Merged
SamTV12345 merged 1 commit into
ether:developfrom
sqmyou:fix/8210-pnpmversion-arg-scope
Oct 11, 2026
Merged

SamTV12345 merged 1 commit into
ether:developfrom
sqmyou:fix/8210-pnpmversion-arg-scope

Conversation

@sqmyou

@sqmyou sqmyou commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #8210

What this changes

The ARG PnpmVersion default is declared before the first FROM, so Docker only resolves it in the global scope that precedes the stages. Inside adminbuild and build it expands to an empty string, which turns

npm install -g pnpm@${PnpmVersion}

into npm install -g pnpm@ — i.e. "install the latest pnpm" — so a version passed with --build-arg PnpmVersion=11.0.6 is ignored and the image still ships the newest release.

This redeclares ARG PnpmVersion inside each stage that installs pnpm, which restores the build-arg:

FROM node:24-alpine AS adminbuild
ARG PnpmVersion
...
FROM node:24-alpine AS build
ARG PnpmVersion

The default value before the first FROM is unchanged, so builds without a build-arg keep using the packageManager pin exactly as before.

What this does not change

The other half of #8210 — the pnpm ls ... --no-production spelling under pnpm 12 — was already fixed on develop and is not touched here.

I deliberately did not change the default pnpm version or the engines floor. Which pnpm the image pins is a separate decision (see the note in the issue about the minimum-release-age policy), and pinning an older build-arg now works but still has to satisfy "pnpm": ">=12.0.0" in package.json.

Testing

Dockerfile is parsed the same way the existing #7911 test already does, so no Docker daemon is needed to regress this:

  • extended src/tests/backend/specs/dockerfilePnpmPin.ts with a check that every stage running npm install -g pnpm@${PnpmVersion} also redeclares ARG PnpmVersion;
  • verified the new test fails on the pre-fix Dockerfile (reports adminbuild and build as offenders) and passes with the fix;
  • NODE_ENV=production npx mocha --import=tsx --extension ts tests/backend/specs/dockerfilePnpmPin.ts → 3 passing.

The default `ARG PnpmVersion=12.4.2` is declared before the first `FROM`, so
it only exists in the global scope that precedes the stages. Inside
`adminbuild` and `build` it expands to an empty string, which turns
`npm install -g pnpm@${PnpmVersion}` into `npm install -g pnpm@` and installs
the latest pnpm rather than the pinned one. A version passed with
`--build-arg PnpmVersion=...` is therefore ignored.

Redeclare the ARG in each stage that installs pnpm, and extend the existing
dockerfilePnpmPin test to assert that every stage running
`npm install -g pnpm@${PnpmVersion}` redeclares `ARG PnpmVersion`, so the pin
cannot silently regress.

Fixes ether#8210
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because the subscription is no longer active. Ask your workspace admin to reactivate the subscription to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix pnpm build-arg scope in Docker build stages

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Redeclare PnpmVersion in both pnpm-installing stages so Docker honors the default and build-arg
 overrides.
• Add a regression test that catches pnpm-installing stages missing the declaration.
Diagram

graph TD
  Pin["Global PnpmVersion"] --> Admin["Admin build stage"] --> AdminInstall["Pinned pnpm install"]
  Pin --> Build["Build stage"] --> BuildInstall["Pinned pnpm install"]
Loading
High-Level Assessment

Keep the global default and redeclare the ARG in each consuming stage. This directly fixes Docker's stage scoping without duplicating the version value or changing the existing pin.

Files changed (2) +31 / -0

Bug fix (1) +7 / -0
DockerfileExpose PnpmVersion inside both pnpm-installing stages +7/-0

Expose PnpmVersion inside both pnpm-installing stages

• Redeclares the global PnpmVersion ARG in 'adminbuild' and 'build', allowing each stage to use the pinned default or a '--build-arg' override. Adds a comment explaining why the stage declarations are required.

Dockerfile

Tests (1) +24 / -0
dockerfilePnpmPin.tsGuard against missing stage-local PnpmVersion declarations +24/-0

Guard against missing stage-local PnpmVersion declarations

• Adds a regression test that splits the Dockerfile into stages and checks that every stage installing 'pnpm@${PnpmVersion}' declares the ARG locally. The assertion names offending stages when the check fails.

src/tests/backend/specs/dockerfilePnpmPin.ts

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Findings visible per group, which tucks the rest behind a View link

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@SamTV12345
SamTV12345 enabled auto-merge (squash) October 11, 2026 16:23
@SamTV12345
SamTV12345 merged commit 01cb22a into ether:develop Oct 11, 2026
21 checks passed
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.

Docker: pnpm version ARG is out of stage scope; plugin builds fail with pnpm 12

2 participants