New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support to run multi script commands specified with regex selector #5871
Changes from 21 commits
413fb09
fd2ebe5
25fae54
776dd24
8424515
f256571
b92e3bb
514986f
bd0aef2
b7e6428
7608448
ec8e4ee
bc23e6b
274a076
671a063
3864f03
e140531
f6fe3cf
8a70297
f917b1f
c02be84
4802e46
421a693
7db6957
acf55fd
cbc19e7
0d81ca4
2b337da
67f62a1
d9bd169
46522b3
1485f79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@pnpm/plugin-commands-script-runners": minor | ||
--- | ||
|
||
feat: support wildcard selector to specify multiple scripts to execute" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add more details. This text is going to be on the release page. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4802e46 👍 |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,15 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function tryBuildRegExpFromCommand ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
command: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
): RegExp | null { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (command.length < 3) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (command[0] !== '/' || command.lastIndexOf('/') < 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return new RegExp(command.slice(0, command.lastIndexOf('/')).slice(1)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Support
Suggested change
Ref: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are other flac chalactor to present flag https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags other than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! I have modified the code: // https://github.com/stdlib-js/regexp-regexp/blob/6428051ac9ef7c9d03468b19bdbb1dc6fc2a5509/lib/regexp.js
const isRegExpStr = /^\/((?:\\\/|[^\/])+)\/([dgimuys]*)$/.test(command)
if (!isRegExpStr) {
return null
}
// https://stackoverflow.com/a/874742/6596777
const match = command.match(new RegExp('^/(.*?)/([dgimuys]*)$'))
if (!match) {
return null
}
try {
return new RegExp(match[1], match[2])
} catch {
return null
} Result: console.log(/build:.*/dgimuys.test("build:web")) // true Excess flags do not affect the results. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In what case would regex flags be useful? A regex is already more powerful than it needs to be for this simple task of selecting scripts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, only the We need to discuss what will happen if the user types
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
// https://github.com/stdlib-js/regexp-regexp/blob/6428051ac9ef7c9d03468b19bdbb1dc6fc2a5509/lib/regexp.js
const reRegExp = new RegExp(/^\/((?:\\\/|[^\/])+)\/([dgimuys]*)$/)
const match = command.match(reRegExp)
if (!match) {
return null
}
// if need print warning
if (match[2]) {
logger.warn("not support flags and will ignore")
}
try {
return new RegExp(match[1])
} catch {
return null
}
// https://github.com/stdlib-js/regexp-regexp/blob/6428051ac9ef7c9d03468b19bdbb1dc6fc2a5509/lib/regexp.js
const reRegExp = new RegExp(/^\/((?:\\\/|[^\/])+)\/([dgimuys]*)$/)
const match = command.match(reRegExp)
if (!match) {
return null
}
try {
return new RegExp(match[1], match[2])
} catch {
return null
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd vote for either reporting an error or consider it as script name. Although the second one may be confusing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like to vote for reporting an error or ignoring flag and warning it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd vote for ignoring the flags and warning it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated the |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BlackHole1 marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,4 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import path from 'path' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import pLimit from 'p-limit' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
docsUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
readProjectManifestOnly, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -13,13 +14,14 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
makeNodeRequireOption, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
RunLifecycleHookOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} from '@pnpm/lifecycle' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { ProjectManifest } from '@pnpm/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { PackageScripts, ProjectManifest } from '@pnpm/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import pick from 'ramda/src/pick' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import realpathMissing from 'realpath-missing' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import renderHelp from 'render-help' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { runRecursive, RecursiveRunOpts } from './runRecursive' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { existsInDir } from './existsInDir' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { handler as exec } from './exec' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { tryBuildRegExpFromCommand } from './regexpCommand' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const IF_PRESENT_OPTION = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'if-present': Boolean, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -43,13 +45,21 @@ export const RESUME_FROM_OPTION_HELP = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name: '--resume-from', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const SEQUENTIAL_OPTION_HELP = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
description: 'Run specified scripts one after one.', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Thanks! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
name: '--sequential', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const shorthands = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
parallel: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'--workspace-concurrency=Infinity', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'--no-sort', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'--stream', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'--recursive', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sequential: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'--workspace-concurrency=1', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export function rcOptionsTypes () { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -112,6 +122,7 @@ For options that may be used with `-r`, see "pnpm help recursive"', | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
PARALLEL_OPTION_HELP, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
RESUME_FROM_OPTION_HELP, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...UNIVERSAL_OPTIONS, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
SEQUENTIAL_OPTION_HELP, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
FILTERING, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -159,7 +170,10 @@ export async function handler ( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return printProjectCommands(manifest, rootManifest ?? undefined) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (scriptName !== 'start' && !manifest.scripts?.[scriptName]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const specifiedScripts = getSpecifiedScripts(manifest.scripts ?? {}, scriptName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (specifiedScripts.length < 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (opts.ifPresent) return | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (opts.fallbackCommandUsed) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (opts.argv == null) throw new Error('Could not fallback because opts.argv.original was not passed to the script runner') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -170,9 +184,9 @@ export async function handler ( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (opts.workspaceDir) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { manifest: rootManifest } = await tryReadProjectManifest(opts.workspaceDir, opts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (rootManifest?.scripts?.[scriptName]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (getSpecifiedScripts(rootManifest?.scripts ?? {}, scriptName).length > 0 && specifiedScripts.length < 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new PnpmError('NO_SCRIPT', `Missing script: ${scriptName}`, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hint: `But ${scriptName} is present in the root of the workspace, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
hint: `But script matched with ${scriptName} is present in the root of the workspace, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
so you may run "pnpm -w run ${scriptName}"`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -203,21 +217,11 @@ so you may run "pnpm -w run ${scriptName}"`, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opts.enablePrePostScripts && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
manifest.scripts?.[`pre${scriptName}`] && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!manifest.scripts[scriptName].includes(`pre${scriptName}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await runLifecycleHook(`pre${scriptName}`, manifest, lifecycleOpts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await runLifecycleHook(scriptName, manifest, { ...lifecycleOpts, args: passedThruArgs }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opts.enablePrePostScripts && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
manifest.scripts?.[`post${scriptName}`] && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!manifest.scripts[scriptName].includes(`post${scriptName}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await runLifecycleHook(`post${scriptName}`, manifest, lifecycleOpts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const limitRun = pLimit(opts.workspaceConcurrency ?? 4) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const _runScript = runScript.bind(null, { manifest, lifecycleOpts, runScriptOptions: { enablePrePostScripts: opts.enablePrePostScripts ?? false }, passedThruArgs }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await Promise.all(specifiedScripts.map(script => limitRun(() => _runScript(script)))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (err: any) { // eslint-disable-line | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (opts.bail !== false) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw err | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -300,6 +304,55 @@ ${renderCommands(rootScripts)}` | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return output | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export interface RunScriptOptions { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
enablePrePostScripts: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const runScript: (opts: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
manifest: ProjectManifest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
lifecycleOpts: RunLifecycleHookOptions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
runScriptOptions: RunScriptOptions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
passedThruArgs: string[] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, scriptName: string) => Promise<void> = async function (opts, scriptName) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opts.runScriptOptions.enablePrePostScripts && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opts.manifest.scripts?.[`pre${scriptName}`] && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!opts.manifest.scripts[scriptName].includes(`pre${scriptName}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await runLifecycleHook(`pre${scriptName}`, opts.manifest, opts.lifecycleOpts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await runLifecycleHook(scriptName, opts.manifest, { ...opts.lifecycleOpts, args: opts.passedThruArgs }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opts.runScriptOptions.enablePrePostScripts && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
opts.manifest.scripts?.[`post${scriptName}`] && | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!opts.manifest.scripts[scriptName].includes(`post${scriptName}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await runLifecycleHook(`post${scriptName}`, opts.manifest, opts.lifecycleOpts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function renderCommands (commands: string[][]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return commands.map(([scriptName, script]) => ` ${scriptName}\n ${script}`).join('\n') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function getSpecifiedScripts (scripts: PackageScripts, scriptName: string) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const scriptSelector = tryBuildRegExpFromCommand(scriptName) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// if scriptName which a user passes is RegExp (like /build:.*/), multiple scripts to execute will be selected with RegExp | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (scriptSelector) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const scriptKeys = Object.keys(scripts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return scriptKeys.filter(script => script.match(scriptSelector)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// if scripts in package.json has script which is equal to scriptName a user passes, return it. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (scripts[scriptName]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return [scriptName] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// if a user passes start command as scriptName, `node server.js` will be executed as a fallback, so return start command even if start command is not defined in package.json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (scriptName === 'start') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return [scriptName] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should do the complicated stuff last because in the vast majority of cases it is
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed. acf55fd |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils' | |
import { Config } from '@pnpm/config' | ||
import { PnpmError } from '@pnpm/error' | ||
import { | ||
runLifecycleHook, | ||
makeNodeRequireOption, | ||
RunLifecycleHookOptions, | ||
} from '@pnpm/lifecycle' | ||
|
@@ -13,6 +12,9 @@ import pLimit from 'p-limit' | |
import realpathMissing from 'realpath-missing' | ||
import { existsInDir } from './existsInDir' | ||
import { getResumedPackageChunks } from './exec' | ||
import { runScript } from './run' | ||
import { tryBuildRegExpFromCommand } from './regexpCommand' | ||
import { PackageScripts } from '@pnpm/types' | ||
|
||
export type RecursiveRunOpts = Pick<Config, | ||
| 'enablePrePostScripts' | ||
|
@@ -73,15 +75,22 @@ export async function runRecursive ( | |
const missingScriptPackages: string[] = packageChunks | ||
.flat() | ||
.map((prefix) => opts.selectedProjectsGraph[prefix]) | ||
.filter((pkg) => !pkg.package.manifest.scripts?.[scriptName]) | ||
.filter((pkg) => getSpecifiedScripts(pkg.package.manifest.scripts ?? {}, scriptName).length < 1) | ||
.map((pkg) => pkg.package.manifest.name ?? pkg.package.dir) | ||
if (missingScriptPackages.length) { | ||
throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `Missing script "${scriptName}" in packages: ${missingScriptPackages.join(', ')}`) | ||
} | ||
} | ||
|
||
for (const chunk of packageChunks) { | ||
await Promise.all(chunk.map(async (prefix: string) => | ||
const selectedScripts = chunk.map(prefix => { | ||
const pkg = opts.selectedProjectsGraph[prefix] | ||
const specifiedScripts = getSpecifiedScripts(pkg.package.manifest.scripts ?? {}, scriptName) | ||
|
||
return specifiedScripts.map(script => ({ prefix, scriptName: script })) | ||
}).flat() | ||
|
||
await Promise.all(selectedScripts.map(async ({ prefix, scriptName }) => | ||
limitRun(async () => { | ||
const pkg = opts.selectedProjectsGraph[prefix] | ||
if ( | ||
|
@@ -113,21 +122,9 @@ export async function runRecursive ( | |
...makeNodeRequireOption(pnpPath), | ||
} | ||
} | ||
if ( | ||
opts.enablePrePostScripts && | ||
pkg.package.manifest.scripts?.[`pre${scriptName}`] && | ||
!pkg.package.manifest.scripts[scriptName].includes(`pre${scriptName}`) | ||
) { | ||
await runLifecycleHook(`pre${scriptName}`, pkg.package.manifest, lifecycleOpts) | ||
} | ||
await runLifecycleHook(scriptName, pkg.package.manifest, { ...lifecycleOpts, args: passedThruArgs }) | ||
if ( | ||
opts.enablePrePostScripts && | ||
pkg.package.manifest.scripts?.[`post${scriptName}`] && | ||
!pkg.package.manifest.scripts[scriptName].includes(`post${scriptName}`) | ||
) { | ||
await runLifecycleHook(`post${scriptName}`, pkg.package.manifest, lifecycleOpts) | ||
} | ||
|
||
const _runScript = runScript.bind(null, { manifest: pkg.package.manifest, lifecycleOpts, runScriptOptions: { enablePrePostScripts: opts.enablePrePostScripts ?? false }, passedThruArgs }) | ||
await _runScript(scriptName) | ||
result.passes++ | ||
} catch (err: any) { // eslint-disable-line | ||
logger.info(err) | ||
|
@@ -164,3 +161,18 @@ export async function runRecursive ( | |
|
||
throwOnCommandFail('pnpm recursive run', result) | ||
} | ||
|
||
function getSpecifiedScripts (scripts: PackageScripts, scriptName: string) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this function not the same as in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my understanding, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps we could add a function parameter for controlling this behavior? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No parameter is needed. It is better to write another wrapper for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is also a solution. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fixed the code to wrap |
||
const scriptSelector = tryBuildRegExpFromCommand(scriptName) | ||
|
||
if (scriptSelector) { | ||
const scriptKeys = Object.keys(scripts) | ||
return scriptKeys.filter(script => script.match(scriptSelector)) | ||
} | ||
|
||
if (scripts[scriptName]) { | ||
return [scriptName] | ||
} | ||
|
||
return [] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also add
pnpm: minor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4802e46 👍