Skip to content

Commit 6885b0a

Browse files
committed
fix: preserve nested process color output
1 parent 979cc87 commit 6885b0a

42 files changed

Lines changed: 1136 additions & 104 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,24 @@ composer dev-tools tests -- --coverage=.dev-tools/coverage
111111
- Rector rules: `src/Rector/`
112112
- Composer plugin: `src/Composer/`
113113

114+
**Architecture Direction:**
115+
116+
- Avoid introducing new dependencies on `composer/composer` outside the
117+
existing Composer plugin integration and legacy surfaces already awaiting
118+
decoupling.
119+
- Prefer DevTools-owned interfaces for generic runtime concerns such as
120+
environment variables, process execution, filesystem access, and console
121+
presentation instead of reaching for Composer utility classes.
122+
- When an existing Composer utility is convenient, first check whether a small
123+
local abstraction would support the ongoing Composer decoupling work with
124+
minimal code.
125+
- During the Composer-to-Symfony command migration, preserve the global
126+
execution affordances already relied on by nested tools: `--ansi`/`--no-ansi`,
127+
cache and `--cache-dir` handling, and working-directory behavior.
128+
- Keep color behavior explicit in command wrappers for tools with known flags
129+
instead of probing binaries dynamically; for example, Symfony/Composer-style
130+
tools can receive `--ansi`, while PHPUnit uses `--colors=always`.
131+
114132
**Naming Conventions:**
115133

116134
- Classes: PascalCase

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414

1515
### Fixed
1616

