Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bada76f
feat(composer): add command runtime hybrid foundation
coisa Apr 25, 2026
5d4ee02
refactor composer json handling away from composer json utility classes
coisa Apr 25, 2026
b147d85
refactor: complete composer-command migration and cleanup for dev-tools
coisa Apr 25, 2026
0d5e111
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 25, 2026
07f1ac6
refactor: remove logger-aware command interface
coisa Apr 25, 2026
7994ab1
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 25, 2026
a7390f6
feat: change dirname e basename method names
coisa Apr 26, 2026
565cd2a
feat: change dirname e basename method names
coisa Apr 26, 2026
52b8231
Fix coverage metadata and stabilize dev-tools command tests
coisa Apr 26, 2026
9b226a9
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 26, 2026
d4b344a
fix: align composer command provider test with proxy map keys
coisa Apr 26, 2026
d79d461
refactor: centralize command retrieval through DevTools API
coisa Apr 26, 2026
139ec4d
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 26, 2026
bda11dc
fix: avoid registering command aliases in composer provider
coisa Apr 26, 2026
3b703e4
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 26, 2026
55f75ee
test: guard composer provider against alias-only command entries
coisa Apr 26, 2026
68b2f51
test: align DevTools test with Application::all loader contract
coisa Apr 26, 2026
aed6356
test: document alias filtering and cover command alias registration
coisa Apr 26, 2026
dd8834e
test: cover alias preservation in composer command provider
coisa Apr 26, 2026
56a0b61
test: avoid command provider assertions depending on map keys
coisa Apr 26, 2026
c87c337
chore: align standards php-cs-fixer naming and harden command loader
coisa Apr 26, 2026
efef8cc
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 26, 2026
94b74e5
refactor: rename dockblock references to docheader
coisa Apr 26, 2026
5454619
chore: normalize phpdoc command naming and docs
coisa Apr 26, 2026
fe313cc
docs: fix heading formatting in rector-and-phpdoc.rst
coisa Apr 26, 2026
6c52eb5
test: centralize tooling excluded directories and cleanup fixture han…
coisa Apr 26, 2026
1dd190b
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 26, 2026
0e1f782
feat: add ignoreErrorsOnPackage for 'composer/composer' in configuration
coisa Apr 26, 2026
e41921f
docs: update phpdoc section to clarify aliases and functionality
coisa Apr 26, 2026
67557a6
docs: update parameter descriptions for SymfonyStyle in command classes
coisa Apr 26, 2026
eebe5ec
Update wiki submodule pointer for PR #270
github-actions[bot] Apr 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .agents/skills/phpunit-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,57 @@ Choose the smallest command that proves the change.
- Re-run after fixes until the targeted tests pass.
- If failures come from unrelated pre-existing breakage, call that out separately and do not silently claim success.

### Composer plugin validation flow

Some repository test scenarios are only valid when DevTools is executed as a Composer plugin.
Create a temporary fixture under `backup/` before running plugin-based verification.

```bash
PROJECT_ROOT="$(pwd)"
PLUGIN_FIXTURE="$PROJECT_ROOT/backup/composer-plugin-consumer"
mkdir -p "$PROJECT_ROOT/backup"
rm -rf "$PLUGIN_FIXTURE"
mkdir -p "$PLUGIN_FIXTURE"

cat > "$PLUGIN_FIXTURE/composer.json" <<'JSON'
{
"name": "fast-forward/dev-tools-composer-plugin-consumer-fixture",
"description": "Fixture project used to validate DevTools plugin behavior.",
"license": "MIT",
"type": "project",
"require": {
"fast-forward/dev-tools": "*@dev"
},
"repositories": [
{
"type": "path",
"url": "../..",
"options": {
"symlink": true
}
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"allow-plugins": {
"ergebnis/composer-normalize": true,
"fast-forward/dev-tools": true,
"phpdocumentor/shim": true,
"phpro/grumphp-shim": true,
"pyrech/composer-changelogs": true
}
},
"scripts": {
"dev-tools": "dev-tools",
"dev-tools:fix": "@dev-tools --fix"
}
}
JSON

cd "$PLUGIN_FIXTURE"
composer install
composer tests
```

