wpelevator/run-parallel
Composer 安装命令:
composer require wpelevator/run-parallel
包简介
Run one command per matched path, optionally in parallel.
README 文档
README
Run a list of commands, or one command per matched path, in parallel.
run-parallel is useful for running Composer scripts concurrently — think npm-run-all for PHP — and for monorepos where each package has its own tool config. It discovers paths, renders one command per path, and executes those commands with prefixed output.
Install
composer require --dev wpelevator/run-parallel
The package declares Composer replacements for the earlier package name wpelevator/phpcs-parallel so dependent packages can move to wpelevator/run-parallel without installing duplicate copies.
Usage
At its simplest, pass each command with --command:
vendor/bin/run-parallel \ --command='composer lint' \ --command='composer test' \ --command='composer analyse'
Each command becomes its own task, and tasks run in parallel with prefixed output, a per-task summary, and the highest exit code as the result. Repeat --command when you want npm-run-all style behaviour. See Composer scripts for running named scripts concurrently.
For monorepos, provide a path pattern and a command template instead. One task is created per matched path:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpstan.neon' \ --command='phpstan analyse --configuration={path} {path | dirname}'
Tasks run in parallel by default, one process per CPU core. Use --processes to control the concurrency (--processes=1 runs serially):
vendor/bin/run-parallel \ --path-pattern='packages/*/phpstan.neon' \ --command='phpstan analyse --configuration={path} {path | dirname} --memory-limit=1G' \ --processes=4
Use --cwd when a tool should run from the matched package directory:
vendor/bin/run-parallel \ --path-pattern='packages/*/composer.json' \ --command='composer test' \ --cwd='{path | dirname}' \ --processes=4
Repeat --command with --path-pattern to run multiple commands for each matched path:
vendor/bin/run-parallel \ --path-pattern='packages/*/composer.json' \ --command='composer validate' \ --command='composer test' \ --cwd='{path | dirname}' \ --processes=4
By default, labels for multiple commands per matched path include both the matched path and the command, such as foo:composer-validate and foo:composer-test.
When --cwd is set, use {path | realpath} for file paths that must still point back to the matched file:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpunit.xml.dist' \ --command='phpunit --configuration={path | realpath}' \ --cwd='{path | dirname}' \ --processes=4
Use --label when you want custom output prefixes:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpunit.xml.dist' \ --command='phpunit --configuration={path}' \ --label='{path | dirname | basename}' \ --processes=4
Options:
| Option | Description |
|---|---|
--command=CMD |
Command to run. Repeatable; with --path-pattern, each command is rendered once per matched path. |
COMMAND ... |
Positional shorthand for --command. |
--path-pattern=GLOB |
Match paths to create tasks. Repeatable; comma-separated values are supported. |
--processes=N |
Number of commands to run at once. Default: auto (CPU core count). |
--cwd=TEMPLATE |
Working directory template for each task. Default: invocation directory. |
--label=TEMPLATE |
Output label template for each task. Default: `{path |
--config=PATH |
PHP config file for custom filters, variables, and defaults. |
--dry-run |
Print the rendered command per task without executing anything. |
--fail-fast |
Stop scheduling and terminate running tasks after the first failure. |
Path patterns
Patterns use glob semantics: * and ? match within a single path segment and never cross /, while ** matches any number of segments. Character classes like [0-9] and [!0-9] are supported.
| Pattern | Matches | Does not match |
|---|---|---|
packages/*/phpcs.xml |
packages/foo/phpcs.xml |
packages/foo/bar/phpcs.xml |
packages/**/phpcs.xml |
packages/phpcs.xml, packages/foo/bar/phpcs.xml |
src/phpcs.xml |
**/composer.json |
composer.json at any depth |
— |
Use --dry-run to preview which paths matched and what will run:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpcs.xml.dist' \ --command='phpcs --standard={path} {path | dirname}' \ --dry-run
Template variables
| Variable | Description |
|---|---|
{path} |
Matched path, rendered relative to the invocation directory when possible. For a command list, the command string itself. |
{command} |
Command template for the current task. |
{index} |
Zero-based task index. |
Filters
Variables can be piped through filters with |. Filters apply left to right, so {path | dirname | basename} takes the directory of the matched path, then its last segment.
Example outputs below assume the matched path is packages/foo/phpcs.xml.dist and run-parallel was invoked from /repo:
| Filter | Description | Example output |
|---|---|---|
dirname |
Parent directory of the path. | packages/foo |
basename |
Last segment of the path. | phpcs.xml.dist |
filename |
Last segment without its final extension. | phpcs.xml |
ext |
Final extension without the dot. | dist |
realpath |
Absolute path. Relative values are resolved against the invocation directory; if the path does not exist, the joined path is returned unresolved. | /repo/packages/foo/phpcs.xml.dist |
relative |
Path relative to the invocation directory (. for the directory itself). Paths outside it are returned unchanged. |
packages/foo/phpcs.xml.dist |
slug |
Replaces every run of characters other than letters, digits, ., _, and - with a single -, then trims leading and trailing dashes. Useful for labels and artifact names. |
packages-foo-phpcs.xml.dist |
Referencing an unknown variable or filter in a template is an error and fails the run. Custom filters and variables can be added via a config file.
Commands are executed directly as argv, not through a shell. Pipes, redirects, and shell expansion are not interpreted.
Binary resolution
The first word of each command is resolved through the PATH environment variable, which child processes inherit from run-parallel. When run-parallel runs as a Composer script, Composer prepends the project's vendor/bin directory to PATH for the duration of the run, so bare binary names like phpcs or phpstan resolve to the project-local binaries — even when --cwd points at a package subdirectory, because the prepended vendor/bin path is absolute.
When invoking vendor/bin/run-parallel directly from the shell, PATH is not modified, so bare names resolve to whatever is installed globally. In that case, reference project-local binaries by path:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpcs.xml.dist' \ --command='vendor/bin/phpcs --standard={path} {path | dirname}'
Working directory
By default, every command runs in the directory where run-parallel was invoked. Use --cwd to run each command from a different directory — typically the matched package directory via --cwd='{path | dirname}'. The template is rendered once per task, and a relative result is resolved against the invocation directory.
--cwd changes the child process working directory, but template variables are still rendered relative to the original invocation directory. Use {path | realpath} when the child process needs an absolute path.
Configuration
Use --config=run-parallel.php to load custom filters, variables, and default option values.
<?php return [ 'filters' => [ 'package' => static function (string $path): string { return basename(dirname($path)); }, ], 'variables' => [ 'php' => PHP_BINARY, ], 'defaults' => [ 'path-pattern' => 'packages/*/composer.json', 'command' => '{php} vendor/bin/phpunit', 'cwd' => '{path | dirname}', 'label' => '{path | package}', 'processes' => 'auto', 'fail-fast' => true, ], ];
Then run:
vendor/bin/run-parallel --config=run-parallel.php
CLI options override config defaults, so you can still replace individual values:
vendor/bin/run-parallel \
--config=run-parallel.php \
--command='composer test'
The command default also accepts a list. Without path patterns, each command becomes its own task. With path patterns, each command runs once per matched path:
'defaults' => [ 'command' => ['composer lint', 'composer test', 'composer analyse'], ],
Custom filters receive the current value, the current task, and the invocation working directory:
'filters' => [ 'artifactName' => static function (string $value, \WPElevator\RunParallel\Task $task, string $cwd): string { return $task->index . '-' . basename(dirname($value)); }, ],
Examples
PHPCS
Run PHPCS once per package ruleset:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpcs.xml.dist' \ --command='phpcs --standard={path} {path | dirname}'
Run PHPCS in parallel and pass PHPCS options directly in the command template:
vendor/bin/run-parallel \ --path-pattern='packages/*/phpcs.xml.dist' \ --command='phpcs --standard={path} {path | dirname} -s --report=summary' \ --processes=4
If your project uses multiple PHPCS config names, repeat --path-pattern:
vendor/bin/run-parallel \ --path-pattern='packages/*/.phpcs.xml' \ --path-pattern='packages/*/phpcs.xml' \ --path-pattern='packages/*/.phpcs.xml.dist' \ --path-pattern='packages/*/phpcs.xml.dist' \ --command='phpcs --standard={path} {path | dirname}' \ --processes=4
PHPCBF
vendor/bin/run-parallel \ --path-pattern='packages/*/phpcs.xml.dist' \ --command='phpcbf --standard={path} {path | dirname}' \ --processes=4
PHPStan
vendor/bin/run-parallel \ --path-pattern='packages/*/phpstan.neon' \ --command='phpstan analyse --configuration={path} {path | dirname} --memory-limit=1G' \ --processes=4
PHPUnit
vendor/bin/run-parallel \ --path-pattern='packages/*/phpunit.xml.dist' \ --command='phpunit --configuration={path}' \ --processes=4
Composer
The command template accepts any Composer invocation, not just composer test:
vendor/bin/run-parallel \ --path-pattern='packages/*/composer.json' \ --command='composer validate' \ --cwd='{path | dirname}' \ --processes=4
vendor/bin/run-parallel \ --path-pattern='packages/*/composer.json' \ --command='composer install --no-interaction' \ --cwd='{path | dirname}' \ --processes=4
Run a named Composer script the same way:
vendor/bin/run-parallel \ --path-pattern='packages/*/composer.json' \ --command='composer run-script lint' \ --cwd='{path | dirname}' \ --processes=4
Composer scripts
Run existing Composer scripts in parallel by wrapping them in a run-parallel script, npm-run-all style:
{
"scripts": {
"lint": "phpcs",
"analyse": "phpstan",
"test": "phpunit",
"check": "run-parallel --command='composer lint' --command='composer analyse' --command='composer test'"
}
}
Now composer check runs all three concurrently with prefixed output and a summary, and fails if any of them fail.
Composer adds vendor/bin to PATH when running scripts, so both run-parallel and the binaries referenced in commands can use bare names here (see Binary resolution):
{
"scripts": {
"lint": "run-parallel --path-pattern='packages/*/phpcs.xml.dist' --command='phpcs --standard={path} {path | dirname} -s' --processes=4",
"test:packages": "run-parallel --path-pattern='packages/*/phpunit.xml.dist' --command='phpunit --configuration={path}' --processes=4"
}
}
Development
Run the same checks used by CI:
composer lint
composer analyse
composer test
Run a specific test suite:
composer test -- --testsuite=Unit composer test -- --testsuite=Integration
Generate PHPUnit coverage reports (requires Xdebug or PCOV):
composer test:coverage
Coverage output is written to the terminal, tests/coverage/clover.xml, and tests/coverage/html.
Use the self test to run all checks concurrently:
composer all
Why not …?
phpcs --parallel, PHPStan workers, ParaTest — these parallelize within one config.run-parallelparallelizes across configs (one run per package), and the two compose: eachrun-paralleltask can itself use the tool's own parallelism.- veewee/composer-run-parallel — runs named Composer scripts concurrently, like
run-parallel's command-list mode, but has no path discovery or per-path command templating.
Notes
- Dependency directories are skipped during discovery:
.git,vendor,node_modules,bower_components. - Child process output is streamed through Symfony Console and prefixed with the task label; labels are colored when the output is a terminal.
- A per-task summary with durations and exit codes is written to stderr after the run.
- The command returns the highest child exit code for normal tool failures. Runtime/tooling errors are promoted to at least exit code
3. - On
SIGINT/SIGTERM(e.g. Ctrl+C), running child processes are stopped before exiting (requires thepcntlextension; standard on Linux/macOS CLI builds). - File-modifying tools are safe only when matched paths do not overlap.
License
This project is open-sourced under the MIT License. See LICENSE for details.
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-07-02