Skip to content

Commit c87c337

Browse files
committed
chore: align standards php-cs-fixer naming and harden command loader
1 parent 56a0b61 commit c87c337

8 files changed

Lines changed: 101 additions & 10 deletions

File tree

.github/wiki

Submodule wiki updated from 219a911 to bbb6338

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Add a hybrid command runtime bootstrap and capability bridge that keeps command discovery split between migrated Symfony commands (`DevTools`) and legacy Composer `BaseCommand` commands (`DevToolsComposer`) while exposing proxy commands during Composer execution for the first migration step (#199)
1313

14+
### Changed
15+
16+
- Align the standards pipeline to invoke PHPDoc checks via the `php-cs-fixer` command name/alias and route standards cache to `.dev-tools/cache/php-cs-fixer`, preserving backwards compatibility for existing `dockblock`-style entry points.
17+
- Rename the command entry point from `standards:phpdoc` to `standards:dockblock` and keep both `dockblock` and `php-cs-fixer` aliases for compatibility (`standards:phpdoc` is intentionally not kept as a command name).
18+
1419
## [1.22.3] - 2026-04-25
1520

1621
### Fixed

src/Console/Command/PhpDocCommand.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444
* Provides operations to inspect, lint, and repair PHPDoc comments across the project.
4545
* The class MUST NOT be extended and SHALL coordinate tools like PHP-CS-Fixer and Rector.
4646
*/
47-
#[AsCommand(name: 'standards:phpdoc', description: 'Checks and fixes PHPDocs.', aliases: ['phpdoc'])]
47+
#[AsCommand(name: 'standards:dockblock', description: 'Checks and fixes PHPDocs.', aliases: [
48+
'dockblock',
49+
'php-cs-fixer',
50+
])]
4851
final class PhpDocCommand extends Command
4952
{
5053
use HasCacheOption;

src/Console/Command/StandardsCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
113113
'input' => $input,
114114
]);
115115

116-
foreach (['refactor', 'phpdoc', 'code-style', 'reports'] as $command) {
116+
foreach (['refactor', 'php-cs-fixer', 'code-style', 'reports'] as $command) {
117117
$commands[] = $command;
118118
$processBuilder = $this->processBuilder;
119119

@@ -129,13 +129,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int
129129
$processBuilder = $processBuilder->withArgument('--fix');
130130
}
131131

132-
if (\in_array($command, ['phpdoc', 'reports'], true) && null !== $cacheArgument) {
132+
if (\in_array($command, ['php-cs-fixer', 'reports'], true) && null !== $cacheArgument) {
133133
$processBuilder = $processBuilder->withArgument($cacheArgument);
134134
}
135135

136136
if (
137137
$cacheDirEnabled
138-
&& \in_array($command, ['phpdoc', 'reports'], true)
138+
&& \in_array($command, ['php-cs-fixer', 'reports'], true)
139139
&& null !== $cacheDir = $this->resolveCacheDirArgument($input, $command)
140140
) {
141141
$processBuilder = $processBuilder->withArgument('--cache-dir', $cacheDir);
@@ -181,7 +181,7 @@ private function getProcessLabel(string $command): string
181181
{
182182
return match ($command) {
183183
'refactor' => 'Refactoring Code with DevTools',
184-
'phpdoc' => 'Checking PHPDoc with DevTools',
184+
'php-cs-fixer', 'dockblock' => 'Checking PHPDoc with DevTools',
185185
'code-style' => 'Checking Code Style with DevTools',
186186
'reports' => 'Generating Reports with DevTools',
187187
default => 'Running DevTools Command',

src/Console/CommandLoader/DevToolsCommandLoader.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use FastForward\DevTools\Filesystem\FinderFactoryInterface;
2323
use Psr\Container\ContainerInterface;
2424
use ReflectionClass;
25+
use RuntimeException;
2526
use Symfony\Component\Console\Attribute\AsCommand;
2627
use Symfony\Component\Console\Command\Command;
2728
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
@@ -96,13 +97,27 @@ private function getCommandMap(FinderFactoryInterface $finderFactory): array
9697
}
9798

9899
$arguments = $attribute->getArguments();
99-
$commandNames = [$arguments['name'], ...($arguments['aliases'] ?? [])];
100+
$commandName = $arguments['name'] ?? $arguments[0] ?? '';
101+
$aliases = $arguments['aliases'] ?? $arguments[2] ?? [];
102+
$commandNames = [$commandName, ...((array) $aliases)];
100103

101104
foreach ($commandNames as $commandName) {
105+
if (! \is_string($commandName)) {
106+
continue;
107+
}
108+
102109
if ('' === $commandName) {
103110
continue;
104111
}
105112

113+
if (\array_key_exists($commandName, $commandMap) && $commandMap[$commandName] !== $class) {
114+
throw new RuntimeException(\sprintf(
115+
'Command %s is already registered and cannot be assigned to %s.',
116+
$commandName,
117+
$class
118+
));
119+
}
120+
106121
$commandMap[$commandName] = $class;
107122
}
108123
}

tests/Console/Command/StandardsCommandTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public function executeWillRunSuiteSequentially(): void
118118
'Code standards checks completed successfully.',
119119
Argument::that(static fn(array $context): bool => $context['input'] instanceof InputInterface
120120
&& $context['output'] instanceof OutputInterface
121-
&& ['refactor', 'phpdoc', 'code-style', 'reports'] === $context['commands']),
121+
&& ['refactor', 'php-cs-fixer', 'code-style', 'reports'] === $context['commands']),
122122
)->shouldBeCalled();
123123

124124
self::assertSame(StandardsCommand::SUCCESS, $this->invokeExecute());
@@ -143,7 +143,7 @@ public function executeWillReturnFailureWhenAnyCommandFails(): void
143143
'Code standards checks failed.',
144144
Argument::that(static fn(array $context): bool => $context['input'] instanceof InputInterface
145145
&& $context['output'] instanceof OutputInterface
146-
&& ['refactor', 'phpdoc', 'code-style', 'reports'] === $context['commands']),
146+
&& ['refactor', 'php-cs-fixer', 'code-style', 'reports'] === $context['commands']),
147147
)->shouldBeCalled();
148148

