Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/wiki
Submodule wiki updated from 4782e8 to 7a7e28
9 changes: 5 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Show the DevTools ASCII logo by default on all top-level command executions, while adding a `--no-logo` global option and automatically suppressing the banner for `--json` / `--pretty-json` invocations (including automatic forwarding of `--no-logo` to internal DevTools subprocesses) to avoid banner repetition in orchestrated command queues (#277)

### Added

- Add a configurable DevTools generated artifact workspace through `--workspace-dir` and `FAST_FORWARD_WORKSPACE_DIR`, keeping explicit output/cache command options authoritative (#274)
- Add a standalone DevTools `self-update` command plus global `--working-dir` and `--auto-update` binary options for local or global installations (#272)
- Show the DevTools ASCII logo by default on all top-level command executions, while adding a `--no-logo` global option and automatically suppressing the banner for `--json` / `--pretty-json` invocations (including automatic forwarding of `--no-logo` to internal DevTools subprocesses) to avoid banner repetition in orchestrated command queues (#277)

### Fixed

- Prevent DevTools from breaking changelog workflows by keeping raw output clean for `changelog:show` and `changelog:next-version` (suppressing the startup ASCII logo when these commands run without explicit `--json`/`--pretty-json`) (#280)

## [1.23.0] - 2026-04-26

Expand Down
52 changes: 46 additions & 6 deletions src/Console/DevTools.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ final class DevTools extends Application

LOGO;

/**
* Commands that require raw output and therefore must not render the logo.
*
* @var list<string>
*/
private const array RAW_OUTPUT_COMMANDS = [
'changelog:next-version',
'changelog:show',
];

/**
* @var ContainerInterface holds the static container instance for global access within the DevTools context
*/
Expand Down Expand Up @@ -139,11 +149,7 @@ protected function getDefaultInputDefinition(): InputDefinition
#[Override]
public function doRun(InputInterface $input, OutputInterface $output): int
{
$noLogo = (bool) $input->getParameterOption('--no-logo', null, true)
|| (bool) $input->hasParameterOption('--json', true)
|| (bool) $input->hasParameterOption('--pretty-json', true);

if (! $noLogo) {
if ($this->shouldRenderLogo($input)) {
$output->writeln(self::LOGO);
}

Expand All @@ -156,7 +162,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int
return Command::FAILURE;
}

if (! $noLogo && ! $this->isSelfUpdateCommand($input)) {
if ($this->shouldRenderLogo($input) && ! $this->isSelfUpdateCommand($input)) {
$this->runAutoUpdateWhenRequested($input, $output);
$this->versionCheckNotifier->notify($output);
}
Expand Down Expand Up @@ -243,6 +249,40 @@ private function runAutoUpdateWhenRequested(InputInterface $input, OutputInterfa
}
}

/**
* Determines whether the startup logo should be rendered for this invocation.
*
* @param InputInterface $input the application input
*/
private function shouldRenderLogo(InputInterface $input): bool
{
if ((bool) $input->getParameterOption('--no-logo', null, true)) {
return false;
}

if ((bool) $input->hasParameterOption('--json', true) || (bool) $input->hasParameterOption('--pretty-json', true)) {
return false;
}

return ! $this->isRawOutputCommand($input);
}

/**
* Checks whether the current command is designed for raw output mode.
*
* @param InputInterface $input the application input
*/
private function isRawOutputCommand(InputInterface $input): bool
{
$commandName = $input->getFirstArgument();

if (! is_string($commandName)) {
return false;
}

return \in_array($commandName, self::RAW_OUTPUT_COMMANDS, true);
}

/**
* Detects whether the current invocation targets the self-update command.
*
Expand Down
45 changes: 45 additions & 0 deletions tests/Console/DevToolsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
use Override;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
Expand Down Expand Up @@ -362,6 +363,50 @@ protected function configure(): void
self::assertStringNotContainsString('_____', $output->fetch());
}

/**
* @return void
*/
#[Test]
#[TestWith(['changelog:show'])]
#[TestWith(['changelog:next-version'])]
public function doRunWillNotRenderLogoWhenRawOutputCommandIsRequested(string $commandName): void
{
$command = new class extends Command {
public function __construct()
{
parent::__construct('placeholder');
$this->setCode(static fn(InputInterface $input, OutputInterface $output): int => Command::SUCCESS);
}
};

$command->setName($commandName);

$this->commandLoader->has($commandName)
->willReturn(true)
->shouldBeCalledOnce();
$this->commandLoader->get($commandName)
->willReturn($command)
->shouldBeCalledOnce();

$input = new ArrayInput([
'command' => $commandName,
]);

$output = new BufferedOutput();

$this->environment->get('FAST_FORWARD_AUTO_UPDATE', '')
->willReturn('');
$this->workingDirectorySwitcher->switchTo(null)
->shouldBeCalledOnce();
$this->versionCheckNotifier->notify($output)
->shouldNotBeCalled();

$result = $this->invokeDoRun($input, $output);

self::assertSame(Command::SUCCESS, $result);
self::assertStringNotContainsString('_____', $output->fetch());
}

/**
* @return void
*/
Expand Down
Loading