Skip to content

Commit 71c6848

Browse files
authored
fix(exec): npx to run specified version if multiple version exist globally (#7587)
When multiple version of the same package is exist globally either at top level or at any level as a sub dependency, even though the version specified does not exist at top level it was running top level bin since it matches the bin name. This fixes checks for depth of the found node along with already existing specs checks. Fixes: #7486
1 parent 93883bb commit 71c6848

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

Diff for: workspaces/libnpmexec/lib/index.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const getManifest = async (spec, flatOptions) => {
3232

3333
// Returns the required manifest if the spec is missing from the tree
3434
// Returns the found node if it is in the tree
35-
const missingFromTree = async ({ spec, tree, flatOptions, isNpxTree }) => {
35+
const missingFromTree = async ({ spec, tree, flatOptions, isNpxTree, shallow }) => {
3636
// If asking for a spec by name only (spec.raw === spec.name):
3737
// - In local or global mode go with anything in the tree that matches
3838
// - If looking in the npx cache check if a newer version is available
@@ -41,6 +41,10 @@ const missingFromTree = async ({ spec, tree, flatOptions, isNpxTree }) => {
4141
// registry spec that is not a specific tag.
4242
const nodesBySpec = tree.inventory.query('packageName', spec.name)
4343
for (const node of nodesBySpec) {
44+
// continue if node is not a top level node
45+
if (shallow && node.depth) {
46+
continue
47+
}
4448
if (spec.rawSpec === '*') {
4549
return { node }
4650
}
@@ -202,7 +206,7 @@ const exec = async (opts) => {
202206
const globalArb = new Arborist({ ...flatOptions, path: globalPath, global: true })
203207
const globalTree = await globalArb.loadActual()
204208
const { manifest: globalManifest } =
205-
await missingFromTree({ spec, tree: globalTree, flatOptions })
209+
await missingFromTree({ spec, tree: globalTree, flatOptions, shallow: true })
206210
if (!globalManifest && await fileExists(`${globalBin}/${args[0]}`)) {
207211
binPaths.push(globalBin)
208212
return await run()

Diff for: workspaces/libnpmexec/test/registry.js

+62
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,65 @@ t.test('run multiple from registry', async t => {
164164
value: 'packages-2.0.0',
165165
})
166166
})
167+
t.test('packages with different versions in the global tree', async t => {
168+
const pkgA1 = createPkg({
169+
localVersion: '1.0.0',
170+
versions: ['1.0.0', '2.0.0'],
171+
name: '@npmcli/A',
172+
})
173+
174+
const pkgA2 = createPkg({
175+
localVersion: '2.0.0',
176+
name: '@npmcli/A',
177+
versions: ['1.0.0', '2.0.0'],
178+
})
179+
180+
const pkgB = createPkg({
181+
localVersion: '1.0.0',
182+
name: '@npmcli/B',
183+
})
184+
185+
const pkgBfix = merge(pkgB.fixtures, {
186+
node_modules: {
187+
'@npmcli': { B: {
188+
node_modules: {
189+
'@npmcli': {
190+
A: pkgA2.fixtures.packages['@npmcli-A-2.0.0'],
191+
} },
192+
'package.json': { dependencies: { '@npmcli/A': '2.0.0' } },
193+
},
194+
},
195+
} })
196+
197+
const { chmod, exec, readOutput, binLinks, registry, path } = setup(t, {
198+
pkg: [pkgA2.pkg, pkgA1.pkg, pkgB.pkg],
199+
global: true,
200+
testdir: merge(pkgA1.fixtures, pkgBfix),
201+
})
202+
203+
await chmod()
204+
await binLinks()
205+
206+
await pkgA2.package({ registry, path, times: 2, tarballs: ['2.0.0'] })
207+
await pkgA1.package({ registry, path, times: 1, tarballs: [] })
208+
209+
await exec({
210+
args: ['@npmcli/[email protected]'],
211+
})
212+
213+
t.match(await readOutput('@npmcli-A'), {
214+
value: 'packages-2.0.0',
215+
args: [],
216+
created: 'packages/@npmcli-A-2.0.0/bin-file.js',
217+
})
218+
219+
await exec({
220+
args: ['@npmcli/[email protected]'],
221+
})
222+
223+
t.match(await readOutput('@npmcli-A'), {
224+
value: 'local-1.0.0',
225+
args: [],
226+
created: 'global/node_modules/@npmcli/A/bin-file.js',
227+
})
228+
})

0 commit comments

Comments
 (0)