mirror of
https://github.com/pnpm/pnpm.git
synced 2026-01-01 11:38:21 -05:00
fix: pnpm update --filter --latest should only change relevant packages and projects, with dedupe-peer-dependents=true (#8905)
* test(update): add failing tests for update with dedupe-peer-dependents=true Relates to https://github.com/pnpm/pnpm/issues/8877 * fix: update --filter --latest should work with dedupe-peer-dependents Fixes https://github.com/pnpm/pnpm/issues/8877, whereby `update --filter --latest` with `dedupe-peer-dependents` would end up updating all available dependencies for all projects. * test(pnpm): more accurate dedupePeers filtered install case * docs: add changeset for updateToLatest moving to projects/importers * docs: add changesets for pnpm and plugin-commands-installation * chore: fix tsc issue by removing unknown bound resolver property This unknown property was accepted by tsc prior to adding updateToLatest in toResovleImporter options, but now it was erroring out. This is likely a tsc quirk about the shape of the object; regardless that property is not defined, and should not be present. * test: keep only pnpm/test/monorepo/dedupePeers.test.ts There was duplicate coverage of the pnpm update --filter --latest command between two tests, so this keeps only the one dedicated to testing the dedupe-peer-dependents feature. * chore: fix unused import error
This commit is contained in:
committed by
Zoltan Kochan
parent
c056fe054b
commit
dec8a472a2
6
.changeset/forty-yaks-jog.md
Normal file
6
.changeset/forty-yaks-jog.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
`pnpm update --filter <pattern> --latest <pkg>` should only change the specified package for the specified workspace, when `dedupe-peer-dependents` is set to `true` [#8877](https://github.com/pnpm/pnpm/issues/8877).
|
||||
6
.changeset/moody-berries-design.md
Normal file
6
.changeset/moody-berries-design.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/resolve-dependencies": major
|
||||
"@pnpm/core": major
|
||||
---
|
||||
|
||||
The `updateToLatest` option is now part of projects/importers, instead of an option of the resolution/installation.
|
||||
@@ -98,7 +98,6 @@ export interface StrictInstallOptions {
|
||||
unsafePerm: boolean
|
||||
registries: Registries
|
||||
tag: string
|
||||
updateToLatest?: boolean
|
||||
overrides: Record<string, string>
|
||||
ownLifecycleHooksStdio: 'inherit' | 'pipe'
|
||||
// We can automatically calculate these
|
||||
|
||||
@@ -109,6 +109,7 @@ const DEV_PREINSTALL = 'pnpm:devPreinstall'
|
||||
|
||||
interface InstallMutationOptions {
|
||||
update?: boolean
|
||||
updateToLatest?: boolean
|
||||
updateMatching?: UpdateMatchingFunction
|
||||
updatePackageManifest?: boolean
|
||||
}
|
||||
@@ -163,6 +164,7 @@ export async function install (
|
||||
rootDir,
|
||||
update: opts.update,
|
||||
updateMatching: opts.updateMatching,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
updatePackageManifest: opts.updatePackageManifest,
|
||||
},
|
||||
],
|
||||
@@ -209,6 +211,7 @@ export async function mutateModulesInSingleProject (
|
||||
{
|
||||
...project,
|
||||
update: maybeOpts.update,
|
||||
updateToLatest: maybeOpts.updateToLatest,
|
||||
updateMatching: maybeOpts.updateMatching,
|
||||
updatePackageManifest: maybeOpts.updatePackageManifest,
|
||||
} as MutatedProject,
|
||||
@@ -835,6 +838,7 @@ export async function addDependenciesToPackage (
|
||||
update: opts.update,
|
||||
updateMatching: opts.updateMatching,
|
||||
updatePackageManifest: opts.updatePackageManifest,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
},
|
||||
],
|
||||
{
|
||||
@@ -1028,7 +1032,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
saveWorkspaceProtocol: opts.saveWorkspaceProtocol,
|
||||
storeController: opts.storeController,
|
||||
tag: opts.tag,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
virtualStoreDir: ctx.virtualStoreDir,
|
||||
virtualStoreDirMaxLength: ctx.virtualStoreDirMaxLength,
|
||||
wantedLockfile: ctx.wantedLockfile,
|
||||
|
||||
@@ -234,6 +234,7 @@ export async function recursive (
|
||||
update: opts.update,
|
||||
updateMatching: opts.updateMatching,
|
||||
updatePackageManifest: opts.updatePackageManifest,
|
||||
updateToLatest: opts.latest,
|
||||
} as MutatedProject)
|
||||
return
|
||||
case 'install':
|
||||
@@ -245,6 +246,7 @@ export async function recursive (
|
||||
update: opts.update,
|
||||
updateMatching: opts.updateMatching,
|
||||
updatePackageManifest: opts.updatePackageManifest,
|
||||
updateToLatest: opts.latest,
|
||||
} as MutatedProject)
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -125,7 +125,6 @@ export async function resolveDependencies (
|
||||
preferredVersions: opts.preferredVersions,
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
workspacePackages: opts.workspacePackages,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
noDependencySelectors: importers.every(({ wantedDependencies }) => wantedDependencies.length === 0),
|
||||
})
|
||||
const projectsToResolve = await Promise.all(importers.map(async (project) => _toResolveImporter(project)))
|
||||
|
||||
@@ -88,6 +88,7 @@ export interface Importer<WantedDepExtraProps> {
|
||||
export interface ImporterToResolveGeneric<WantedDepExtraProps> extends Importer<WantedDepExtraProps> {
|
||||
updatePackageManifest: boolean
|
||||
updateMatching?: (pkgName: string) => boolean
|
||||
updateToLatest?: boolean
|
||||
hasRemovedDependencies?: boolean
|
||||
preferredVersions?: PreferredVersions
|
||||
wantedDependencies: Array<WantedDepExtraProps & WantedDependency & { updateDepth: number }>
|
||||
@@ -127,7 +128,6 @@ export interface ResolveDependenciesOptions {
|
||||
wantedLockfile: Lockfile
|
||||
workspacePackages: WorkspacePackages
|
||||
supportedArchitectures?: SupportedArchitectures
|
||||
updateToLatest?: boolean
|
||||
peersSuffixMaxLength: number
|
||||
}
|
||||
|
||||
@@ -214,9 +214,9 @@ export async function resolveDependencyTree<T> (
|
||||
},
|
||||
updateDepth: -1,
|
||||
updateMatching: importer.updateMatching,
|
||||
updateToLatest: importer.updateToLatest,
|
||||
prefix: importer.rootDir,
|
||||
supportedArchitectures: opts.supportedArchitectures,
|
||||
updateToLatest: opts.updateToLatest,
|
||||
}
|
||||
return {
|
||||
updatePackageManifest: importer.updatePackageManifest,
|
||||
|
||||
@@ -91,6 +91,58 @@ auto-install-peers=false`, 'utf8')
|
||||
expect(loadJsonFile<any>('project-2/package.json').dependencies['@pnpm.e2e/abc-grand-parent-with-c']).toBe('^1.0.1') // eslint-disable-line
|
||||
})
|
||||
|
||||
// Covers https://github.com/pnpm/pnpm/issues/8877
|
||||
test('partial update --latest in a workspace should not affect other packages when dedupe-peer-dependents is true', async () => {
|
||||
await addDistTag({ package: '@pnpm.e2e/foo', version: '1.0.0', distTag: 'latest' })
|
||||
await addDistTag({ package: '@pnpm.e2e/bar', version: '100.0.0', distTag: 'latest' })
|
||||
|
||||
preparePackages([
|
||||
{
|
||||
location: 'project-1',
|
||||
package: {
|
||||
name: 'project-1',
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/foo': '1.0.0',
|
||||
'@pnpm.e2e/bar': '100.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
location: 'project-2',
|
||||
package: {
|
||||
name: 'project-2',
|
||||
|
||||
dependencies: {
|
||||
'@pnpm.e2e/foo': '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
|
||||
fs.writeFileSync('.npmrc', `dedupe-peer-dependents=true
|
||||
auto-install-peers=false`, 'utf8')
|
||||
await execPnpm(['install'])
|
||||
|
||||
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'])
|
||||
|
||||
// project 1's manifest is unaffected, while project 2 has 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
|
||||
|
||||
// similar for the importers in the lockfile; project 1 is unaffected, while
|
||||
// project 2 resolves the latest foo
|
||||
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')
|
||||
})
|
||||
|
||||
// Covers https://github.com/pnpm/pnpm/issues/6154
|
||||
test('peer dependents deduplication should not remove peer dependencies', async () => {
|
||||
await addDistTag({ package: '@pnpm.e2e/peer-a', version: '1.0.0', distTag: 'latest' })
|
||||
|
||||
Reference in New Issue
Block a user