From ed450cafd4aee2093163c27164a069dd0e72a298 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 11 Jul 2026 09:28:01 +0200 Subject: [PATCH 1/2] Fix --config option when placed before the command name The Entropy input parser mishandles a leading long option: the first argv token is force-parsed as a boolean flag, so "ecs --config=ecs.php" turned into a bogus "config=ecs.php" flag and failed with 'Unknown option'. Options after the command name ("ecs check --config=ecs.php") worked. Inject the default "check" command in ecs_normalize_argv() when the first real argument is an option, so the parser's main loop handles it correctly. Help flags stay untouched to keep the global "--help" listing. Adds a config_option.yaml CI workflow that runs the real binary with --config in every position. --- .github/workflows/config_option.yaml | 64 ++++++++++++++++++++++++++++ bin/ecs.php | 11 +++++ 2 files changed, 75 insertions(+) create mode 100644 .github/workflows/config_option.yaml diff --git a/.github/workflows/config_option.yaml b/.github/workflows/config_option.yaml new file mode 100644 index 0000000000..f41d07a3c2 --- /dev/null +++ b/.github/workflows/config_option.yaml @@ -0,0 +1,64 @@ +name: Config Option + +# verifies https://github.com/ecsphp/ecs-src/pull/27#issuecomment-4938413629 +# the "--config " option must work in every position, including before the +# command name / with no command name, where the Entropy input parser would +# otherwise fail with 'Unknown option: "--config=..."' + +on: + pull_request: + push: + branches: + - main + +jobs: + config_option: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - + uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + coverage: none + + - run: composer install --no-progress --ansi + + - + name: "Create a custom config in a non-default location" + run: | + mkdir -p build/nested + printf ' build/nested/some_file.php + cat > build/custom-ecs.php <<'PHP' + withPaths([__DIR__ . '/nested']) + ->withPreparedSets(psr12: true); + PHP + + - + name: "ecs --config= (leading option, default command) must load the custom config" + run: | + OUTPUT="$(bin/ecs --config=build/custom-ecs.php --no-progress-bar --ansi || true)" + echo "$OUTPUT" + echo "$OUTPUT" | grep -q 'some_file.php' + ! echo "$OUTPUT" | grep -q 'Unknown option' + + - + name: "ecs --config (space-separated, leading option) must load the custom config" + run: | + OUTPUT="$(bin/ecs --config build/custom-ecs.php --no-progress-bar --ansi || true)" + echo "$OUTPUT" + echo "$OUTPUT" | grep -q 'some_file.php' + ! echo "$OUTPUT" | grep -q 'Unknown option' + + - + name: "ecs check --config= (option after command) must load the custom config" + run: | + OUTPUT="$(bin/ecs check --config=build/custom-ecs.php --no-progress-bar --ansi || true)" + echo "$OUTPUT" + echo "$OUTPUT" | grep -q 'some_file.php' + ! echo "$OUTPUT" | grep -q 'Unknown option' diff --git a/bin/ecs.php b/bin/ecs.php index 306730c68a..0bed39400c 100755 --- a/bin/ecs.php +++ b/bin/ecs.php @@ -186,6 +186,10 @@ public function loadIfNotLoadedYet(string $file): void * the "-c" config shortcut to "--config", so the Entropy input parser does not * treat them as unknown command options. * + * When the first argument is an option (e.g. "ecs --config=ecs.php"), inject the + * default "check" command, so the Entropy input parser does not mistake the leading + * "--config=" for an unknown boolean flag and fail with "Unknown option". + * * @param string[] $argv * @return string[] */ @@ -227,5 +231,12 @@ function ecs_normalize_argv(array $argv): array $normalized[] = $arg; } + // $normalized[0] is the script name; the first real argument sits at index 1. + // Keep "-h"/"--help" untouched, so it still prints the global command list. + $helpFlags = ['-h', '--help']; + if (isset($normalized[1]) && str_starts_with($normalized[1], '-') && ! in_array($normalized[1], $helpFlags, true)) { + array_splice($normalized, 1, 0, 'check'); + } + return $normalized; } From 1dfb502ed700cf74dcd156a355e0b1d9435fa198 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sat, 11 Jul 2026 09:42:55 +0200 Subject: [PATCH 2/2] Bump rector to ^2.5 and satisfy its early-return rules CI installs the latest deps (composer.lock is not committed), so it runs rector 2.5.5, which flags AbstractDocBlockFixer with early-return rules. Bump the constraint to ^2.5 and apply the required refactor, so the Rector job passes. --- composer.json | 2 +- .../src/Fixer/Commenting/AbstractDocBlockFixer.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 6af062fc7a..5121355024 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "phpstan/phpstan-webmozart-assert": "^2.0", "phpunit/phpunit": "^13.2", "rector/jack": "^1.0", - "rector/rector": "^2.4", + "rector/rector": "^2.5", "rector/type-perfect": "^2.1", "symplify/phpstan-rules": "^14.12", "symplify/vendor-patches": "^11.5", diff --git a/packages/coding-standard/src/Fixer/Commenting/AbstractDocBlockFixer.php b/packages/coding-standard/src/Fixer/Commenting/AbstractDocBlockFixer.php index a91215e32c..42159c2a7a 100644 --- a/packages/coding-standard/src/Fixer/Commenting/AbstractDocBlockFixer.php +++ b/packages/coding-standard/src/Fixer/Commenting/AbstractDocBlockFixer.php @@ -44,7 +44,11 @@ public function isCandidate(Tokens $tokens): bool continue; } - if (! (isset($tokens[$index + 3]) && $tokens[$index + 3]->getContent() === ')')) { + if (! isset($tokens[$index + 3])) { + continue; + } + + if ($tokens[$index + 3]->getContent() !== ')') { continue; }