mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-01 20:49:45 -04:00
fix: write packageManagerDependencies to lockfile when devEngines.packageManager is set (#11681)
When `devEngines.packageManager.pnpm` is set without `onFail: "download"`,
`pnpm install` ran `syncEnvLockfile` instead of `switchCliVersion`. That sync
returned early whenever the env lockfile did not already record a
`packageManagerDependencies.pnpm` entry, so the resolved pnpm version was
never recorded on first install — contradicting the documented behavior
("The resolved version is stored in pnpm-lock.yaml") and forcing users to
add `onFail: "download"` purely to trigger the lockfile write.
Drop the two early-returns that only fired when the env lockfile was
missing or empty. The resolution proceeds whenever (a) the project pins a
pnpm version via `devEngines.packageManager` (or a v12+ `packageManager`
field) and (b) the running pnpm satisfies that pin. The existing
"already-resolved" no-op path still skips work when the lockfile already
records a satisfying version, so steady-state installs don't churn.
Closes #11674 (part 1). Part 3 (pruning `@pnpm/exe` platform entries when
`onFail: "download"` is removed) is left for a follow-up — it needs a
state-transition signal the codebase doesn't yet track.
Co-authored-by: Damon <damon@deeplearning.ai>
This commit is contained in:
5
.changeset/sync-env-lockfile-when-missing-11674.md
Normal file
5
.changeset/sync-env-lockfile-when-missing-11674.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Fix `devEngines.packageManager` not writing `packageManagerDependencies` to `pnpm-lock.yaml` when the lockfile lacks an env-doc entry. Previously the lockfile sync skipped resolution unless an existing `packageManagerDependencies.pnpm` entry needed refreshing, so a fresh install without `onFail: "download"` left the resolved pnpm version unrecorded — contradicting the documented behavior that the resolved version is stored in `pnpm-lock.yaml` [#11674](https://github.com/pnpm/pnpm/issues/11674).
|
||||
@@ -84,21 +84,32 @@ test('no-op when running pnpm does not satisfy wanted range', async () => {
|
||||
expect(resolvePackageManagerIntegrities).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('no-op when no env lockfile exists', async () => {
|
||||
test('writes packageManagerDependencies when no env lockfile exists yet (#11674)', async () => {
|
||||
const dir = tempDir()
|
||||
await syncEnvLockfile(baseConfig, makeContext(dir, {
|
||||
wantedPackageManager: { name: 'pnpm', version: packageManager.version, fromDevEngines: true },
|
||||
}))
|
||||
expect(resolvePackageManagerIntegrities).not.toHaveBeenCalled()
|
||||
expect(resolvePackageManagerIntegrities).toHaveBeenCalledTimes(1)
|
||||
const updated = await readEnvLockfile(dir)
|
||||
expect(updated).not.toBeNull()
|
||||
expect(updated!.importers['.'].packageManagerDependencies?.['pnpm']).toEqual({
|
||||
specifier: packageManager.version,
|
||||
version: packageManager.version,
|
||||
})
|
||||
})
|
||||
|
||||
test('no-op when lockfile has no packageManagerDependencies for pnpm', async () => {
|
||||
test('writes packageManagerDependencies when env lockfile exists but lacks pnpm entry (#11674)', async () => {
|
||||
const dir = tempDir()
|
||||
writeEnvLockfileWithoutPmDeps(dir)
|
||||
await syncEnvLockfile(baseConfig, makeContext(dir, {
|
||||
wantedPackageManager: { name: 'pnpm', version: packageManager.version, fromDevEngines: true },
|
||||
}))
|
||||
expect(resolvePackageManagerIntegrities).not.toHaveBeenCalled()
|
||||
expect(resolvePackageManagerIntegrities).toHaveBeenCalledTimes(1)
|
||||
const updated = await readEnvLockfile(dir)
|
||||
expect(updated!.importers['.'].packageManagerDependencies?.['pnpm']).toEqual({
|
||||
specifier: packageManager.version,
|
||||
version: packageManager.version,
|
||||
})
|
||||
})
|
||||
|
||||
test('no-op when lockfile already records a satisfying version', async () => {
|
||||
|
||||
@@ -8,14 +8,17 @@ import semver from 'semver'
|
||||
import { shouldPersistLockfile } from './shouldPersistLockfile.js'
|
||||
|
||||
/**
|
||||
* Refreshes the env lockfile's `packageManagerDependencies` entry when it
|
||||
* records a pnpm version that no longer satisfies the wanted
|
||||
* `devEngines.packageManager` range. The currently running pnpm version
|
||||
* (already verified to satisfy the wanted range by checkPackageManager) is
|
||||
* recorded as the new resolution.
|
||||
* Records the currently running pnpm version in the env lockfile's
|
||||
* `packageManagerDependencies` entry when the project opts in to
|
||||
* lockfile-pinned versioning (via `devEngines.packageManager`, or a v12+
|
||||
* `packageManager` pin) and the lockfile doesn't already record a version
|
||||
* that satisfies the wanted range.
|
||||
*
|
||||
* No-op when the project does not pin a pnpm version, when no env lockfile
|
||||
* exists yet, or when the recorded version still satisfies the wanted range.
|
||||
* The currently running pnpm version has already been verified by
|
||||
* checkPackageManager to satisfy the wanted range, so recording it is safe.
|
||||
*
|
||||
* No-op when the project does not pin a pnpm version or when the recorded
|
||||
* version still satisfies the wanted range.
|
||||
*/
|
||||
export async function syncEnvLockfile (config: Config, context: ConfigContext): Promise<void> {
|
||||
const pm = context.wantedPackageManager
|
||||
@@ -27,15 +30,13 @@ export async function syncEnvLockfile (config: Config, context: ConfigContext):
|
||||
if (!semver.satisfies(packageManager.version, pm.version, { includePrerelease: true })) return
|
||||
|
||||
const envLockfile = await readEnvLockfile(context.rootProjectManifestDir)
|
||||
if (envLockfile == null) return
|
||||
const lockedVersion = envLockfile.importers['.'].packageManagerDependencies?.['pnpm']?.version
|
||||
if (lockedVersion == null) return
|
||||
if (semver.satisfies(lockedVersion, pm.version, { includePrerelease: true })) return
|
||||
const lockedVersion = envLockfile?.importers['.'].packageManagerDependencies?.['pnpm']?.version
|
||||
if (lockedVersion != null && semver.satisfies(lockedVersion, pm.version, { includePrerelease: true })) return
|
||||
|
||||
const store = await createStoreController({ ...config, ...context })
|
||||
try {
|
||||
await resolvePackageManagerIntegrities(packageManager.version, {
|
||||
envLockfile,
|
||||
envLockfile: envLockfile ?? undefined,
|
||||
registries: config.registries,
|
||||
rootDir: context.rootProjectManifestDir,
|
||||
storeController: store.ctrl,
|
||||
|
||||
Reference in New Issue
Block a user