Skip to content

Updated pnpm to 11.4.0#28197

Merged
9larsons merged 3 commits into
mainfrom
upgrade/pnpm-11
May 27, 2026
Merged

Updated pnpm to 11.4.0#28197
9larsons merged 3 commits into
mainfrom
upgrade/pnpm-11

Conversation

@9larsons
Copy link
Copy Markdown
Contributor

@9larsons 9larsons commented May 27, 2026

no ref

Updating pnpm 10.33>11.4.0:

  • Stops reading the pnpm field from package.json. overrides, packageExtensions, and onlyBuiltDependencies (renamed to allowBuilds) now live in pnpm-workspace.yaml.
  • Stops reading non-auth/registry keys from .npmrc.
  • Replaces the millions of index/*.json files in the store with a single SQLite index.db (v11 store format) — faster lookups, fewer syscalls.
  • New supply-chain defaults: minimumReleaseAge: 1440 (1 day) and blockExoticSubdeps: true.

Node version requirement is unchanged for us (already on 22.18.0).

What changed

  • Moved the pnpm: {…} block out of package.json into pnpm-workspace.yaml.
  • onlyBuiltDependencies (array) → allowBuilds (map of name → true).
  • Declared minimumReleaseAge: 4320 (3 days, matches our Renovate cadence) and blockExoticSubdeps: true explicitly, even though the latter is now the default — keeps the supply-chain stance visible in the config rather than implicit.
  • Added an override redirecting perf-primitives to the npm-published ^0.0.6. liquid-wormhole@3.0.1 (transitive in ghost/admin) pins perf-primitives via a personal-fork git URL, which blockExoticSubdeps (correctly) refuses; the override routes us to the upstream-maintained package at the same version.
  • Deleted .npmrc — both entries (shamefully-hoist=false, engine-strict=false) were pnpm 11 defaults that are no longer honored in .npmrc anyway.
  • Regenerated pnpm-lock.yaml against the new policies under pnpm 11's v11 store.

Verification

  • pnpm install clean under pnpm 11.4.0.
  • pnpm test:unit in ghost/core: 6600 pass, 10 skip, 0 fail.
  • pnpm nx run @tryghost/admin:build (Ember + 8 dependent Vite app builds): success.

Notes for reviewers

  • The biggest behavioral change is the perf-primitives override — ghost/admin previously shipped a personal-fork git ref of this package; it now resolves to the upstream npm release at v0.0.6. The admin build is green; if anything regresses around liquid-wormhole transitions, that's the first place to look.
  • CI's pnpm cache and the Docker pnpm-store mount will cold-fill the v11 store on the first run after merge, then settle.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR upgrades pnpm from version 10.33.0 to 11.4.0 and restructures dependency management configuration. The package manager version is bumped in package.json and related configuration is migrated into pnpm-workspace.yaml, which now includes supply-chain hardening policies (minimumReleaseAge, blockExoticSubdeps, allowBuilds allowlist), extensive dependency overrides with version constraints, and packageExtensions to augment specific package dependencies. GitHub Actions workflows across CI and release jobs are updated to use pnpm/action-setup v6.0.8 instead of v4. The .npmrc file had two configuration entries removed.

Possibly related PRs

  • TryGhost/Ghost#27886: Modifies pnpm workspace configuration and adds catalog-based workspace entries that interact with workspace-level pnpm rules.
  • TryGhost/Ghost#27969: Updates pnpm packageExtensions for specific packages (e.g., @tryghost/nql, lodash), touching the same pnpm workspace mechanisms for dependency installation.

Suggested reviewers

  • EvanHahn
  • troyciesco
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Updated pnpm to 11.4.0' directly and clearly reflects the main change: upgrading the pnpm package manager version from 10.33.0 to 11.4.0, which is the primary objective of this pull request.
Description check ✅ Passed The description comprehensively covers all aspects of the changeset including configuration migrations, supply-chain policies, dependency overrides, and verification steps, with clear notes for reviewers about behavioral changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch upgrade/pnpm-11

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@9larsons 9larsons enabled auto-merge (squash) May 27, 2026 15:03
@9larsons 9larsons force-pushed the upgrade/pnpm-11 branch 2 times, most recently from 5939993 to 8939d41 Compare May 27, 2026 15:58
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/enforce-package-manager.js:
- Around line 7-14: The comment overstates certainty about pnpm-specific env
vars; update the explanatory comment above the fallback that checks
Object.keys(process.env).some(key => key.startsWith('pnpm_config_')) to use
softer wording—e.g., "pnpm-driven lifecycles typically set `pnpm_config_*`, so
we use this as a heuristic"—and remove or generalize the specific pnpm v10/v11
GitHub Actions shim claim so the note accurately reflects it as a heuristic
rather than an absolute guarantee.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b162616f-5e44-4201-82f5-2e958a82530e

📥 Commits

Reviewing files that changed from the base of the PR and between 8939d41 and dbc39e5.

📒 Files selected for processing (1)
  • .github/scripts/enforce-package-manager.js

Comment on lines +7 to +14
// Fallback for environments where pnpm 11 doesn't propagate
// npm_config_user_agent to lifecycle scripts — observed on GitHub Actions
// where the runner's pre-installed pnpm v10 shim layer strips the var even
// when pnpm 11 is the active binary. The `pnpm_config_*` env-var prefix is
// exclusive to pnpm and reliably set when pnpm 11 spawns a child process.
if (Object.keys(process.env).some(key => key.startsWith('pnpm_config_'))) {
process.exit(0);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that pnpm sets pnpm_config_* environment variables in lifecycle scripts

# Create a minimal test package.json with a script that prints pnpm_config_* vars
mkdir -p /tmp/pnpm-env-test
cd /tmp/pnpm-env-test

cat > package.json << 'EOF'
{
  "name": "pnpm-env-test",
  "version": "1.0.0",
  "scripts": {
    "test": "node -e \"Object.keys(process.env).filter(k => k.startsWith('pnpm_config_')).forEach(k => console.log(k + '=' + process.env[k]))\""
  }
}
EOF

echo "=== Testing pnpm ==="
pnpm run test 2>/dev/null || echo "No pnpm_config_* variables found or pnpm not available"

# Clean up
cd - > /dev/null
rm -rf /tmp/pnpm-env-test

Repository: TryGhost/Ghost

Length of output: 173


🌐 Web query:

Does pnpm set environment variables with the pnpm_config_ prefix during lifecycle scripts?

💡 Result:

No, as of pnpm v11, pnpm does not set environment variables with the pnpm_config_ prefix during lifecycle scripts [1][2]. Historically, pnpm would populate npm_config_* environment variables with pnpm configuration values during lifecycle script execution [2]. However, this behavior was changed to reduce noise and avoid warnings when lifecycle scripts invoke npm internally [2]. Since pnpm v11, only well-known npm_* environment variables are set (such as npm_lifecycle_event, npm_package_name, and npm_package_version), aligning pnpm's behavior with Yarn [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

tmpdir="$(mktemp -d)"
cleanup() { rm -rf "$tmpdir"; }
trap cleanup EXIT

cd "$tmpdir"

cat > package.json <<'EOF'
{
  "name": "env-test",
  "version": "1.0.0",
  "scripts": {
    "print": "node -e \"const p=Object.keys(process.env).filter(k=>k.startsWith('pnpm_config_')).sort(); console.log('pnpm_config_keys=' + (p.length?p.join(','):'')); p.forEach(k=>console.log(k+'='+process.env[k])); const n=Object.keys(process.env).filter(k=>k.startsWith('npm_config_')).sort(); console.log('npm_config_keys=' + (n.length?n.join(','):''));\""
  }
}
EOF

echo "=== pnpm ==="
if command -v pnpm >/dev/null 2>&1; then
  pnpm -v
  pnpm run print || true
else
  echo "pnpm not found"
fi

echo "=== npm ==="
if command -v npm >/dev/null 2>&1; then
  npm -v
  npm run print || true
else
  echo "npm not found"
fi

echo "=== yarn ==="
if command -v yarn >/dev/null 2>&1; then
  yarn -v
  yarn run print || true
else
  echo "yarn not found"
fi

echo "=== bun ==="
if command -v bun >/dev/null 2>&1; then
  bun -v
  bun run print || true
else
  echo "bun not found"
fi

Repository: TryGhost/Ghost

Length of output: 2177


Soften the “exclusive/reliably set” wording for the pnpm_config_* fallback

  • In lifecycle scripts, pnpm provides pnpm_config_* (e.g., pnpm_config_verify_deps_before_run), while npm and yarn did not set any pnpm_config_* keys—so the fallback won’t be bypassed by npm/yarn.
  • The explanatory comment’s “exclusive to pnpm” and the specific GitHub Actions “pnpm v10 shim strips … when pnpm 11 is active” scenario are stronger than the evidence shown here; consider rephrasing to a heuristic (pnpm-driven lifecycles typically set pnpm_config_*) or removing the v10/11 shim specifics.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/enforce-package-manager.js around lines 7 - 14, The comment
overstates certainty about pnpm-specific env vars; update the explanatory
comment above the fallback that checks Object.keys(process.env).some(key =>
key.startsWith('pnpm_config_')) to use softer wording—e.g., "pnpm-driven
lifecycles typically set `pnpm_config_*`, so we use this as a heuristic"—and
remove or generalize the specific pnpm v10/v11 GitHub Actions shim claim so the
note accurately reflects it as a heuristic rather than an absolute guarantee.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.88%. Comparing base (e2322f8) to head (3c3582b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #28197   +/-   ##
=======================================
  Coverage   73.88%   73.88%           
=======================================
  Files        1531     1531           
  Lines      129865   129865           
  Branches    15582    15585    +3     
=======================================
+ Hits        95954    95956    +2     
+ Misses      32949    32946    -3     
- Partials      962      963    +1     
Flag Coverage Δ
admin-tests 54.17% <ø> (-0.03%) ⬇️
e2e-tests 73.88% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

9larsons added 3 commits May 27, 2026 11:27
- pnpm 11 stops reading the `pnpm` field from package.json, so `overrides`,
  `packageExtensions`, and `onlyBuiltDependencies` move to pnpm-workspace.yaml.
  `onlyBuiltDependencies` is renamed to `allowBuilds` (map form).
- Declared `minimumReleaseAge: 1440` (1 day, pnpm 11 default) and
  `blockExoticSubdeps: true` explicitly in pnpm-workspace.yaml. The 1-day
  floor matches what Renovate currently enforces in practice for regular
  updates (renovate.json5 only applies its 3-day soak inside
  `vulnerabilityAlerts`); aligning both to 3 days is tracked as a follow-up.
- Added an override redirecting `perf-primitives` to the npm-published
  `^0.0.6`. liquid-wormhole@3.0.1 pins it via a personal-fork git URL, which
  blockExoticSubdeps (correctly) refuses; the override resolves to the
  upstream-maintained package at the same version.
- `.npmrc` deleted: its only entries were pnpm 11 defaults that are no longer
  honored in .npmrc anyway.
- Lockfile regenerated against the new policies under pnpm 11's v11 store.

CI's pnpm cache and the Docker `pnpm-store` mount will cold-fill the v11
store on the first run after merge, then settle.
v4 predates pnpm 11; v6 (April) was the first release with pnpm 11
support. Under v4, pnpm 11 wasn't propagating `npm_config_user_agent`
to lifecycle scripts in CI, which broke our preinstall guard
(`.github/scripts/enforce-package-manager.js`) until the action was
bumped.

v6.0.0 also moved the action to Node 24 internally; this only affects
the action's own runtime, not the Node version used for `pnpm install`
(still controlled by actions/setup-node + NODE_VERSION).
The GitHub Actions Ubuntu runner pre-installs pnpm v10 at
/home/runner/setup-pnpm/node_modules/.bin/. When pnpm/action-setup v6
installs pnpm 11 over it, the v10-style shim layer ends up stripping
`npm_config_user_agent` from child processes — so our preinstall guard
sees an empty user-agent string and exits 1 with "Detected package
manager: unknown", even though pnpm 11 is in fact the active binary.

Added a fallback that checks for any `pnpm_config_*` env var, a prefix
exclusive to pnpm and reliably set when pnpm 11 spawns child processes
regardless of how it was invoked. Original user-agent check still runs
first, so pnpm 10 and older behavior is unchanged.

This is a defence-in-depth pair with the pnpm/action-setup bump — the
action bump is the correct action for our pnpm version; the script
fallback covers the runner-layout case neither side fully resolves.
@9larsons 9larsons merged commit b5852fd into main May 27, 2026
41 of 42 checks passed
@9larsons 9larsons deleted the upgrade/pnpm-11 branch May 27, 2026 16:43
9larsons added a commit that referenced this pull request May 27, 2026
The pnpm 11 upgrade in #28197 deleted the root .npmrc, but two Dockerfiles
still list it in their COPY directives:

- Dockerfile.production (production image builds)
- docker/ghost-dev/Dockerfile (devcontainer + local dev)

Docker COPY fails when an explicitly-named source file doesn't exist,
breaking the devcontainer image build on main and any subsequent prod
build. I scanned both files for `.npmrc` references during the pnpm 11
PR but failed to update the COPY lines when the file itself was removed.

Also re-applies the comment softening from the PR review on
.github/scripts/enforce-package-manager.js — that change was reviewed
and approved on #28197 but never made it into a commit before the rebase
autostash on my end.
9larsons added a commit that referenced this pull request May 27, 2026
The pnpm 11 upgrade in #28197 deleted the root .npmrc, but several
release-pipeline pieces still referenced it:

1. Dockerfile.production and docker/ghost-dev/Dockerfile listed .npmrc
   in their COPY directives — Docker fails when a named source is
   missing, breaking the devcontainer image build on main.
2. ghost/core/scripts/pack.js read root .npmrc to build the published
   Ghost tarball — would throw on the first release after merge.

Also surfaced two latent pack.js issues in the process:

- pnpm 11 strict-validates `catalog:` refs in workspace package.jsons.
  `pnpm pack` on @tryghost/i18n (etc.) needs pnpm-workspace.yaml in
  scope; pack.js wrote it AFTER the pack loop. Reordered to write it
  before.
- The overrides merge into the packaged package.json read from root
  package.json's `pnpm.overrides`, which is empty under pnpm 11
  (overrides moved to pnpm-workspace.yaml). Updated to read from
  workspace.yaml with the legacy path as fallback.

Verified end-to-end: pack succeeds, tarball builds cleanly via
Dockerfile.production. No .npmrc is produced or required — the only
thing it carried for the published package was `frozen-lockfile=false`,
which pnpm 11 ignores in .npmrc anyway.

Also re-applies the comment softening from the #28197 review of
.github/scripts/enforce-package-manager.js — that change was reviewed
and agreed on the PR but never made it into a commit before the rebase
autostash on my end.
9larsons added a commit that referenced this pull request May 27, 2026
The pnpm 11 upgrade in #28197 deleted the root .npmrc, but several
release-pipeline pieces still referenced it:

1. Dockerfile.production and docker/ghost-dev/Dockerfile listed .npmrc
   in their COPY directives — Docker fails when a named source is
   missing, breaking the devcontainer image build on main.
2. ghost/core/scripts/pack.js read root .npmrc to build the published
   Ghost tarball — would throw on the first release after merge.

Also surfaced two latent pack.js issues in the process:

- pnpm 11 strict-validates `catalog:` refs in workspace package.jsons.
  `pnpm pack` on @tryghost/i18n (etc.) needs pnpm-workspace.yaml in
  scope; pack.js wrote it AFTER the pack loop. Reordered to write it
  before.
- The overrides merge into the packaged package.json read from root
  package.json's `pnpm.overrides`, which is empty under pnpm 11
  (overrides moved to pnpm-workspace.yaml). Updated to read from
  workspace.yaml with the legacy path as fallback.

Verified end-to-end: pack succeeds, tarball builds cleanly via
Dockerfile.production. No .npmrc is produced or required — the only
thing it carried for the published package was `frozen-lockfile=false`,
which pnpm 11 ignores in .npmrc anyway.

Also re-applies the comment softening from the #28197 review of
.github/scripts/enforce-package-manager.js — that change was reviewed
and agreed on the PR but never made it into a commit before the rebase
autostash on my end.
9larsons added a commit that referenced this pull request May 27, 2026
The pnpm 11 upgrade in #28197 deleted the root .npmrc, which removed
both a file reference (broke Docker COPY) and the `frozen-lockfile=false`
directive that had been silently absorbing several lockfile/workspace
mismatches in published-tarball installs (pnpm 11 ignores .npmrc keys
other than auth/registry, so it couldn't carry the directive anyway).

Five distinct issues across the release pipeline:

1. `Dockerfile.production` and `docker/ghost-dev/Dockerfile` listed
   .npmrc in their COPY directives. Docker fails on missing sources —
   devcontainer image build went red on first push to main.

2. `pack.js` read root .npmrc to build the published tarball. Would
   throw on the next `pnpm archive` / release.

3. pnpm 11 strict-validates `catalog:` refs in workspace package.jsons,
   so `pnpm pack` of @tryghost/i18n etc. needs pnpm-workspace.yaml in
   scope. pack.js wrote it AFTER the pack loop. Reordered to write it
   first.

4. The packaged pnpm-workspace.yaml shipped overrides + packageExtensions
   verbatim from root, but `pnpm deploy` generates a lockfile that
   doesn't record them (they're already applied to the resolved
   package.json). pnpm 11's frozen-lockfile install (CI=true default for
   ghost-cli) compares config to lockfile as raw strings and fails
   ERR_PNPM_LOCKFILE_CONFIG_MISMATCH. Solution: pack.js writes a
   trimmed workspace.yaml carrying only catalog/catalogs/allowBuilds/
   strictDepBuilds — the things end-user installs actually need.

5. After pack.js's package.json post-processing (strip peer suffixes,
   rewrite file: refs to component tarballs), the deploy lockfile no
   longer matched. Under pnpm 10 this was masked by frozen-lockfile=false
   in the shipped .npmrc. Solution: pack.js regenerates the lockfile
   inside the deploy dir with `pnpm install --lockfile-only` so the
   shipped tarball is internally consistent.

Also re-applies the comment softening from the #28197 review of
.github/scripts/enforce-package-manager.js (was lost to a rebase
autostash on my end before merge).
9larsons added a commit that referenced this pull request May 27, 2026
The pnpm 11 upgrade in #28197 deleted the root .npmrc, which removed
both a file reference (broke Docker COPY) and the `frozen-lockfile=false`
directive that had been silently absorbing several lockfile/workspace
mismatches in published-tarball installs (pnpm 11 ignores .npmrc keys
other than auth/registry, so it couldn't carry the directive anyway).

Five distinct issues across the release pipeline:

1. `Dockerfile.production` and `docker/ghost-dev/Dockerfile` listed
   .npmrc in their COPY directives. Docker fails on missing sources —
   devcontainer image build went red on first push to main.

2. `pack.js` read root .npmrc to build the published tarball. Would
   throw on the next `pnpm archive` / release.

3. pnpm 11 strict-validates `catalog:` refs in workspace package.jsons,
   so `pnpm pack` of @tryghost/i18n etc. needs pnpm-workspace.yaml in
   scope. pack.js wrote it AFTER the pack loop. Reordered to write it
   first.

4. The packaged pnpm-workspace.yaml shipped overrides + packageExtensions
   verbatim from root, but `pnpm deploy` generates a lockfile that
   doesn't record them (they're already applied to the resolved
   package.json). pnpm 11's frozen-lockfile install (CI=true default for
   ghost-cli) compares config to lockfile as raw strings and fails
   ERR_PNPM_LOCKFILE_CONFIG_MISMATCH. Solution: pack.js writes a
   trimmed workspace.yaml carrying only catalog/catalogs/allowBuilds/
   strictDepBuilds — the things end-user installs actually need.

5. After pack.js's package.json post-processing (strip peer suffixes,
   rewrite file: refs to component tarballs), the deploy lockfile no
   longer matched. Under pnpm 10 this was masked by frozen-lockfile=false
   in the shipped .npmrc. Solution: pack.js regenerates the lockfile
   inside the deploy dir with `pnpm install --lockfile-only` so the
   shipped tarball is internally consistent.

Also re-applies the comment softening from the #28197 review of
.github/scripts/enforce-package-manager.js (was lost to a rebase
autostash on my end before merge).
9larsons added a commit that referenced this pull request May 27, 2026
ref #28197

Five distinct release-pipeline files broke after the
`.npmrc` deletion, but the deeper story is that `.npmrc` was also
carrying `frozen-lockfile=false`, which was silently absorbing several
pnpm-deploy-vs-lockfile mismatches under pnpm 10. pnpm 11 ignores
`.npmrc` for that directive, so the mismatches surface.

## What was broken

- `Dockerfile.production:28` — production image builds. `COPY` fails on
missing source.
- `docker/ghost-dev/Dockerfile:21` — devcontainer + local dev. Already
failed on main: [run
26525156893](https://github.com/TryGhost/Ghost/actions/runs/26525156893).
- `ghost/core/scripts/pack.js:124` — read root `.npmrc` to build the
published Ghost tarball; would throw on next release.
- `pack.js` — `pnpm pack` of `@tryghost/i18n`/etc. needs
`pnpm-workspace.yaml` in scope (pnpm 11 strict-validates `catalog:`
refs); pack.js wrote it AFTER the pack loop.
- `pack.js` — the shipped tarball's `pnpm-workspace.yaml` carried
`overrides` + `packageExtensions` verbatim from root, but `pnpm
deploy`'s generated lockfile doesn't record them (they're already
applied to the resolved package.json). pnpm 11's frozen-lockfile install
(CI=true default for ghost-cli) failed
`ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`.
- `pack.js` — after the existing peer-suffix-stripping and
component-file: rewriting on the deployed package.json, the deploy
lockfile no longer matched. Under pnpm 10 this was masked by
`frozen-lockfile=false` in `.npmrc`; pnpm 11 fails
`ERR_PNPM_OUTDATED_LOCKFILE`.
- `pack.js` — `minimumReleaseAge` policy in the shipped workspace.yaml
404'd on the private component tarballs and failed install inside
`Dockerfile.production`.
9larsons added a commit that referenced this pull request May 27, 2026
ref #28197

`job_build_artifacts` is missing from `job_required_tests.needs`, so
when it fails the gate doesn't see it. Its downstream jobs
(`job_ghost-cli`, `job_build_e2e_image`, `job_e2e_tests`) cascade into
"skipped" via their own `needs:` / `if:` checks, and the gate's
`contains(needs.*.result, 'failure')` check sees only success/skipped —
green merge despite a real release-pipeline failure.

Surfaced concretely in #28197: pack.js broke under pnpm 11, `Build &
Publish Artifacts` went red, the three downstream jobs skipped, gate
passed, the .npmrc-deletion regression landed on main (devcontainer +
production Docker + next release would all have failed).
9larsons added a commit that referenced this pull request May 27, 2026
refs #28197, #28205. 

This fixes the `ghost-dev` compose for pnpm 11.

The dev Dockerfile (`docker/ghost-dev/Dockerfile`) only stages
`ghost/{core,i18n,parse-email-address}` `package.json`s at build time.
Compose then mounts `./ghost` into the container at runtime, which
exposes `ghost/admin`'s `workspace:*` deps (e.g.
`@tryghost/admin-x-framework` → lives in `apps/admin-x-framework/`).
pnpm 10 was lenient about the missing workspace packages; pnpm 11
strict-validates the workspace graph and `pnpm dev` fails instead of
being tolerated.
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