pnpm/pnpm#14934 (in pnpm 12.7.0) gives every private project
`repository` changelog storage: `pnpm version -r` commits its section to
CHANGELOG.md. That is right for packages that are never published, but
the npm wrappers of the Rust products (pacquet, `@pnpm/napi`,
`@pnpm/pnpr`) are private in-repo only to keep a workspace-wide publish
from shipping them. Their generate-packages scripts drop the flag when
they are published for real.
The first release bumped with pnpm 12.7.0 (pnpm/pnpm#16312) therefore
committed their sections to CHANGELOG.md and parked nothing. release.yml
reads the parked section for the GitHub release body, and the
publish-time changelog composer reads it for the npm tarball's
CHANGELOG.md, so both would have come out empty. That release was fixed
by hand.
bump.ts now moves each wrapper's freshly written CHANGELOG.md to
`.changeset/changelogs/<name>@<version>.md` after `pnpm version -r`.
Intent consumption is unchanged: a private project's intents are
consumed immediately, and the parked section is garbage-collected by the
next bump once the registry confirms the published changelog carries it.
The move refuses a CHANGELOG.md holding anything but the released
section, so a stale file cannot be parked under the wrong version.
The script runs before the workspace is installed, so it mirrors the
filename encoding of `pendingChangelogPath` in
`@pnpm/releasing.versioning` instead of importing it.
Related to pnpm/tasks#38.
Every per-target archive is built from one shared `dist/`, so the Windows
entries rode along into the macOS and Linux archives: the `node-gyp.cmd` batch
twin of the POSIX `node-gyp` wrapper, and the fastlist binaries `ps-list`
spawns from its Windows-only branch. In the macOS arm64 archive for 11.28.0
those two `.exe` files alone are 487 KB that no macOS process can load.
`copy-artifacts.ts` already drops the non-target `@reflink` native packages
per target, so the same pruning now covers these entries for every non-Windows
target. The Windows archives and the npm packages are unchanged: those serve
Windows, and the npm packages serve every platform out of one `dist/`.
The Rust CLI's GitHub archives carry `node-gyp.cmd` the same way, from a
node-gyp payload built once and shared by every target, so the non-Windows
archiving step drops it there too. Its npm packages keep it, as they do in the
TypeScript CLI.
pnpm run forwards everything after the script name to the script verbatim,
including the -- separator itself, so the create-release-pr workflow's
`pnpm run bump -- --release <product>` invocations delivered a literal --
as the first argument and the fail-closed parser rejected it.
parseSelectedProducts now skips a single leading --; a -- in any other
position, and any other unrecognized token, still fails closed.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
pnpm bump ran `pnpm version -r` unfiltered, consuming the entire changeset
ledger, so every release flushed the TypeScript CLI's pending intents alongside
the Rust products' alpha prereleases. A rapid v12 alpha cadence therefore forced
an equally rapid v11 release cadence — and with it a v11 "Update available!"
notification almost every day.
Give create-release-pr.yml three checkboxes — pnpm11 (the TypeScript CLI),
pnpm (the Rust CLI, v12 alpha), and pnpr — in any combination. bump.ts
translates the selected products into `pnpm version -r --filter` arguments,
consuming only their intents and leaving the rest in the ledger. The default
lane (pnpm11) has no single positive selector, so it is expressed as the
complement of the unselected alpha products (an exclude-only filter selects
every project minus those); selecting all three yields no filter — a full
release. The embedded trust-root refresh steps run only when pnpm11 is selected,
since those keys ship in the TypeScript CLI.
Argument parsing fails closed: an unrecognized token (e.g. a `--releases` typo)
throws instead of leaving the selection empty and releasing every product; a
bare `pnpm bump` with no arguments still cuts a full release. The version
command is built as an argv array (execFileSync, no shell) so a filter value is
never interpreted by a shell.
Related to pnpm/pnpm#13264.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Rust CLI and pnpr embed the versions their release builds report and
verify (`PNPM_VERSION` in pnpm/crates/config/src/defaults.rs, the crate
version in pnpr/crates/pnpr/Cargo.toml, and its Cargo.lock entry). These
were mirrored from the npm wrappers by `syncRustVersions` in bump.ts — a
step separate from the meta-updater, so running `pnpm version -r` without
the full bump flow bumped the wrappers (pacquet 12.0.0-alpha.10, pnpr
0.1.0-alpha.2) while the Rust sources stayed at the previous versions. The
release workflow's "Verify the committed version" step then failed, and
nothing caught the drift before the tag.
Move the sync into the meta-updater as a set of Rust-source file handlers,
so it is written by `pnpm update-manifests` and, crucially, validated by
`meta-updater --test` in pre-push and CI — a missed sync now fails locally
instead of at release time. bump.ts drops the redundant `syncRustVersions`
and runs `pnpm update-manifests` after `pnpm version -r`; the root `bump`
script no longer needs its own trailing `update-manifests`.
Regenerating brings the Rust sources up to the already-bumped wrapper
versions (alpha.10 / alpha.2), unblocking the release.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge the three release flows (TypeScript, Rust CLI + @pnpm/napi, pnpr)
into a single flow driven by pnpm's native workspace versioning
(pnpm/pnpm#12953), dropping the @changesets/cli dependency (Closes
pnpm/pnpm#12947).
The native engine keys package identity on the workspace directory, so
the Rust CLI wrapper is named pnpm (the v12 line at pnpm/npm/pnpm) and
shares the published name with the TypeScript CLI at pnpm11/pnpm.
Release configuration moves from .changeset/config.json to the
versioning key of pnpm-workspace.yaml: versioning.lanes puts the Rust
CLI, @pnpm/napi, and @pnpm/pnpr on an alpha lane (X.Y.Z-alpha.N
prereleases published under next) while the TypeScript CLI releases
stable on the main lane; versioning.fixed keeps the Rust CLI and
@pnpm/napi at one shared version; versioning.ignore freezes
@pnpm/logger, which is consumed as a catalog: peer the engine would
otherwise reject as an internal range.
Lanes replace the hand-rolled prerelease continuation, and the
committed .changeset/ledger.yaml replaces the .changeset-released
directory as the cherry-pick-safe record of consumed intents. bump.ts
drops both and is now just pnpm version -r plus syncRustVersions, which
mirrors the bumped wrapper versions into defaults.rs and the pnpr crate
version.
Because two workspace projects are named pnpm, name-based --filter=pnpm
is qualified by directory (pnpm{pnpm11/pnpm}) across the build and
release scripts, the meta-updater excludes the Rust wrappers by
directory, and changesets targeting the TypeScript CLI reference it as
./pnpm11/pnpm. release.yml's plan job gates per-product publish jobs on
which committed versions are unpublished; everything publishes via
trusted publishing. @changesets/cli, .changeset/config.json, and the
standalone pacquet/pnpr release workflows are removed; their npm
trusted-publisher bindings must be re-pointed at release.yml before the
first unified release.
pnpm-lock.yaml is regenerated from scratch: an incremental
--lockfile-only resolve after the @changesets/cli removal hit a pacquet
incremental-resolver bug (pnpm/pnpm#12958) that emptied a peer-context
snapshot the CLI depends on and broke the bundle build. A from-scratch
resolve is correct; the bug is filed separately.
The TypeScript pnpm CLI freezes at v11; pnpm 12 will be the Rust pacquet
port. To make that split legible, all TypeScript source, test, and build
directories move under a new top-level pnpm11/ directory. The name states
the version boundary rather than implying a behavioral fork, since the two
stacks are meant to behave identically.
Scope is source-only: the shared workspace root stays at the repo root.
pnpm-workspace.yaml, package.json, pnpm-lock.yaml, .pnpmfile.cjs,
.meta-updater, __patches__, .changeset, .husky, and the lint/spell configs
remain in place, so one pnpm workspace and one Cargo workspace still span
all three products. pnpr/client and pacquet/tasks/registry-mock stay as
cross-product workspace members.
Rewiring the move required:
- pnpm-workspace.yaml globs prefixed with pnpm11/
- root package.json script paths, eslint.config.mjs, tsconfig.lint.json,
.gitignore, and CODEOWNERS updated
- .meta-updater/src/index.ts literals repointed (pnpm11/pnpm/package.json,
pnpm11/__utils__, pnpm11/__typings__, and the main package directory)
- regenerated every moved package's repository/homepage URL via meta-updater
- pnpm11/pnpm/bundle-deps.ts and __utils__/scripts/src/typecheck-only.ts
climb one more level to reach the repo root
.meta-updater stays at the repo root because @pnpm/meta-updater resolves
its config at <cwd>/.meta-updater/main.mjs.
TS CI (.github/workflows/ci.yml) now only runs when pnpm11/-relevant paths
change, via a dorny/paths-filter changes job plus a TS CI / Success
aggregate gate; branch protection should require only that gate.