fix(run): infinite recursion

A recursive run should not rerun the same package script which started the lifecycle event.

For instance, let's say one of the workspace projects has the following script:

```json
"scripts": {
  "build": "pnpm run -r build"
}
```

Running `pnpm run build` in this project should not start an infinite recursion.
`pnpm run -r build` in this case should run `build` in all the workspace projects except the one that started the build.

Related issue: #2528
This commit is contained in:
Zoltan Kochan
2020-05-30 16:28:03 +03:00
committed by Zoltan Kochan
parent c56438567b
commit 8094b2a628
7 changed files with 96 additions and 6 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/lifecycle": minor
---
Run lifecycle scripts with the PNPM_SCRIPT_SRC_DIR env variable set. This new env variable contains the directory of the package.json file that contains the executed lifecycle script.

View File

@@ -0,0 +1,18 @@
---
"@pnpm/plugin-commands-script-runners": patch
---
A recursive run should not rerun the same package script which started the lifecycle event.
For instance, let's say one of the workspace projects has the following script:
```json
"scripts": {
"build": "pnpm run -r build"
}
```
Running `pnpm run build` in this project should not start an infinite recursion.
`pnpm run -r build` in this case should run `build` in all the workspace projects except the one that started the build.
Related issue: #2528

View File

@@ -38,7 +38,7 @@
"@pnpm/core-loggers": "workspace:4.0.2",
"@pnpm/read-package-json": "workspace:3.1.1",
"@pnpm/types": "workspace:6.0.0",
"@zkochan/npm-lifecycle": "3.1.4",
"@zkochan/npm-lifecycle": "3.2.0",
"path-exists": "4.0.0",
"run-groups": "2.0.3"
},

View File

@@ -48,6 +48,7 @@ export default async function runLifecycleHook (
config: opts.rawConfig,
dir: opts.rootModulesDir,
extraBinPaths: opts.extraBinPaths || [],
extraEnv: { PNPM_SCRIPT_SRC_DIR: opts.pkgRoot },
log: {
clearProgress: noop,
info: noop,

View File

@@ -46,7 +46,11 @@ export default async (
await Promise.all(chunk.map((prefix: string) =>
limitRun(async () => {
const pkg = opts.selectedProjectsGraph[prefix]
if (!pkg.package.manifest.scripts || !pkg.package.manifest.scripts[scriptName]) {
if (
!pkg.package.manifest.scripts?.[scriptName] ||
process.env.npm_lifecycle_event === scriptName &&
process.env.PNPM_SCRIPT_SRC_DIR === prefix
) {
return
}
hasCommand++

View File

@@ -11,6 +11,8 @@ import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS, REGISTRY } from './utils'
const pnpmBin = path.join(__dirname, '../../pnpm/bin/pnpm.js')
test('pnpm recursive run', async (t) => {
const projects = preparePackages(t, [
{
@@ -592,3 +594,63 @@ test('`pnpm recursive run` should always trust the scripts', async (t) => {
t.deepEqual(outputs, ['project'])
t.end()
})
test('`pnpm run -r` should avoid infinite recursion', async (t) => {
preparePackages(t, [
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: `node ${pnpmBin} run -r build`,
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'json-append': '1',
},
scripts: {
build: `node -e "process.stdout.write('project-2')" | json-append ../output1.json`,
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'json-append': '1',
},
scripts: {
build: `node -e "process.stdout.write('project-3')" | json-append ../output2.json`,
},
},
])
await writeYamlFile('pnpm-workspace.yaml', {})
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
const { allProjects, selectedProjectsGraph } = await readProjects(process.cwd(), [{ namePattern: 'project-1' }])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: path.resolve('project-1'),
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
const outputs1 = await import(path.resolve('output1.json')) as string[]
const outputs2 = await import(path.resolve('output2.json')) as string[]
t.deepEqual(outputs1, ['project-2'])
t.deepEqual(outputs2, ['project-3'])
t.end()
})

8
pnpm-lock.yaml generated
View File

@@ -733,7 +733,7 @@ importers:
'@pnpm/core-loggers': 'link:../core-loggers'
'@pnpm/read-package-json': 'link:../read-package-json'
'@pnpm/types': 'link:../types'
'@zkochan/npm-lifecycle': 3.1.4
'@zkochan/npm-lifecycle': 3.2.0
path-exists: 4.0.0
run-groups: 2.0.3
devDependencies:
@@ -749,7 +749,7 @@ importers:
'@pnpm/read-package-json': 'workspace:3.1.1'
'@pnpm/types': 'workspace:6.0.0'
'@types/rimraf': ^3.0.0
'@zkochan/npm-lifecycle': 3.1.4
'@zkochan/npm-lifecycle': 3.2.0
json-append: 1.1.1
load-json-file: 6.2.0
path-exists: 4.0.0
@@ -3908,7 +3908,7 @@ packages:
node: '>=10'
resolution:
integrity: sha512-RMFanFCfD7KSqokE8DZV9Vx/WCqxp5Zfvco2oIBPv9PPa01Z61Gy6VwFxTNmszUWQpaeNvdZBJFdjtFcXUq8GA==
/@zkochan/npm-lifecycle/3.1.4:
/@zkochan/npm-lifecycle/3.2.0:
dependencies:
byline: 5.0.0
graceful-fs: 4.2.4
@@ -3922,7 +3922,7 @@ packages:
engines:
node: '>=8.15'
resolution:
integrity: sha512-s+Uk93fCpRRNWmiG5RDH7N81TIgQEsokCChy7e/Wcq0fB593eUreIo2U+DkKnMRBqJh8NLJxsJ7HNPw5HMyw2A==
integrity: sha512-YdcFbrJ5n0P2/1XMEVa3rOdiSKFo2DbVDNiZOyD008uTdkqit+eKEyjJIoYBXTLUeT/QC0nXSqW4W4trrb+yCg==
/@zkochan/npm-package-arg/1.0.2:
dependencies:
hosted-git-info: 2.8.8