Skip to content

Commit 58e2022

Browse files
[process] Stop forcing PTY for queued processes (#171) (#229)
* [process] Stop forcing PTY for queued processes (#171) * Update wiki submodule pointer for PR #229 --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent da58692 commit 58e2022

5 files changed

Lines changed: 21 additions & 22 deletions

File tree

.github/wiki

Submodule wiki updated from 077086a to fc94a14

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2323
- Keep Composer plugin command discovery compatible with consumer environments by moving unsupported Symfony Console named parameters out of command metadata/configuration and by decoupling the custom filesystem wrapper from Composer's bundled Symfony Filesystem signatures (#185)
2424
- Keep Composer autoload, Rector, and ECS from traversing nested fixture `vendor` directories when the composer-plugin consumer fixture has installed dependencies (#179)
2525
- Skip LICENSE generation cleanly when a consumer composer manifest omits or leaves the `license` field empty (#227)
26+
- Run nested DevTools subprocesses without forcing PTY, fixing aggregate commands in non-interactive environments (#171)
2627

2728
## [1.20.0] - 2026-04-23
2829

docs/troubleshooting.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ Likely causes:
142142
- a tool is prompting for confirmation;
143143
- CI is missing required environment variables.
144144

145+
DevTools streams child-process output through Symfony Process callbacks rather
146+
than forcing pseudo-terminal execution. Aggregated commands such as
147+
``reports``, ``standards``, and ``dev-tools:fix`` MUST keep nested commands
148+
non-PTY in CI or other non-interactive process runners.
149+
145150
Recovery:
146151

147152
.. code-block:: bash

src/Process/ProcessQueue.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ public function add(
8787
bool $detached = false,
8888
?string $label = null
8989
): void {
90-
if (Process::isPtySupported()) {
91-
$process->setPty(true);
92-
}
93-
9490
$this->entries[] = [
9591
'process' => $process,
9692
'ignoreFailure' => $ignoreFailure,

tests/Process/ProcessQueueTest.php

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,24 @@ protected function setUp(): void
7676
}
7777

7878
/**
79-
* @param ObjectProphecy<Process> $process
80-
*
8179
* @return void
8280
*/
83-
private function expectPtyConfiguration(ObjectProphecy $process): void
81+
#[Test]
82+
public function addWillNotEnablePtyForQueuedProcesses(): void
8483
{
85-
if (! Process::isPtySupported()) {
86-
return;
87-
}
84+
$process = $this->prophesize(Process::class);
85+
$process->setPty(Argument::any())
86+
->shouldNotBeCalled();
87+
$process->run(Argument::any())
88+
->willReturn(ProcessQueueInterface::SUCCESS);
89+
$process->getExitCode()
90+
->willReturn(ProcessQueueInterface::SUCCESS);
91+
$process->isRunning()
92+
->willReturn(false);
8893

89-
$process->setPty(true)
90-
->willReturn($process->reveal())
91-
->shouldBeCalled();
94+
$this->queue->add($process->reveal());
95+
96+
self::assertSame(ProcessQueueInterface::SUCCESS, $this->queue->run($this->output->reveal()));
9297
}
9398

9499
/**
@@ -102,7 +107,6 @@ private function createBlockingProcessMock(
102107
bool $isRunning = false,
103108
): ObjectProphecy {
104109
$process = $this->prophesize(Process::class);
105-
$this->expectPtyConfiguration($process);
106110
$process->run(Argument::any())
107111
->willReturn($exitCode ?? ProcessQueueInterface::FAILURE);
108112
$process->getCommandLine()
@@ -127,7 +131,6 @@ private function createBlockingProcessMock(
127131
private function createDetachedProcessMock(bool ...$runningSequence): ObjectProphecy
128132
{
129133
$process = $this->prophesize(Process::class);
130-
$this->expectPtyConfiguration($process);
131134
$process->getCommandLine()
132135
->willReturn('test-command');
133136
$process->getWorkingDirectory()
@@ -212,7 +215,6 @@ public function runWithNullExitCodeReturnsFailure(): void
212215
public function runBlockingProcessExceptionReturnsFailure(): void
213216
{
214217
$process = $this->prophesize(Process::class);
215-
$this->expectPtyConfiguration($process);
216218
$process->getCommandLine()
217219
->willReturn('test-command');
218220
$process->getWorkingDirectory()
@@ -249,7 +251,6 @@ public function runDetachedProcessStartsWithoutBlockingAndWaitsAtTheEnd(): void
249251
public function runDetachedProcessStartFailureReturnsFailure(): void
250252
{
251253
$process = $this->prophesize(Process::class);
252-
$this->expectPtyConfiguration($process);
253254
$process->getCommandLine()
254255
->willReturn('test-command');
255256
$process->getWorkingDirectory()
@@ -271,7 +272,6 @@ public function runDetachedProcessStartFailureReturnsFailure(): void
271272
public function runDetachedProcessStartFailureWithIgnoreFailureReturnsSuccess(): void
272273
{
273274
$process = $this->prophesize(Process::class);
274-
$this->expectPtyConfiguration($process);
275275
$process->getCommandLine()
276276
->willReturn('test-command');
277277
$process->getWorkingDirectory()
@@ -295,7 +295,6 @@ public function runWillWriteBlockingProcessOutputToStandardAndErrorOutputs(): vo
295295
$capturedCallback = null;
296296

297297
$process = $this->prophesize(Process::class);
298-
$this->expectPtyConfiguration($process);
299298
$process->run(Argument::that(function ($callback) use (&$capturedCallback): bool {
300299
$capturedCallback = $callback;
301300

@@ -335,7 +334,6 @@ public function waitWillFlushFinishedDetachedOutputWithoutWaitingForEveryProcess
335334
$capturedSecondCallback = null;
336335

337336
$firstProcess = $this->prophesize(Process::class);
338-
$this->expectPtyConfiguration($firstProcess);
339337
$firstProcess->getCommandLine()
340338
->willReturn('first-command');
341339
$firstProcess->getWorkingDirectory()
@@ -355,7 +353,6 @@ public function waitWillFlushFinishedDetachedOutputWithoutWaitingForEveryProcess
355353
})->shouldBeCalled();
356354

357355
$secondProcess = $this->prophesize(Process::class);
358-
$this->expectPtyConfiguration($secondProcess);
359356
$secondProcess->getCommandLine()
360357
->willReturn('second-command');
361358
$secondProcess->getWorkingDirectory()

0 commit comments

Comments
 (0)