mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-18 22:02:53 -04: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,
|
projectDir: options.projectDir,
|
||||||
registry: options.registry,
|
registry: options.registry,
|
||||||
workspacePackages: options.workspacePackages,
|
workspacePackages: options.workspacePackages,
|
||||||
updateToLatest: options.updateToLatest,
|
updateToLatest: options.update === 'latest',
|
||||||
injectWorkspacePackages: options.injectWorkspacePackages,
|
injectWorkspacePackages: options.injectWorkspacePackages,
|
||||||
}), { priority: options.downloadPriority })
|
}), { priority: options.downloadPriority })
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import loadJsonFile from 'load-json-file'
|
|||||||
import nock from 'nock'
|
import nock from 'nock'
|
||||||
import normalize from 'normalize-path'
|
import normalize from 'normalize-path'
|
||||||
import tempy from 'tempy'
|
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 registry = `http://localhost:${REGISTRY_MOCK_PORT}`
|
||||||
const f = fixtures(__dirname)
|
const f = fixtures(__dirname)
|
||||||
@@ -182,7 +182,7 @@ test('refetch local tarball if its integrity has changed', async () => {
|
|||||||
registry,
|
registry,
|
||||||
skipFetch: true,
|
skipFetch: true,
|
||||||
update: false,
|
update: false,
|
||||||
}
|
} satisfies RequestPackageOptions
|
||||||
|
|
||||||
{
|
{
|
||||||
const requestPackage = createPackageRequester({
|
const requestPackage = createPackageRequester({
|
||||||
@@ -288,7 +288,7 @@ test('refetch local tarball if its integrity has changed. The requester does not
|
|||||||
projectDir,
|
projectDir,
|
||||||
registry,
|
registry,
|
||||||
update: false,
|
update: false,
|
||||||
}
|
} satisfies RequestPackageOptions
|
||||||
|
|
||||||
{
|
{
|
||||||
const requestPackage = createPackageRequester({
|
const requestPackage = createPackageRequester({
|
||||||
|
|||||||
@@ -824,11 +824,10 @@ async function resolveDependenciesOfDependency (
|
|||||||
prefix: options.prefix,
|
prefix: options.prefix,
|
||||||
proceed: extendedWantedDep.proceed || updateShouldContinue || ctx.updatedSet.size > 0,
|
proceed: extendedWantedDep.proceed || updateShouldContinue || ctx.updatedSet.size > 0,
|
||||||
publishedBy: options.publishedBy,
|
publishedBy: options.publishedBy,
|
||||||
update,
|
update: update ? options.updateToLatest ? 'latest' : 'compatible' : false,
|
||||||
updateDepth,
|
updateDepth,
|
||||||
updateMatching: options.updateMatching,
|
updateMatching: options.updateMatching,
|
||||||
supportedArchitectures: options.supportedArchitectures,
|
supportedArchitectures: options.supportedArchitectures,
|
||||||
updateToLatest: options.updateToLatest,
|
|
||||||
parentIds: options.parentIds,
|
parentIds: options.parentIds,
|
||||||
}
|
}
|
||||||
const resolveDependencyResult = await resolveDependency(extendedWantedDep.wantedDependency, ctx, resolveDependencyOpts)
|
const resolveDependencyResult = await resolveDependency(extendedWantedDep.wantedDependency, ctx, resolveDependencyOpts)
|
||||||
@@ -1175,11 +1174,10 @@ interface ResolveDependencyOptions {
|
|||||||
proceed: boolean
|
proceed: boolean
|
||||||
publishedBy?: Date
|
publishedBy?: Date
|
||||||
pickLowestVersion?: boolean
|
pickLowestVersion?: boolean
|
||||||
update: boolean
|
update: false | 'compatible' | 'latest'
|
||||||
updateDepth: number
|
updateDepth: number
|
||||||
updateMatching?: UpdateMatchingFunction
|
updateMatching?: UpdateMatchingFunction
|
||||||
supportedArchitectures?: SupportedArchitectures
|
supportedArchitectures?: SupportedArchitectures
|
||||||
updateToLatest?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResolveDependencyResult = PkgAddress | LinkedDependency | null
|
type ResolveDependencyResult = PkgAddress | LinkedDependency | null
|
||||||
@@ -1260,7 +1258,6 @@ async function resolveDependency (
|
|||||||
err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById)
|
err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
updateToLatest: options.updateToLatest,
|
|
||||||
injectWorkspacePackages: ctx.injectWorkspacePackages,
|
injectWorkspacePackages: ctx.injectWorkspacePackages,
|
||||||
})
|
})
|
||||||
} catch (err: any) { // eslint-disable-line
|
} catch (err: any) { // eslint-disable-line
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ test('partial update --latest in a workspace should not affect other packages wh
|
|||||||
|
|
||||||
dependencies: {
|
dependencies: {
|
||||||
'@pnpm.e2e/foo': '1.0.0',
|
'@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/foo', version: '2.0.0', distTag: 'latest' })
|
||||||
await addDistTag({ package: '@pnpm.e2e/bar', version: '100.1.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/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-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/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
|
// 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
|
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/foo'].version).toStrictEqual('1.0.0')
|
||||||
expect(lockfile.importers['project-1']?.dependencies?.['@pnpm.e2e/bar'].version).toStrictEqual('100.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/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
|
// Covers https://github.com/pnpm/pnpm/issues/6154
|
||||||
|
|||||||
@@ -126,12 +126,11 @@ export interface RequestPackageOptions {
|
|||||||
registry: string
|
registry: string
|
||||||
sideEffectsCache?: boolean
|
sideEffectsCache?: boolean
|
||||||
skipFetch?: boolean
|
skipFetch?: boolean
|
||||||
update?: boolean
|
update?: false | 'compatible' | 'latest'
|
||||||
workspacePackages?: WorkspacePackages
|
workspacePackages?: WorkspacePackages
|
||||||
forceResolve?: boolean
|
forceResolve?: boolean
|
||||||
supportedArchitectures?: SupportedArchitectures
|
supportedArchitectures?: SupportedArchitectures
|
||||||
onFetchError?: OnFetchError
|
onFetchError?: OnFetchError
|
||||||
updateToLatest?: boolean
|
|
||||||
injectWorkspacePackages?: boolean
|
injectWorkspacePackages?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user