andersundsehr / rector-p
rector run file by file (like git add -p)
Requires
- php: ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0
- rector/rector: ^2.2.10
- symfony/console: ^5.4 || ^6.4 || ^7.4 || ^8.1
Requires (Dev)
- andersundsehr/grumphp-fractor-task: @dev
- andersundsehr/phpstan-git-files: @dev
- phpunit/phpunit: ^11.5.0 || ^12.0.0
- pluswerk/grumphp-bom-task: @dev
- pluswerk/grumphp-config: @dev
- pluswerk/grumphp-xliff-task: @dev
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
andersundsehr/rector-p
Run Rector file by file and decide for each file whether to apply the changes, like git add -p.
Why?
Introducing Rector in a large, old project often produces more changes than anyone can review at once. rector-p lets you go through the project one file at a time: you see the diff for a file, apply it, skip it or adjust things and try again. It remembers which files are done, so you can stop and continue later.
rector-pis part ofpluswerk/grumphp-config. If you use that package, it is already installed.
Requirements
- PHP 8.2 or newer
- Rector 2 with a
rector.php; it must definepathsunless you pass paths on the command line
Installation
composer require --dev andersundsehr/rector-p
Usage
vendor/bin/rector-p
Only some directories or files:
vendor/bin/rector-p src/Controller/ vendor/bin/rector-p src/Controller/MyController.php src/Controller/MyOtherController.php
What happens
-
rector-pfinds the Rector configuration like Rector does: the file given with--config, otherwiserector.phporrector.dist.phpin the current directory. Without a configuration it stops with an error. It collects the files from the configuredpaths, or from the paths you pass as arguments, with the file extensions of the configuration (withFileExtensions()). Like in Rector, a path with*is a glob pattern; a path you pass that matches nothing stopsrector-pwith an error. The files are sorted by name. If there are no files, it stops withNo files found.For this list
rector-puses an empty cache of its own instead of Rector's result cache. Otherwise Rector would leave out files it already checked, and the list and the chunks would change from run to run. Rector's result cache stays as it is. Which files are left to do is decided by the progress ofrector-p(see below). -
For each file it runs
rector process --dry-run <file>with that configuration, which shows the diff. -
If Rector has nothing to change, the file is marked as done. If Rector fails, for example because of a broken configuration,
rector-pstops with Rector's exit code. Otherwise you choose:Answer Effect execute(default)Apply the changes and mark the file as done skip-fileLeave the file as it is; you are asked again on the next run retryRun the dry run again, e.g. after you edited the file or rector.phpquitStop; files marked as done stay done -
After each file it shows its progress, e.g.
done with 12/240 files, and an estimate of the remaining time.
With --no-interaction (-n) every question is answered with the default, execute, so all changes are applied without asking.
Progress
rector-p stores a SHA-256 hash of every file marked as done in its package directory (usually vendor/andersundsehr/rector-p/). A file is skipped as long as its content does not change.
- Each Rector configuration has its own progress:
rector.phpin the current directory usescache.json, every other configuration acache-<hash>.json. - Start from the beginning with
--startOver(-s), for example after you added rules to your configuration. This clears the progress of the current configuration only. - The progress is lost when Composer reinstalls the package.
Chunks
Split the sorted file list into equal parts and work on one part at a time, for example to share the work in a team or over several days:
vendor/bin/rector-p --chunk=1/4 # first quarter vendor/bin/rector-p --chunk=2/4 # second quarter
After a chunk, rector-p prints the command for the next one. It keeps the verbosity, --config and the paths you passed, so the next chunk works on the same file list.
Options
Usage:
partial [options] [--] [<source>...]
Arguments:
source Files or directories to be upgraded.
Options:
-s, --startOver Start over with the first file (be default rector-p keeps a record of files that have no changes in them)
-p, --chunk=CHUNK chunk(part) definition eg 1/2 (first half) or 2/2 (second half) or 3/10 (third tenth) [default: "1/1"]
-c, --config=CONFIG Path to config file [default: "<current directory>/rector.php"]
-h, --help Display help for the given command. When no command is given display help for the partial command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
- The configuration that was used for the file list is passed on to every Rector run, so the file list and the changes always use the same configuration.
- With
-vvrector-pprints every Rector command, with-vvvalso how long it took. rector-pcallsrectorfrom Composer'svendor/bindirectory, or from yourPATHif it cannot find it there. Paths with spaces are supported.- If Rector fails while checking or changing a file,
rector-pstops with Rector's exit code.
Contributing
This package is developed in the monorepo andersundsehr/grumphp-config. Please open issues and pull requests there.
The tests in tests/ run rector-p against small temporary projects. Most of them use a fake Rector (tests/Fixture/bin/rector) that answers in milliseconds, a few use the real Rector. They run as part of vendor/bin/grumphp run in this package, or alone:
composer install vendor/bin/phpunit
Infection checks the tests with mutation testing; infection.json5 sets the minimum score. See Mutation testing in CONTRIBUTING.md for how to run it.
License
GPL-2.0-or-later
with ♥️ from anders und sehr GmbH
If something did not work 😮
or you appreciate this Extension 🥰 let us know.
We are hiring https://www.andersundsehr.com/karriere/