mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-24 07:38:12 -05:00
fix: ensure that recursive pnpm update --latest <pkg> updates only the specified package (#8933)
* test(pnpm): expand dedupePeers test to account for other dependencies in same package Previously, this test only asserted that _other_ monorepo packages were unaffected, but it did not check other dependencies of the _same_ monorepo package. * fix: ensure that recursive update --latest only updates matched packages * fix: move update check to resolveDependendency * refactor: move updateToLatest conditional up in resolveDependency * refactor: make update types mutually exclusive in resolveDependencies * refactor: rename 'in-range' update type to 'compatible' Co-authored-by: Zoltan Kochan <z@kochan.io> * refactor: use update union type in package-requester and store-controller-type * docs: add changesets --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
committed by
GitHub
parent
c5080ded56
commit
dde650b96f
5
.changeset/friendly-tips-rest.md
Normal file
5
.changeset/friendly-tips-rest.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/resolve-dependencies": patch
|
||||
---
|
||||
|
||||
Fix a case in `resolveDependencies`, whereby an importer that should not have been updated altogether, was being updated when `updateToLatest` was specified in the options.
|
||||
8
.changeset/serious-swans-wonder.md
Normal file
8
.changeset/serious-swans-wonder.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"@pnpm/package-requester": major
|
||||
"@pnpm/store-controller-types": major
|
||||
---
|
||||
|
||||
`RequestPackageOptions` now takes a union type for the `update` option, instead of a separate `updateToLatest` option.
|
||||
|
||||
This avoids pitfalls around specifying only `update` or, specifying `update: false`, but still providing `updateToLatest: true`.
|
||||
5
.changeset/shy-hounds-wave.md
Normal file
5
.changeset/shy-hounds-wave.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Ensure that recursive `pnpm update --latest <pkg>` updates only the specified package, with `dedupe-peer-dependents=true`.
|
||||
@@ -187,7 +187,7 @@ async function resolveAndFetch (
|
||||
projectDir: options.projectDir,
|
||||
registry: options.registry,
|
||||
workspacePackages: options.workspacePackages,
|
||||
updateToLatest: options.updateToLatest,
|
||||
updateToLatest: options.update === 'latest',
|
||||
injectWorkspacePackages: options.injectWorkspacePackages,
|
||||
}), { priority: options.downloadPriority })
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ import loadJsonFile from 'load-json-file'
|
||||
import nock from 'nock'
|
||||
import normalize from 'normalize-path'
|
||||
import tempy from 'tempy'
|
||||
import { type PkgResolutionId, type PkgRequestFetchResult } from '@pnpm/store-controller-types'
|
||||
import { type PkgResolutionId, type PkgRequestFetchResult, type RequestPackageOptions } from '@pnpm/store-controller-types'
|
||||
|
||||
const registry = `http://localhost:${REGISTRY_MOCK_PORT}`
|
||||
const f = fixtures(__dirname)
|
||||
@@ -182,7 +182,7 @@ test('refetch local tarball if its integrity has changed', async () => {
|
||||
registry,
|
||||
skipFetch: true,
|
||||
update: false,
|
||||
}
|
||||
} satisfies RequestPackageOptions
|
||||
|
||||
{
|
||||
const requestPackage = createPackageRequester({
|
||||
@@ -288,7 +288,7 @@ test('refetch local tarball if its integrity has changed. The requester does not
|
||||
projectDir,
|
||||
registry,
|
||||
update: false,
|
||||
}
|
||||
} satisfies RequestPackageOptions
|
||||
|
||||
{
|
||||
const requestPackage = createPackageRequester({
|
||||
|
||||
@@ -824,11 +824,10 @@ async function resolveDependenciesOfDependency (
|
||||
prefix: options.prefix,
|
||||
proceed: extendedWantedDep.proceed || updateShouldContinue || ctx.updatedSet.size > 0,
|
||||
publishedBy: options.publishedBy,
|
||||
update,
|
||||
update: update ? options.updateToLatest ? 'latest' : 'compatible' : false,
|
||||
updateDepth,
|
||||
updateMatching: options.updateMatching,
|
||||
supportedArchitectures: options.supportedArchitectures,
|
||||
updateToLatest: options.updateToLatest,
|
||||
parentIds: options.parentIds,
|
||||
}
|
||||
const resolveDependencyResult = await resolveDependency(extendedWantedDep.wantedDependency, ctx, resolveDependencyOpts)
|
||||
@@ -1175,11 +1174,10 @@ interface ResolveDependencyOptions {
|
||||
proceed: boolean
|
||||
publishedBy?: Date
|
||||
pickLowestVersion?: boolean
|
||||
update: boolean
|
||||
update: false | 'compatible' | 'latest'
|
||||
updateDepth: number
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
updateToLatest?: boolean
|
||||
}
|
||||
|
||||
type ResolveDependencyResult = PkgAddress | LinkedDependency | null
|
||||
@@ -1260,7 +1258,6 @@ async function resolveDependency (
|
||||
err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById)
|
||||
return err
|
||||
},
|
||||
updateToLatest: options.updateToLatest,
|
||||
injectWorkspacePackages: ctx.injectWorkspacePackages,
|
||||
})
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
|
||||
@@ -115,6 +115,7 @@ test('partial update --latest in a workspace should not affect other packages wh
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/foo': '1.0.0',
|
||||
'@pnpm.e2e/bar': '100.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -128,19 +129,22 @@ auto-install-peers=false`, 'utf8')
|
||||
await addDistTag({ package: '@pnpm.e2e/foo', version: '2.0.0', distTag: 'latest' })
|
||||
await addDistTag({ package: '@pnpm.e2e/bar', version: '100.1.0', distTag: 'latest' })
|
||||
|
||||
await execPnpm(['update', '--filter', 'project-2', '--latest'])
|
||||
// update foo only for project-2
|
||||
await execPnpm(['update', '--filter', 'project-2', '--latest', '@pnpm.e2e/foo'])
|
||||
|
||||
// project 1's manifest is unaffected, while project 2 has foo updated
|
||||
// project 1's manifest is unaffected, while project 2 has only foo updated
|
||||
expect(loadJsonFile<any>('project-1/package.json').dependencies['@pnpm.e2e/foo']).toBe('1.0.0') // eslint-disable-line
|
||||
expect(loadJsonFile<any>('project-1/package.json').dependencies['@pnpm.e2e/bar']).toBe('100.0.0') // eslint-disable-line
|
||||
expect(loadJsonFile<any>('project-2/package.json').dependencies['@pnpm.e2e/foo']).toBe('2.0.0') // eslint-disable-line
|
||||
expect(loadJsonFile<any>('project-2/package.json').dependencies['@pnpm.e2e/bar']).toBe('100.0.0') // eslint-disable-line
|
||||
|
||||
// similar for the importers in the lockfile; project 1 is unaffected, while
|
||||
// project 2 resolves the latest foo
|
||||
// project 2 resolves the latest foo, but keeps bar to the previous version
|
||||
const lockfile = readYamlFile<any>(path.resolve(WANTED_LOCKFILE)) // eslint-disable-line
|
||||
expect(lockfile.importers['project-1']?.dependencies?.['@pnpm.e2e/foo'].version).toStrictEqual('1.0.0')
|
||||
expect(lockfile.importers['project-1']?.dependencies?.['@pnpm.e2e/bar'].version).toStrictEqual('100.0.0')
|
||||
expect(lockfile.importers['project-2']?.dependencies?.['@pnpm.e2e/foo'].version).toStrictEqual('2.0.0')
|
||||
expect(lockfile.importers['project-2']?.dependencies?.['@pnpm.e2e/bar'].version).toStrictEqual('100.0.0')
|
||||
})
|
||||
|
||||
// Covers https://github.com/pnpm/pnpm/issues/6154
|
||||
|
||||
@@ -126,12 +126,11 @@ export interface RequestPackageOptions {
|
||||
registry: string
|
||||
sideEffectsCache?: boolean
|
||||
skipFetch?: boolean
|
||||
update?: boolean
|
||||
update?: false | 'compatible' | 'latest'
|
||||
workspacePackages?: WorkspacePackages
|
||||
forceResolve?: boolean
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
onFetchError?: OnFetchError
|
||||
updateToLatest?: boolean
|
||||
injectWorkspacePackages?: boolean
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user