Read [references/generation-checklist.md](references/generation-checklist.md) before writing or repairing tests in an unfamiliar repository.
2 changes: 1 addition & 1 deletion .github/wiki
Submodule wiki updated from 3dea0d to c99c7c
10 changes: 5 additions & 5 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

declare(strict_types=1);

require __DIR__ . '/vendor/autoload.php';

use FastForward\DevTools\Path\WorkingProjectPathResolver;

$rules = [
'phpdoc_indent' => true,
'phpdoc_order' => [
Expand Down Expand Up @@ -39,11 +43,7 @@

$finder = PhpCsFixer\Finder::create()
->in([getcwd()])
->exclude('public')
->exclude('resources')
->exclude('vendor')
->exclude('tmp')
;
->exclude(WorkingProjectPathResolver::TOOLING_EXCLUDED_DIRECTORIES);

return (new PhpCsFixer\Config())
->setRiskyAllowed(false)
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

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

### Changed

- Restore `standards:phpdoc` as the command entry point for PHPDoc checks while keeping
the legacy aliases `docheader` and `php-cs-fixer`.
- Remove the `phpdoc` alias from `reports:docs` to avoid command-name collisions with
the standards PHPDoc check command.

## [1.22.3] - 2026-04-25

### Fixed
Expand Down
3 changes: 1 addition & 2 deletions bin/dev-tools.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@
namespace FastForward\DevTools;

use FastForward\DevTools\Console\DevTools;
use Symfony\Component\Console\Input\ArgvInput;

$projectVendorAutoload = \dirname(__DIR__, 4) . '/vendor/autoload.php';
$pluginVendorAutoload = \dirname(__DIR__) . '/vendor/autoload.php';

require_once file_exists($projectVendorAutoload) ? $projectVendorAutoload : $pluginVendorAutoload;

DevTools::create()->run(new ArgvInput([...$argv, '--no-plugins']));
DevTools::create()->run();
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"require": {
"php": "^8.3",
"composer-plugin-api": "^2.0",
"composer/composer": "^2.9",
"container-interop/service-provider": "^0.4.1",
"dg/bypass-finals": "^1.9",
"ergebnis/agent-detector": "^1.1",
Expand Down Expand Up @@ -82,6 +81,9 @@
"thecodingmachine/safe": "^3.4",
"twig/twig": "^3.24"
},
"require-dev": {
"composer/composer": "^2.9"
},
"minimum-stability": "stable",
"autoload": {
"psr-4": {
Expand Down
5 changes: 3 additions & 2 deletions docs/api/commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ subprocess execution is needed.
- ``refactor``
- Runs Rector with local or packaged configuration.
* - ``FastForward\DevTools\Console\Command\PhpDocCommand``
- ``phpdoc``
- Runs PHP-CS-Fixer and a focused Rector PHPDoc pass.
- ``standards:phpdoc``
- Runs PHP-CS-Fixer and a focused Rector PHPDoc pass. Supported aliases:
``phpdoc``, ``docheader`` and ``php-cs-fixer``.
* - ``FastForward\DevTools\Console\Command\CodeStyleCommand``
- ``code-style``
- Runs Composer Normalize and ECS.
Expand Down
2 changes: 1 addition & 1 deletion docs/commands/funding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Options

``--composer-file`` (optional)
Path to the Composer manifest to synchronize. Default:
``Factory::getComposerFile()``.
``composer.json``.

``--funding-file`` (optional)
Path to the GitHub funding file to synchronize. Default:
Expand Down
2 changes: 1 addition & 1 deletion docs/commands/metrics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Options
Comma-separated directories that should be excluded from analysis.

Default:
``vendor,tmp,cache,spec,build,.dev-tools,backup,resources,tests/Fixtures``.
``vendor,tmp,cache,spec,build,.dev-tools,backup,resources``.

``--target=<directory>``
Output directory for the generated metrics reports.
Expand Down
1 change: 1 addition & 0 deletions docs/commands/phpdoc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Description
-----------

The ``phpdoc`` command coordinates PHPDoc checking and fixing using:
(alias ``docheader`` and ``php-cs-fixer``)

- PHP-CS-Fixer - fixes PHPDoc formatting
- Rector with ``AddMissingMethodPhpDocRector`` - adds missing method PHPDoc
Expand Down
2 changes: 1 addition & 1 deletion src/Changelog/Checker/UnreleasedEntryChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function hasPendingChanges(string $file, ?string $againstReference = null
}

try {
$baseline = $this->gitClient->show($againstReference, $file, $this->filesystem->dirname($file));
$baseline = $this->gitClient->show($againstReference, $file, $this->filesystem->getDirectory($file));
} catch (Throwable) {
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Changelog/Manager/ChangelogManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ private function persist(string $file, ChangelogDocument $document): void
{
$this->filesystem->dumpFile(
$file,
$this->renderer->render($document, $this->resolveRepositoryUrl($this->filesystem->dirname($file))),
$this->renderer->render($document, $this->resolveRepositoryUrl($this->filesystem->getDirectory($file))),
);
}
}
31 changes: 26 additions & 5 deletions src/Composer/Capability/DevToolsCommandProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

namespace FastForward\DevTools\Composer\Capability;

use Composer\Command\BaseCommand;
use Composer\Plugin\Capability\CommandProvider;
use FastForward\DevTools\Composer\Command\ProxyCommand;
use FastForward\DevTools\Console\DevTools;

/**
Expand All @@ -29,14 +29,35 @@
*/
final class DevToolsCommandProvider implements CommandProvider
{
/**
* @var string the namespace prefix for dev-tools console commands to be registered as Composer commands
*/
private const string COMMAND_NAMESPACE = 'FastForward\DevTools\Console\Command';

/**
* {@inheritDoc}
*/
public function getCommands()
{
return array_values(array_filter(
DevTools::create()->all(),
static fn(object $command): bool => $command instanceof BaseCommand,
));
$commands = [];

foreach (DevTools::create()->all() as $registeredName => $command) {
/**
* Composer plugin registrations must be canonicalized to one command per Symfony command.
* The application exposes alias keys in `all()`, but Composer interprets each entry as
* an independent command and emits override warnings.
*/
if ($registeredName !== $command->getName()) {
continue;
}

if (! str_starts_with($command::class, self::COMMAND_NAMESPACE)) {
continue;
}

$commands[] = new ProxyCommand($command);
}

return $commands;
}
}
58 changes: 58 additions & 0 deletions src/Composer/Command/ProxyCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

/**
* Fast Forward Development Tools for PHP projects.
*
* This file is part of fast-forward/dev-tools project.
*
* @author Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
* @license https://opensource.org/licenses/MIT MIT License
*
* @see https://github.com/php-fast-forward/
* @see https://github.com/php-fast-forward/dev-tools
* @see https://github.com/php-fast-forward/dev-tools/issues
* @see https://php-fast-forward.github.io/dev-tools/
* @see https://datatracker.ietf.org/doc/html/rfc2119
*/

namespace FastForward\DevTools\Composer\Command;

use Composer\Command\BaseCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Adapts migrated Symfony commands to Composer's BaseCommand contract.
*/
final class ProxyCommand extends BaseCommand
{
/**
* @param Command $command the Symfony command adapted for Composer plugin execution
*/
public function __construct(
private readonly Command $command,
) {
parent::__construct($this->command->getName());

$this
->setAliases($this->command->getAliases())
->setDescription($this->command->getDescription())
->setHelp($this->command->getHelp())
->setDefinition(clone $this->command->getDefinition())
->setHidden($this->command->isHidden());
}

/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
return $this->command->run($input, $output);
}
}
Loading
Loading