From 3a1a1385d8418c7d06f0c48c212a0e056a2bdc88 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 30 Apr 2023 11:50:25 +0300 Subject: [PATCH] fix: linking bins of local deps, when node-linker is hoisted (#6488) close #6486 --- .changeset/hot-buttons-train.md | 6 ++ .../core/test/hoistedNodeLinker/install.ts | 68 ++++++++++++++++++- pkg-manager/headless/src/index.ts | 2 +- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 .changeset/hot-buttons-train.md diff --git a/.changeset/hot-buttons-train.md b/.changeset/hot-buttons-train.md new file mode 100644 index 00000000000..e4e9e76feed --- /dev/null +++ b/.changeset/hot-buttons-train.md @@ -0,0 +1,6 @@ +--- +"@pnpm/headless": patch +"pnpm": patch +--- + +Link the bin files of local workspace dependencies, when `node-linker` is set to `hoisted` [6486](https://github.com/pnpm/pnpm/issues/6486). diff --git a/pkg-manager/core/test/hoistedNodeLinker/install.ts b/pkg-manager/core/test/hoistedNodeLinker/install.ts index 1f3054488bd..7f63bf792d9 100644 --- a/pkg-manager/core/test/hoistedNodeLinker/install.ts +++ b/pkg-manager/core/test/hoistedNodeLinker/install.ts @@ -1,7 +1,7 @@ import fs from 'fs' import path from 'path' import { addDependenciesToPackage, install, mutateModules, mutateModulesInSingleProject } from '@pnpm/core' -import { prepareEmpty } from '@pnpm/prepare' +import { prepareEmpty, preparePackages } from '@pnpm/prepare' import { addDistTag } from '@pnpm/registry-mock' import rimraf from '@zkochan/rimraf' import { sync as loadJsonFile } from 'load-json-file' @@ -250,3 +250,69 @@ test('externalDependencies should prevent package from being hoisted to the root expect(fs.existsSync('node_modules/ms')).toBeFalsy() expect(fs.existsSync('node_modules/send/node_modules/ms')).toBeTruthy() }) + +test('linking bins of local projects when node-linker is set to hoisted', async () => { + const project1Manifest = { + name: 'project-1', + version: '1.0.0', + + dependencies: { + 'project-2': 'workspace:*', + }, + } + const project2Manifest = { + name: 'project-2', + version: '1.0.0', + bin: { + 'project-2': 'index.js', + }, + } + preparePackages([ + project1Manifest, + project2Manifest, + ]) + fs.writeFileSync('project-2/index.js', '#!/usr/bin/env node\nconsole.log("hello")', 'utf8') + + const workspacePackages = { + 'project-1': { + '1.0.0': { + dir: path.resolve('project-1'), + manifest: project1Manifest, + }, + }, + 'project-2': { + '1.0.0': { + dir: path.resolve('project-2'), + manifest: project2Manifest, + }, + }, + } + + await mutateModules([ + { + mutation: 'install', + rootDir: path.resolve('project-1'), + }, + { + mutation: 'install', + rootDir: path.resolve('project-2'), + }, + ], await testDefaults({ + allProjects: [ + { + buildIndex: 0, + manifest: project1Manifest, + rootDir: path.resolve('project-1'), + }, + { + buildIndex: 1, + manifest: project2Manifest, + rootDir: path.resolve('project-2'), + }, + ], + nodeLinker: 'hoisted', + workspacePackages, + })) + + expect(fs.existsSync('project-1/node_modules/.bin/project-2')).toBeTruthy() +}) diff --git a/pkg-manager/headless/src/index.ts b/pkg-manager/headless/src/index.ts index 0d2f61c2e9e..8b53ea6698b 100644 --- a/pkg-manager/headless/src/index.ts +++ b/pkg-manager/headless/src/index.ts @@ -516,7 +516,7 @@ export async function headlessInstall (opts: HeadlessOptions) { /** Skip linking and due to no project manifest */ if (!opts.ignorePackageManifest) { await Promise.all(selectedProjects.map(async (project) => { - if (opts.publicHoistPattern?.length && path.relative(opts.lockfileDir, project.rootDir) === '') { + if (opts.nodeLinker === 'hoisted' || opts.publicHoistPattern?.length && path.relative(opts.lockfileDir, project.rootDir) === '') { await linkBinsOfImporter(project, { extraNodePaths: opts.extraNodePaths, preferSymlinkedExecutables: opts.preferSymlinkedExecutables,