PHPackages                             wpelevator/phpcs-parallel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. wpelevator/phpcs-parallel

Abandoned → [wpelevator/run-parallel](/?search=wpelevator%2Frun-parallel)Library[Testing &amp; Quality](/categories/testing)

wpelevator/phpcs-parallel
=========================

Run PHPCS and PHPCBF across monorepos with isolated per-project configs, optionally in parallel.

v1.1.0(1mo ago)02MITPHPPHP &gt;=8.1CI passing

Since Jul 1Pushed 1mo agoCompare

[ Source](https://github.com/wpelevator/run-parallel)[ Packagist](https://packagist.org/packages/wpelevator/phpcs-parallel)[ RSS](/packages/wpelevator-phpcs-parallel/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (3)Dependencies (8)Versions (4)Used By (0)

run-parallel
============

[](#run-parallel)

[![Test](https://github.com/wpelevator/run-parallel/actions/workflows/ci.yml/badge.svg)](https://github.com/wpelevator/run-parallel/actions/workflows/ci.yml)

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
-------

[](#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
-----

[](#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](#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:

OptionDescription`--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

[](#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.

PatternMatchesDoes 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

[](#template-variables)

VariableDescription`{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

[](#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`:

FilterDescriptionExample 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](#configuration).

Commands are executed directly as argv, not through a shell. Pipes, redirects, and shell expansion are not interpreted.

### Binary resolution

[](#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-scripts), 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

[](#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
-------------

[](#configuration)

Use `--config=run-parallel.php` to load custom filters, variables, and default option values.

```
