diff --git a/.changeset/forty-yaks-jog.md b/.changeset/forty-yaks-jog.md new file mode 100644 index 0000000000..ca0870e404 --- /dev/null +++ b/.changeset/forty-yaks-jog.md @@ -0,0 +1,6 @@ +--- +"@pnpm/plugin-commands-installation": patch +"pnpm": patch +--- + +`pnpm update --filter --latest ` 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). diff --git a/.changeset/moody-berries-design.md b/.changeset/moody-berries-design.md new file mode 100644 index 0000000000..74aa780741 --- /dev/null +++ b/.changeset/moody-berries-design.md @@ -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. diff --git a/pkg-manager/core/src/install/extendInstallOptions.ts b/pkg-manager/core/src/install/extendInstallOptions.ts index cd1fb0a7e5..2b29b6125b 100644 --- a/pkg-manager/core/src/install/extendInstallOptions.ts +++ b/pkg-manager/core/src/install/extendInstallOptions.ts @@ -98,7 +98,6 @@ export interface StrictInstallOptions { unsafePerm: boolean registries: Registries tag: string - updateToLatest?: boolean overrides: Record ownLifecycleHooksStdio: 'inherit' | 'pipe' // We can automatically calculate these diff --git a/pkg-manager/core/src/install/index.ts b/pkg-manager/core/src/install/index.ts index 435c1ae5a9..c3bfe6ffd1 100644 --- a/pkg-manager/core/src/install/index.ts +++ b/pkg-manager/core/src/install/index.ts @@ -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, diff --git a/pkg-manager/plugin-commands-installation/src/recursive.ts b/pkg-manager/plugin-commands-installation/src/recursive.ts index 0e1d29d4ed..9552946564 100755 --- a/pkg-manager/plugin-commands-installation/src/recursive.ts +++ b/pkg-manager/plugin-commands-installation/src/recursive.ts @@ -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) } })) diff --git a/pkg-manager/resolve-dependencies/src/index.ts b/pkg-manager/resolve-dependencies/src/index.ts index 86a8a056ce..28fa1b4c87 100644 --- a/pkg-manager/resolve-dependencies/src/index.ts +++ b/pkg-manager/resolve-dependencies/src/index.ts @@ -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))) diff --git a/pkg-manager/resolve-dependencies/src/resolveDependencyTree.ts b/pkg-manager/resolve-dependencies/src/resolveDependencyTree.ts index 1facf920b5..9e188a260c 100644 --- a/pkg-manager/resolve-dependencies/src/resolveDependencyTree.ts +++ b/pkg-manager/resolve-dependencies/src/resolveDependencyTree.ts @@ -88,6 +88,7 @@ export interface Importer { export interface ImporterToResolveGeneric extends Importer { updatePackageManifest: boolean updateMatching?: (pkgName: string) => boolean + updateToLatest?: boolean hasRemovedDependencies?: boolean preferredVersions?: PreferredVersions wantedDependencies: Array @@ -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 ( }, updateDepth: -1, updateMatching: importer.updateMatching, + updateToLatest: importer.updateToLatest, prefix: importer.rootDir, supportedArchitectures: opts.supportedArchitectures, - updateToLatest: opts.updateToLatest, } return { updatePackageManifest: importer.updatePackageManifest, diff --git a/pnpm/test/monorepo/dedupePeers.test.ts b/pnpm/test/monorepo/dedupePeers.test.ts index 4d72e5ba3c..8c1e377533 100644 --- a/pnpm/test/monorepo/dedupePeers.test.ts +++ b/pnpm/test/monorepo/dedupePeers.test.ts @@ -91,6 +91,58 @@ auto-install-peers=false`, 'utf8') expect(loadJsonFile('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('project-1/package.json').dependencies['@pnpm.e2e/foo']).toBe('1.0.0') // eslint-disable-line + expect(loadJsonFile('project-1/package.json').dependencies['@pnpm.e2e/bar']).toBe('100.0.0') // eslint-disable-line + expect(loadJsonFile('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(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' })