Files
pnpm/exec/plugin-commands-script-runners/test/runRecursive.ts
Zoltan Kochan 3a5bfaa94f chore: update zkochan packages to latest versions (#10930)
Update all packages from zkochan/packages to their latest major versions
and exclude them from minimumReleaseAge requirement. This includes
updating catalog entries, adapting to breaking API changes (default
exports replaced with named exports, sync functions renamed with Sync
suffix), and updating type declarations.
2026-03-11 13:47:46 +01:00

1100 lines
29 KiB
TypeScript

import fs from 'fs'
import path from 'path'
import { preparePackages } from '@pnpm/prepare'
import { run } from '@pnpm/plugin-commands-script-runners'
import { filterPkgsBySelectorObjects } from '@pnpm/filter-workspace-packages'
import { filterPackagesFromDir } from '@pnpm/workspace.filter-packages-from-dir'
import type { PnpmError } from '@pnpm/error'
import { createTestIpcServer } from '@pnpm/test-ipc-server'
import { safeExeca as execa } from 'execa'
import { writeYamlFileSync } from 'write-yaml-file'
import { DEFAULT_OPTS, REGISTRY_URL } from './utils/index.js'
const pnpmBin = path.join(import.meta.dirname, '../../../pnpm/bin/pnpm.mjs')
test('pnpm recursive run', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: `${server1.sendLineScript('project-1')} && ${server2.sendLineScript('project-1')}`,
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server1.sendLineScript('project-2'),
postbuild: server1.sendLineScript('project-2-postbuild'),
prebuild: server1.sendLineScript('project-2-prebuild'),
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server2.sendLineScript('project-3'),
},
},
{
name: 'project-0',
version: '1.0.0',
dependencies: {},
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
expect(server1.getLines()).toStrictEqual(['project-1', 'project-2'])
expect(server2.getLines()).toStrictEqual(['project-1', 'project-3'])
})
test('pnpm recursive run with enable-pre-post-scripts', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: `${server1.sendLineScript('project-1')} && ${server2.sendLineScript('project-1')}`,
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server1.sendLineScript('project-2'),
postbuild: server1.sendLineScript('project-2-postbuild'),
prebuild: server1.sendLineScript('project-2-prebuild'),
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server2.sendLineScript('project-3'),
},
},
{
name: 'project-0',
version: '1.0.0',
dependencies: {},
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
enablePrePostScripts: true,
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
expect(server1.getLines()).toStrictEqual(['project-1', 'project-2-prebuild', 'project-2', 'project-2-postbuild'])
expect(server2.getLines()).toStrictEqual(['project-1', 'project-3'])
})
test('pnpm recursive run reversed', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: `${server1.sendLineScript('project-1')} && ${server2.sendLineScript('project-1')}`,
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server1.sendLineScript('project-2'),
postbuild: server1.sendLineScript('project-2-postbuild'),
prebuild: server1.sendLineScript('project-2-prebuild'),
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server2.sendLineScript('project-3'),
},
},
{
name: 'project-0',
version: '1.0.0',
dependencies: {},
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
reverse: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
expect(server1.getLines()).toStrictEqual(['project-2', 'project-1'])
expect(server2.getLines()).toStrictEqual(['project-3', 'project-1'])
})
test('pnpm recursive run concurrently', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: `node -e "let i = 20;setInterval(() => {if (!--i) process.exit(0); console.log(Date.now());},50)" | ${server1.generateSendStdinScript()}`,
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: `node -e "let i = 40;setInterval(() => {if (!--i) process.exit(0); console.log(Date.now());},25)" | ${server2.generateSendStdinScript()}`,
},
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
const outputs1 = server1.getLines().map(x => Number.parseInt(x))
const outputs2 = server2.getLines().map(x => Number.parseInt(x))
expect(Math.max(outputs1[0], outputs2[0]) < Math.min(outputs1[outputs1.length - 1], outputs2[outputs2.length - 1])).toBeTruthy()
})
test('`pnpm recursive run` fails when run without filters and no package has the desired command, unless if-present is set', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-0',
version: '1.0.0',
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
console.log('recursive run does not fail when if-present is true')
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
ifPresent: true,
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
let err!: PnpmError
try {
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
} catch (_err: any) { // eslint-disable-line
err = _err
}
expect(err.code).toBe('ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT')
})
test('`pnpm recursive run` fails when run with a filter that includes all packages and no package has the desired command, unless if-present is set', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-0',
version: '1.0.0',
},
])
console.log('recursive run does not fail when if-present is true')
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
ifPresent: true,
recursive: true,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
let err!: PnpmError
try {
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
} catch (_err: any) { // eslint-disable-line
err = _err
}
expect(err.code).toBe('ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT')
})
test('`pnpm recursive run` fails when run against a subset of packages and no package has the desired command, unless if-present is set', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-0',
version: '1.0.0',
},
])
const { allProjects } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
const { selectedProjectsGraph } = await filterPkgsBySelectorObjects(
allProjects,
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() }
)
// Recursive run does not fail when if-present is true
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
ifPresent: true,
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
await expect(
run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['this-command-does-not-exist'])
).rejects.toThrow(/None of the selected packages has a/)
})
test('"pnpm run --filter <pkg>" without specifying the script name', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
foo: 'echo hi',
test: 'ts-node test',
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
{
name: 'project-0',
version: '1.0.0',
},
])
const { allProjects } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
console.log('prints the list of available commands if a single project is selected')
{
const { selectedProjectsGraph } = await filterPkgsBySelectorObjects(
allProjects,
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() }
)
const output = await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, [])
expect(output).toBe(`\
Lifecycle scripts:
test
ts-node test
Commands available via "pnpm run":
foo
echo hi`)
}
console.log('throws an error if several projects are selected')
{
const { selectedProjectsGraph } = await filterPkgsBySelectorObjects(
allProjects,
[{ includeDependents: true, namePattern: 'project-1' }],
{ workspaceDir: process.cwd() }
)
let err!: PnpmError
try {
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, [])
} catch (_err: any) { // eslint-disable-line
err = _err
}
expect(err).toBeTruthy()
expect(err.code).toBe('ERR_PNPM_SCRIPT_NAME_IS_REQUIRED')
expect(err.message).toBe('You must specify the script you want to run')
}
})
test('testing the bail config with "pnpm recursive run"', async () => {
await using server = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: server.sendLineScript('project-1'),
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: `exit 1 && ${server.sendLineScript('project-2')}`,
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server.sendLineScript('project-3'),
},
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
let err1!: PnpmError
try {
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
bail: false,
}, ['build'])
} catch (_err: any) { // eslint-disable-line
err1 = _err
}
expect(err1.code).toBe('ERR_PNPM_RECURSIVE_FAIL')
expect(server.getLines()).toStrictEqual(['project-1', 'project-3'])
let err2!: PnpmError
try {
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
} catch (_err: any) { // eslint-disable-line
err2 = _err
}
expect(err2.code).toBe('ERR_PNPM_RECURSIVE_FAIL')
})
test('pnpm recursive run with filtering', async () => {
await using server = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: server.sendLineScript('project-1'),
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
scripts: {
build: server.sendLineScript('project-2'),
postbuild: server.sendLineScript('project-2-postbuild'),
prebuild: server.sendLineScript('project-2-prebuild'),
},
},
])
const { allProjects } = await filterPackagesFromDir(process.cwd(), [])
const { selectedProjectsGraph } = await filterPkgsBySelectorObjects(
allProjects,
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() }
)
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
expect(server.getLines()).toStrictEqual(['project-1'])
})
test('`pnpm recursive run` should always trust the scripts', async () => {
await using server = await createTestIpcServer()
preparePackages([
{
name: 'project',
version: '1.0.0',
scripts: {
build: server.sendLineScript('project'),
},
},
])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
process.env['npm_config_unsafe_perm'] = 'false'
await run.handler({
...DEFAULT_OPTS,
dir: process.cwd(),
recursive: true,
workspaceDir: process.cwd(),
...await filterPackagesFromDir(process.cwd(), []),
}, ['build'])
delete process.env.npm_config_unsafe_perm
expect(server.getLines()).toStrictEqual(['project'])
})
test('`pnpm run -r` should avoid infinite recursion', async () => {
await using server1 = await createTestIpcServer()
await using server2 = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: `node ${pnpmBin} run -r build`,
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: server1.sendLineScript('project-2'),
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: server2.sendLineScript('project-3'),
},
},
])
writeYamlFileSync('pnpm-workspace.yaml', {
packages: ['**'],
})
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [{ namePattern: 'project-1' }])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: path.resolve('project-1'),
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
expect(server1.getLines()).toStrictEqual(['project-2'])
expect(server2.getLines()).toStrictEqual(['project-3'])
})
test('`pnpm recursive run` should fail when no script in package with requiredScripts', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'echo 2',
},
dependencies: {
'project-1': '1',
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'project-1': '1',
},
},
])
let err!: PnpmError
try {
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
requiredScripts: ['build'],
rootProjectManifest: {
name: 'test-workspaces',
private: true,
},
workspaceDir: process.cwd(),
}, ['build'])
} catch (_err: any) { // eslint-disable-line
err = _err
}
expect(err.message).toContain('Missing script "build" in packages: project-1, project-3')
expect(err.code).toBe('ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT')
})
test('`pnpm -r --resume-from run` should executed from given package', async () => {
await using server = await createTestIpcServer()
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: server.sendLineScript('project-1'),
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: server.sendLineScript('project-2'),
},
dependencies: {
'project-1': '1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: server.sendLineScript('project-3'),
},
dependencies: {
'project-1': '1',
},
},
])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
resumeFrom: 'project-3',
workspaceDir: process.cwd(),
}, ['build'])
expect(server.getLines().sort()).toEqual(['project-2', 'project-3'])
})
test('pnpm run with RegExp script selector should work on recursive', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
'build:a': 'node -e "require(\'fs\').writeFileSync(\'../output-build-1-a.txt\', \'1-a\', \'utf8\')"',
'build:b': 'node -e "require(\'fs\').writeFileSync(\'../output-build-1-b.txt\', \'1-b\', \'utf8\')"',
'build:c': 'node -e "require(\'fs\').writeFileSync(\'../output-build-1-c.txt\', \'1-c\', \'utf8\')"',
build: 'node -e "require(\'fs\').writeFileSync(\'../output-build-1-a.txt\', \'should not run\', \'utf8\')"',
'lint:a': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-1-a.txt\', \'1-a\', \'utf8\')"',
'lint:b': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-1-b.txt\', \'1-b\', \'utf8\')"',
'lint:c': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-1-c.txt\', \'1-c\', \'utf8\')"',
lint: 'node -e "require(\'fs\').writeFileSync(\'../output-lint-1-a.txt\', \'should not run\', \'utf8\')"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
'build:a': 'node -e "require(\'fs\').writeFileSync(\'../output-build-2-a.txt\', \'2-a\', \'utf8\')"',
'build:b': 'node -e "require(\'fs\').writeFileSync(\'../output-build-2-b.txt\', \'2-b\', \'utf8\')"',
'build:c': 'node -e "require(\'fs\').writeFileSync(\'../output-build-2-c.txt\', \'2-c\', \'utf8\')"',
build: 'node -e "require(\'fs\').writeFileSync(\'../output-build-2-a.txt\', \'should not run\', \'utf8\')"',
'lint:a': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-2-a.txt\', \'2-a\', \'utf8\')"',
'lint:b': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-2-b.txt\', \'2-b\', \'utf8\')"',
'lint:c': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-2-c.txt\', \'2-c\', \'utf8\')"',
lint: 'node -e "require(\'fs\').writeFileSync(\'../output-lint-2-a.txt\', \'should not run\', \'utf8\')"',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
'build:a': 'node -e "require(\'fs\').writeFileSync(\'../output-build-3-a.txt\', \'3-a\', \'utf8\')"',
'build:b': 'node -e "require(\'fs\').writeFileSync(\'../output-build-3-b.txt\', \'3-b\', \'utf8\')"',
'build:c': 'node -e "require(\'fs\').writeFileSync(\'../output-build-3-c.txt\', \'3-c\', \'utf8\')"',
build: 'node -e "require(\'fs\').writeFileSync(\'../output-build-3-a.txt\', \'should not run\', \'utf8\')"',
'lint:a': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-3-a.txt\', \'3-a\', \'utf8\')"',
'lint:b': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-3-b.txt\', \'3-b\', \'utf8\')"',
'lint:c': 'node -e "require(\'fs\').writeFileSync(\'../output-lint-3-c.txt\', \'3-c\', \'utf8\')"',
lint: 'node -e "require(\'fs\').writeFileSync(\'../output-lint-3-a.txt\', \'should not run\', \'utf8\')"',
},
},
])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY_URL,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
rootProjectManifest: {
name: 'test-workspaces',
private: true,
},
workspaceDir: process.cwd(),
}, ['/^(lint|build):.*/'])
expect(fs.readFileSync('output-build-1-a.txt', { encoding: 'utf-8' })).toBe('1-a')
expect(fs.readFileSync('output-build-1-b.txt', { encoding: 'utf-8' })).toBe('1-b')
expect(fs.readFileSync('output-build-1-c.txt', { encoding: 'utf-8' })).toBe('1-c')
expect(fs.readFileSync('output-build-2-a.txt', { encoding: 'utf-8' })).toBe('2-a')
expect(fs.readFileSync('output-build-2-b.txt', { encoding: 'utf-8' })).toBe('2-b')
expect(fs.readFileSync('output-build-2-c.txt', { encoding: 'utf-8' })).toBe('2-c')
expect(fs.readFileSync('output-build-3-a.txt', { encoding: 'utf-8' })).toBe('3-a')
expect(fs.readFileSync('output-build-3-b.txt', { encoding: 'utf-8' })).toBe('3-b')
expect(fs.readFileSync('output-build-3-c.txt', { encoding: 'utf-8' })).toBe('3-c')
expect(fs.readFileSync('output-lint-1-a.txt', { encoding: 'utf-8' })).toBe('1-a')
expect(fs.readFileSync('output-lint-1-b.txt', { encoding: 'utf-8' })).toBe('1-b')
expect(fs.readFileSync('output-lint-1-c.txt', { encoding: 'utf-8' })).toBe('1-c')
expect(fs.readFileSync('output-lint-2-a.txt', { encoding: 'utf-8' })).toBe('2-a')
expect(fs.readFileSync('output-lint-2-b.txt', { encoding: 'utf-8' })).toBe('2-b')
expect(fs.readFileSync('output-lint-2-c.txt', { encoding: 'utf-8' })).toBe('2-c')
expect(fs.readFileSync('output-lint-3-a.txt', { encoding: 'utf-8' })).toBe('3-a')
expect(fs.readFileSync('output-lint-3-b.txt', { encoding: 'utf-8' })).toBe('3-b')
expect(fs.readFileSync('output-lint-3-c.txt', { encoding: 'utf-8' })).toBe('3-c')
})
test('pnpm recursive run report summary', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-1\'), 1000)"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-3\'), 1000)"',
},
},
{
name: 'project-4',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-5',
version: '1.0.0',
},
])
let error
try {
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
reportSummary: true,
workspaceDir: process.cwd(),
}, ['build'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error.code).toBe('ERR_PNPM_RECURSIVE_FAIL')
const { default: { executionStatus } } = (await import(path.resolve('pnpm-exec-summary.json')))
expect(executionStatus[path.resolve('project-1')].status).toBe('passed')
expect(executionStatus[path.resolve('project-1')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-2')].status).toBe('failure')
expect(executionStatus[path.resolve('project-2')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-3')].status).toBe('passed')
expect(executionStatus[path.resolve('project-3')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-4')].status).toBe('failure')
expect(executionStatus[path.resolve('project-4')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-5')].status).toBe('skipped')
})
test('pnpm recursive run report summary with --bail', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-1\'), 1000)"',
},
},
{
name: 'project-2',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-3',
version: '1.0.0',
scripts: {
build: 'node -e "setTimeout(() => console.log(\'project-3\'), 1000)"',
},
},
{
name: 'project-4',
version: '1.0.0',
scripts: {
build: 'exit 1',
},
},
{
name: 'project-5',
version: '1.0.0',
},
])
let error
try {
await run.handler({
...DEFAULT_OPTS,
...await filterPackagesFromDir(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
reportSummary: true,
workspaceDir: process.cwd(),
bail: true,
workspaceConcurrency: 3,
}, ['build'])
} catch (err: any) { // eslint-disable-line
error = err
}
expect(error.code).toBe('ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL')
const { default: { executionStatus } } = (await import(path.resolve('pnpm-exec-summary.json')))
expect(executionStatus[path.resolve('project-1')].status).toBe('running')
expect(executionStatus[path.resolve('project-2')].status).toBe('failure')
expect(executionStatus[path.resolve('project-2')].duration).not.toBeFalsy()
expect(executionStatus[path.resolve('project-3')].status).toBe('running')
expect(executionStatus[path.resolve('project-4')].status).toBe('queued')
expect(executionStatus[path.resolve('project-5')].status).toBe('skipped')
})
test('pnpm recursive run with custom node-options', async () => {
preparePackages([
{
name: 'project-1',
version: '1.0.0',
scripts: {
build: 'node -e "assert.strictEqual(process.env.NODE_OPTIONS, \'--max-old-space-size=1200\')"',
},
},
])
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
await run.handler({
...DEFAULT_OPTS,
allProjects,
dir: process.cwd(),
nodeOptions: '--max-old-space-size=1200',
recursive: true,
selectedProjectsGraph,
workspaceDir: process.cwd(),
}, ['build'])
})