149149
self::assertSame(StandardsCommand::FAILURE, $this->invokeExecute());
@@ -162,7 +162,7 @@ public function executeWithCacheWillForwardCacheOnlyToCacheAwareNestedCommands()
162162
$this->processBuilder->withArgument('--cache')
163163
->willReturn($this->processBuilder->reveal())
164164
->shouldBeCalledTimes(2);
165-
$this->processBuilder->withArgument('--cache-dir', '.dev-tools/cache/phpdoc')
165+
$this->processBuilder->withArgument('--cache-dir', '.dev-tools/cache/php-cs-fixer')
166166
->willReturn($this->processBuilder->reveal())
167167
->shouldBeCalledOnce();
168168
$this->processBuilder->withArgument('--cache-dir', '.dev-tools/cache/reports')

tests/Console/CommandLoader/DevToolsCommandLoaderTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use FastForward\DevTools\Console\Command\TestsCommand;
2626
use FastForward\DevTools\Console\CommandLoader\DevToolsCommandLoader;
2727
use FastForward\DevTools\Filesystem\FinderFactoryInterface;
28+
use RuntimeException;
2829
use PHPUnit\Framework\Attributes\CoversClass;
2930
use PHPUnit\Framework\Attributes\Test;
3031
use PHPUnit\Framework\Attributes\UsesClass;
@@ -171,6 +172,47 @@ public function constructorWillRegisterAliasesFromAsCommandAttribute(): void
171172
self::assertTrue($loader->has('phpunit'));
172173
}
173174

175+
/**
176+
* @return void
177+
*/
178+
#[Test]
179+
public function constructorWillFailWhenCommandNameConflicts(): void
180+
{
181+
$commandDirectory = \dirname(__DIR__, 3);
182+
$fixtureDirectory = $commandDirectory . '/tests/Fixtures/Console/Command';
183+
$srcDirectory = $commandDirectory . '/src/Console/Command';
184+
185+
$this->finderFactory->create()
186+
->willReturn($this->finder->reveal())
187+
->shouldBeCalledOnce();
188+
$this->finder->files()
189+
->willReturn($this->finder->reveal())
190+
->shouldBeCalled();
191+
$this->finder->in(Argument::type('string'))->willReturn($this->finder->reveal())->shouldBeCalled();
192+
$this->finder->notPath('Traits')
193+
->willReturn($this->finder->reveal())
194+
->shouldBeCalled();
195+
$this->finder->name('*.php')
196+
->willReturn($this->finder->reveal())
197+
->shouldBeCalled();
198+
$this->finder->getIterator()
199+
->willReturn(new ArrayIterator([
200+
new SplFileInfo(
201+
$fixtureDirectory . '/FixtureDuplicateCommandName.php',
202+
'',
203+
'FixtureDuplicateCommandName.php'
204+
),
205+
new SplFileInfo($srcDirectory . '/AgentsCommand.php', '', 'AgentsCommand.php'),
206+
]))->shouldBeCalled();
207+
208+
$this->expectException(RuntimeException::class);
209+
$this->expectExceptionMessage(
210+
'Command agents is already registered and cannot be assigned to FastForward\\DevTools\\Console\\Command\\AgentsCommand.'
211+
);
212+
213+
new DevToolsCommandLoader($this->finderFactory->reveal(), $this->container->reveal());
214+
}
215+
174216
/**
175217
* @return void
176218
*/
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Fast Forward Development Tools for PHP projects.
7+
*
8+
* This file is part of fast-forward/dev-tools project.
9+
*
10+
* @author Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
11+
* @license https://opensource.org/licenses/MIT MIT License
12+
*
13+
* @see https://github.com/php-fast-forward/
14+
* @see https://github.com/php-fast-forward/dev-tools
15+
* @see https://github.com/php-fast-forward/dev-tools/issues
16+
* @see https://php-fast-forward.github.io/dev-tools/
17+
* @see https://datatracker.ietf.org/doc/html/rfc2119
18+
*/
19+
20+
namespace FastForward\DevTools\Console\Command;
21+
22+
use Symfony\Component\Console\Attribute\AsCommand;
23+
use Symfony\Component\Console\Command\Command;
24+
25+
#[AsCommand(name: 'agents')]
26+
final class FixtureDuplicateCommandName extends Command {}

0 commit comments

Comments
 (0)