From 837078f92eb0bdc2cfaf1cb144af5cd61d29fe94 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Wed, 19 Apr 2023 02:34:50 +0300 Subject: [PATCH] fix(headless): don't add links to the lockfile when excludeLinksFromLockfile is enabled (#6427) --- .changeset/silly-spoons-warn.md | 5 ++ .../test/install/excludeLinksFromLockfile.ts | 54 ++++++++++++++++++- pkg-manager/headless/src/index.ts | 15 +++--- 3 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 .changeset/silly-spoons-warn.md diff --git a/.changeset/silly-spoons-warn.md b/.changeset/silly-spoons-warn.md new file mode 100644 index 0000000000..16eb83ca58 --- /dev/null +++ b/.changeset/silly-spoons-warn.md @@ -0,0 +1,5 @@ +--- +"@pnpm/headless": patch +--- + +Don't add links to the lockfile on repeat install, when excludeLinksFromLockfile is enabled. diff --git a/pkg-manager/core/test/install/excludeLinksFromLockfile.ts b/pkg-manager/core/test/install/excludeLinksFromLockfile.ts index b5845c0d30..d1e90b0762 100644 --- a/pkg-manager/core/test/install/excludeLinksFromLockfile.ts +++ b/pkg-manager/core/test/install/excludeLinksFromLockfile.ts @@ -8,7 +8,7 @@ import { type MutatedProject, type ProjectOptions, } from '@pnpm/core' -import { type LockfileV6 } from '@pnpm/lockfile-types' +import { type Lockfile, type LockfileV6 } from '@pnpm/lockfile-types' import { prepareEmpty, preparePackages, tempDir } from '@pnpm/prepare' import { fixtures } from '@pnpm/test-fixtures' import rimraf from '@zkochan/rimraf' @@ -159,3 +159,55 @@ test('hoisted install should not fail with excludeLinksFromLockfile true', async const m = project.requireModule('local-pkg') expect(m).toBeTruthy() }) + +test('update the lockfile when a new project is added to the workspace but do not add external links', async () => { + preparePackages([ + { + location: 'project-1', + package: { name: 'project-1' }, + }, + ]) + const absolutePath = path.resolve('..', 'local-pkg') + f.copy('local-pkg', absolutePath) + + const importers: MutatedProject[] = [ + { + mutation: 'install', + rootDir: path.resolve('project-1'), + }, + ] + const allProjects: ProjectOptions[] = [ + { + buildIndex: 0, + manifest: { + name: 'project-1', + version: '1.0.0', + + dependencies: { + 'is-positive': '1.0.0', + 'local-pkg': `link:${normalizePath(absolutePath)}`, + }, + }, + rootDir: path.resolve('project-1'), + }, + ] + await mutateModules(importers, await testDefaults({ allProjects, excludeLinksFromLockfile: true })) + + importers.push({ + mutation: 'install', + rootDir: path.resolve('project-2'), + }) + allProjects.push({ + buildIndex: 0, + manifest: { + name: 'project-2', + version: '1.0.0', + }, + rootDir: path.resolve('project-2'), + }) + await mutateModules(importers, await testDefaults({ allProjects, excludeLinksFromLockfile: true, frozenLockfile: true })) + + const lockfile: Lockfile = await readYamlFile(WANTED_LOCKFILE) + expect(Object.keys(lockfile.importers)).toStrictEqual(['project-1', 'project-2']) + expect(Object.keys(lockfile.importers['project-1'].dependencies ?? {})).toStrictEqual(['is-positive']) +}) diff --git a/pkg-manager/headless/src/index.ts b/pkg-manager/headless/src/index.ts index 7282252faf..90b959f579 100644 --- a/pkg-manager/headless/src/index.ts +++ b/pkg-manager/headless/src/index.ts @@ -269,13 +269,14 @@ export async function headlessInstall (opts: HeadlessOptions) { for (const { id, manifest } of selectedProjects) { if (filteredLockfile.importers[id]) { for (const depType of DEPENDENCIES_FIELDS) { - for (const [depName, spec] of Object.entries(manifest[depType] ?? {})) { - if (spec.startsWith('link:')) { - if (!filteredLockfile.importers[id][depType]) { - filteredLockfile.importers[id][depType] = {} - } - filteredLockfile.importers[id][depType]![depName] = `link:${path.relative(opts.lockfileDir, spec.substring(5))}` - } + filteredLockfile.importers[id][depType] = { + ...filteredLockfile.importers[id][depType], + ...Object.entries(manifest[depType] ?? {}) + .filter(([_, spec]) => spec.startsWith('link:')) + .reduce((acc, [depName, spec]) => { + acc[depName] = `link:${path.relative(opts.lockfileDir, spec.substring(5))}` + return acc + }, {} as Record), } } }