Skip to content

Commit

Permalink
fix(dlx): pnpm dlx should work with git-hosted pkgs
Browse files Browse the repository at this point in the history
close #4714
  • Loading branch information
zkochan committed May 11, 2022
1 parent 0bdf6ba commit 7762f39
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .changeset/fifty-taxis-exist.md
@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-script-runners": patch
"pnpm": patch
---

`pnpm dlx` should work with git-hosted packages. For example: `pnpm dlx gengjiawen/envinfo` [#4714](https://github.com/pnpm/pnpm/issues/4714).
13 changes: 6 additions & 7 deletions packages/plugin-commands-script-runners/src/dlx.ts
Expand Up @@ -77,13 +77,18 @@ export async function handler (
}, pkgs)
const binName = opts.package
? command
: await getBinName(modulesDir, versionless(command))
: await getBinName(modulesDir, await getPkgName(prefix))
await execa(binName, args, {
env,
stdio: 'inherit',
})
}

async function getPkgName (pkgDir: string) {
const manifest = await readPkgFromDir(pkgDir)
return Object.keys(manifest.dependencies ?? {})[0]
}

async function getBinName (modulesDir: string, pkgName: string): Promise<string> {
const pkgDir = path.join(modulesDir, pkgName)
const manifest = await readPkgFromDir(pkgDir)
Expand Down Expand Up @@ -112,12 +117,6 @@ function scopeless (pkgName: string) {
return pkgName
}

function versionless (pkgName: string) {
const index = pkgName.indexOf('@', 1)
if (index === -1) return pkgName
return pkgName.substring(0, index)
}

async function getDlxDir (
opts: {
dir: string
Expand Down
30 changes: 24 additions & 6 deletions packages/plugin-commands-script-runners/test/dlx.e2e.ts
@@ -1,4 +1,5 @@
import fs from 'fs'
import path from 'path'
import { dlx } from '@pnpm/plugin-commands-script-runners'
import { prepareEmpty } from '@pnpm/prepare'
import { DLX_DEFAULT_OPTS as DEFAULT_OPTS } from './utils'
Expand All @@ -8,18 +9,31 @@ test('dlx', async () => {

await dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
}, ['shx', 'touch', 'foo'])

expect(fs.existsSync('foo')).toBeTruthy()
})

test('dlx should work when the package name differs from the bin name', async () => {
test('dlx install from git', async () => {
prepareEmpty()

await dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
}, ['shelljs/shx#61aca968cd7afc712ca61a4fc4ec3201e3770dc7', 'touch', 'foo'])

expect(fs.existsSync('foo')).toBeTruthy()
})

test('dlx should work when the package name differs from the bin name', async () => {
prepareEmpty()

await dlx.handler({
...DEFAULT_OPTS,
dir: path.resolve('project'),
storeDir: path.resolve('store'),
}, ['touch-file-one-bin'])

expect(fs.existsSync('touch.txt')).toBeTruthy()
Expand All @@ -31,7 +45,8 @@ test('dlx should fail when the installed package has many commands and none equa
await expect(
dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
}, ['touch-file-many-bins'])
).rejects.toThrow('Could not determine executable to run. touch-file-many-bins has multiple binaries: t, tt')
})
Expand All @@ -41,7 +56,8 @@ test('dlx should not fail when the installed package has many commands and one e

await dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
}, ['touch-file-good-bin-name'])

expect(fs.existsSync('touch.txt')).toBeTruthy()
Expand All @@ -52,7 +68,8 @@ test('dlx --package <pkg1> [--package <pkg2>]', async () => {

await dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
package: [
'zkochan/for-testing-pnpm-dlx',
'is-positive',
Expand All @@ -68,7 +85,8 @@ test('dlx should fail when the package has no bins', async () => {
await expect(
dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
}, ['is-positive'])
).rejects.toThrow(/No binaries found in is-positive/)
})
7 changes: 5 additions & 2 deletions packages/plugin-commands-script-runners/test/dlx.ts
@@ -1,3 +1,4 @@
import path from 'path'
import execa from 'execa'
import { dlx } from '@pnpm/plugin-commands-script-runners'
import { prepareEmpty } from '@pnpm/prepare'
Expand All @@ -13,7 +14,8 @@ test('dlx should work with scoped packages', async () => {

await dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
userAgent,
}, ['@foo/touch-file-one-bin'])

Expand All @@ -29,7 +31,8 @@ test('dlx should work with versioned packages', async () => {

await dlx.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
dir: path.resolve('project'),
storeDir: path.resolve('store'),
}, ['@foo/touch-file-one-bin@latest'])

expect(execa).toBeCalledWith('touch-file-one-bin', [], expect.anything())
Expand Down

0 comments on commit 7762f39

Please sign in to comment.