17+
- Preserve color-friendly nested command environments, explicit Symfony Console ANSI flags, concise process section labels, and offline-safe PhpMetrics execution without restoring PTY (#239)
1718
- Keep the reports workflow permission warning loop shell-safe for paths containing backslashes (#244)
1819
- Keep required PHPUnit matrix checks reporting after workflow-managed `.github/wiki` pointer commits by running the pull-request test workflow without top-level path filters and aligning the packaged consumer test wrapper (#230)
1920
- Publish pending and per-version required PHPUnit statuses for workflow-dispatched test runs so wiki pointer commits do not wait for an all-matrix aggregate status (#230)

docs/commands/metrics.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,6 @@ Behavior
9393
- ``--json`` and ``--pretty-json`` keep DevTools itself structured while
9494
running PhpMetrics in a quieter mode to avoid polluting the captured payload;
9595
- it runs PhpMetrics through the active PHP binary and suppresses PhpMetrics
96-
deprecation notices emitted by the dependency itself.
96+
deprecation notices emitted by the dependency itself;
97+
- it disables PhpMetrics' Composer package freshness lookup so metrics runs do
98+
not block on Packagist availability or local network state.

docs/internals/architecture.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ command list:
7575
- Services
7676
* - ``FastForward\DevTools\Process\ProcessBuilderInterface``
7777
- ``ProcessBuilderInterface`` and ``ProcessQueueInterface`` build and
78-
execute subprocess pipelines.
78+
execute subprocess pipelines, while process environment and output
79+
Symfony-style sections keep nested command output readable without PTY.
7980
* - ``Filesystem and metadata``
8081
- ``FilesystemInterface``, ``ComposerJsonInterface``, and
8182
``FileLocatorInterface`` resolve local files, project metadata, and

docs/running/specialized-commands.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ Important details:
132132
structured while forwarding JSON or quieter modes to the wrapped tools where
133133
available;
134134
- it suppresses deprecation notices emitted by the PhpMetrics dependency
135-
itself so the command output stays readable.
135+
itself so the command output stays readable;
136+
- it disables PhpMetrics' Composer package freshness lookup so report
137+
generation does not depend on Packagist connectivity.
136138

137139
``code-style``
138140
--------------
@@ -270,6 +272,9 @@ Important details:
270272
``--progress`` re-enables it for human-readable runs;
271273
- ``--json`` and ``--pretty-json`` are propagated to each subprocess, while
272274
their progress output is suppressed where supported;
275+
- human-readable runs keep nested command output grouped with concise local
276+
section boundaries, pass color-friendly environment variables to
277+
subprocesses, and forward explicit ANSI flags to Symfony Console tools;
273278
- it is the reporting stage used by ``standards``.
274279

275280
``skills``

src/Console/Command/CodeStyleCommand.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
132132
->build('composer normalize');
133133

134134
$processBuilder = $this->processBuilder
135+
->withArgument('--ansi')
135136
->withArgument('--config', $this->fileLocator->locate(self::CONFIG));
136137

137138
if (! $progress) {
@@ -148,9 +149,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
148149

149150
$ecs = $processBuilder->build('vendor/bin/ecs');
150151

151-
$this->processQueue->add($composerUpdate);
152-
$this->processQueue->add($composerNormalize);
153-
$this->processQueue->add($ecs);
152+
$this->processQueue->add(process: $composerUpdate, label: 'Refreshing Composer Lock');
153+
$this->processQueue->add(
154+
process: $composerNormalize,
155+
label: 'Normalizing composer.json with Composer Normalize'
156+
);
157+
$this->processQueue->add(process: $ecs, label: 'Checking Code Style with Easy Coding Standard');
154158

155159
$result = $this->processQueue->run($processOutput);
156160

src/Console/Command/DependenciesCommand.php

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int
129129
return $this->failure($invalidArgumentException->getMessage(), $input);
130130
}
131131

132-
$this->processQueue->add($this->getRaiseToInstalledCommand($input));
133-
$this->processQueue->add($this->getOpenVersionsCommand($input));
132+
$this->processQueue->add(
133+
process: $this->getRaiseToInstalledCommand($input),
134+
label: 'Raising Dependency Constraints with Jack',
135+
);
136+
$this->processQueue->add(
137+
process: $this->getOpenVersionsCommand($input),
138+
label: 'Opening Dependency Constraints with Jack',
139+
);
134140

135141
if ($input->getOption('upgrade')) {
136-
$this->processQueue->add($this->getComposerUpdateCommand());
137-
$this->processQueue->add($this->getComposerNormalizeCommand());
142+
$this->processQueue->add(
143+
process: $this->getComposerUpdateCommand(),
144+
label: 'Updating Dependencies with Composer'
145+
);
146+
$this->processQueue->add(
147+
process: $this->getComposerNormalizeCommand(),
148+
label: 'Normalizing composer.json with Composer Normalize',
149+
);
138150
}
139151

140152
if (! $jsonOutput) {
@@ -143,10 +155,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
143155
]);
144156
}
145157

146-
$this->processQueue->add($this->getComposerDependencyAnalyserCommand($input));
147158
$this->processQueue->add(
148-
$this->getJackBreakpointCommand($input, $maximumOutdated),
149-
$this->shouldIgnoreOutdatedFailures($maximumOutdated),
159+
process: $this->getComposerDependencyAnalyserCommand($input),
160+
label: 'Analyzing Dependencies with Composer Dependency Analyser',
161+
);
162+
$this->processQueue->add(
163+
process: $this->getJackBreakpointCommand($input, $maximumOutdated),
164+
ignoreFailure: $this->shouldIgnoreOutdatedFailures($maximumOutdated),
165+
label: 'Checking Outdated Dependencies with Jack',
150166
);
151167

152168
$result = $this->processQueue->run($processOutput);
@@ -279,7 +295,9 @@ private function getComposerUpdateCommand(): Process
279295
*/
280296
private function getComposerNormalizeCommand(): Process
281297
{
282-
return $this->processBuilder->build('composer normalize');
298+
return $this->processBuilder
299+
->withArgument('--ansi')
300+
->build('composer normalize');
283301
}
284302

285303
/**

src/Console/Command/DocsCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
165165

166166
$phpdoc = $processBuilder->build('vendor/bin/phpdoc');
167167

168-
$this->processQueue->add($phpdoc);
168+
$this->processQueue->add(process: $phpdoc, label: 'Generating API Docs with phpDocumentor');
169169

170170
$result = $this->processQueue->run($processOutput);
171171

src/Console/Command/FundingCommand.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,10 @@ private function normalizeComposerFile(string $composerFile, OutputInterface $ou
500500
$processBuilder = $processBuilder->withArgument('--file', $composerBasename);
501501
}
502502

503-
$this->processQueue->add($processBuilder->build('composer normalize'));
503+
$this->processQueue->add(
504+
process: $processBuilder->build('composer normalize'),
505+
label: 'Normalizing composer.json with Composer Normalize',
506+
);
504507

505508
return $this->processQueue->run($output);
506509
}

src/Console/Command/MetricsCommand.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
118118
$processBuilder = $this->processBuilder
119119
->withArgument('--ansi')
120120
->withArgument('--git', 'git')
121+
->withArgument('--composer', 'false')
121122
->withArgument('--exclude', $exclude)
122123
->withArgument('--report-html', $target)
123124
->withArgument('--report-json', $target . '/report.json')
@@ -132,9 +133,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
132133
}
133134

134135
$this->processQueue->add(
135-
$processBuilder
136+
process: $processBuilder
136137
->withArgument('.')
137-
->build([\PHP_BINARY, '-derror_reporting=' . self::PHP_ERROR_REPORTING, self::BINARY])
138+
->build([\PHP_BINARY, '-derror_reporting=' . self::PHP_ERROR_REPORTING, self::BINARY]),
139+
label: 'Generating Metrics with PhpMetrics',
138140
);
139141

140142
$result = $this->processQueue->run($processOutput);

0 commit comments

Comments
 (0)