Skip to content

Commit

Permalink
feature symfony#57426 [Messenger] Add --format option to the `messe…
Browse files Browse the repository at this point in the history
…nger:stats` command (xvilo)

This PR was squashed before being merged into the 7.2 branch.

Discussion
----------

[Messenger] Add `--format` option to the `messenger:stats` command

| Q             | A
| ------------- | ---
| Branch?       | 7.2
| Bug fix?      | no
| New feature?  | yes <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Issues        | Fix symfony#48583 <!-- prefix each issue number with "Fix #", no need to create an issue if none exists, explain below instead -->
| License       | MIT

As requested in symfony#48583 add a way to output different in formats for `messenger:stats` command. This can be more easily used in, for example, `jq` or with external automations/scripts and such.

Considerations I made:
- To not, yet, make different classes for the output. In case a new output format is added this might be handy.
- To not use an enum for output format, do we want this?
- To ignore warnings for now, except for the `uncountable_transports`. If we want to warning in there, what format?

Commits
-------

0e9f458 [Messenger] Add `--format` option to the `messenger:stats` command
  • Loading branch information
fabpot committed Jun 25, 2024
2 parents cd255c3 + 0e9f458 commit ce67e41
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/Messenger/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

7.2
---

* Add `--format` option to the `messenger:stats` command

7.1
---

Expand Down
56 changes: 54 additions & 2 deletions src/Symfony/Component/Messenger/Command/StatsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface;

/**
Expand All @@ -36,8 +38,10 @@ public function __construct(

protected function configure(): void
{
$outputFormats = implode(', ', $this->getAvailableFormatOptions());
$this
->addArgument('transport_names', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'List of transports\' names')
->addOption('format', '', InputOption::VALUE_REQUIRED, 'The output format, e.g.: '.$outputFormats, 'text', $this->getAvailableFormatOptions())
->setHelp(<<<EOF
The <info>%command.name%</info> command counts the messages for all the transports:
Expand All @@ -46,6 +50,11 @@ protected function configure(): void
Or specific transports only:
<info>php %command.full_name% <transportNames></info>
The <info>--format</info> option specifies the format of command output,
these are "{$outputFormats}".
<info>php %command.full_name% --format=json</info>
EOF
)
;
Expand All @@ -55,6 +64,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);

$format = $input->getOption('format');
if (!\in_array($format, $this->getAvailableFormatOptions(), true)) {
throw new InvalidArgumentException('Invalid output format.');
}

$transportNames = $this->transportNames;
if ($input->getArgument('transport_names')) {
$transportNames = $input->getArgument('transport_names');
Expand All @@ -64,7 +78,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$uncountableTransports = [];
foreach ($transportNames as $transportName) {
if (!$this->transportLocator->has($transportName)) {
$io->warning(\sprintf('The "%s" transport does not exist.', $transportName));
if ($this->formatSupportsWarnings($format)) {
$io->warning(\sprintf('The "%s" transport does not exist.', $transportName));
}

continue;
}
Expand All @@ -77,12 +93,48 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$outputTable[] = [$transportName, $transport->getMessageCount()];
}

match ($format) {
'text' => $this->outputText($io, $outputTable, $uncountableTransports),
'json' => $this->outputJson($io, $outputTable, $uncountableTransports),
};

return 0;
}

private function outputText(SymfonyStyle $io, array $outputTable, array $uncountableTransports): void
{
$io->table(['Transport', 'Count'], $outputTable);

if ($uncountableTransports) {
$io->note(\sprintf('Unable to get message count for the following transports: "%s".', implode('", "', $uncountableTransports)));
}
}

return 0;
private function outputJson(SymfonyStyle $io, array $outputTable, array $uncountableTransports): void
{
$output = ['transports' => []];
foreach ($outputTable as [$transportName, $count]) {
$output['transports'][$transportName] = ['count' => $count];
}

if ($uncountableTransports) {
$output['uncountable_transports'] = $uncountableTransports;
}

$io->writeln(json_encode($output, \JSON_PRETTY_PRINT));
}

private function formatSupportsWarnings(string $format): bool
{
return match ($format) {
'text' => true,
'json' => false,
};
}

/** @return string[] */
private function getAvailableFormatOptions(): array
{
return ['text', 'json'];
}
}
44 changes: 44 additions & 0 deletions src/Symfony/Component/Messenger/Tests/Command/StatsCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ public function testWithoutArgument()
$this->assertStringContainsString('! [NOTE] Unable to get message count for the following transports: "simple".', $display);
}

public function testWithoutArgumentJsonFormat()
{
$tester = new CommandTester($this->command);
$tester->execute(['--format' => 'json']);
$display = $tester->getDisplay();

$this->assertJsonStringEqualsJsonString('{
"transports": {
"message_countable": {"count": 6},
"another_message_countable": {"count": 6}
},
"uncountable_transports": [
"simple"
]
}', $display);
}

public function testWithOneExistingMessageCountableTransport()
{
$tester = new CommandTester($this->command);
Expand All @@ -81,6 +98,19 @@ public function testWithOneExistingMessageCountableTransport()
$this->assertStringNotContainsString(' ! [NOTE] Unable to get message count for the following transports: "simple".', $display);
}

public function testWithOneExistingMessageCountableTransportJsonFormat()
{
$tester = new CommandTester($this->command);
$tester->execute(['transport_names' => ['message_countable'], '--format' => 'json']);
$display = $tester->getDisplay();

$this->assertJsonStringEqualsJsonString('{
"transports": {
"message_countable": {"count": 6}
}
}', $display);
}

public function testWithMultipleExistingMessageCountableTransport()
{
$tester = new CommandTester($this->command);
Expand All @@ -93,6 +123,20 @@ public function testWithMultipleExistingMessageCountableTransport()
$this->assertStringNotContainsString('! [NOTE] Unable to get message count for the following transports: "simple".', $display);
}

public function testWithMultipleExistingMessageCountableTransportJsonFormat()
{
$tester = new CommandTester($this->command);
$tester->execute(['transport_names' => ['message_countable', 'another_message_countable'], '--format' => 'json']);
$display = $tester->getDisplay();

$this->assertJsonStringEqualsJsonString('{
"transports": {
"message_countable": {"count": 6},
"another_message_countable": {"count": 6}
}
}', $display);
}

public function testWithNotMessageCountableTransport()
{
$tester = new CommandTester($this->command);
Expand Down

0 comments on commit ce67e41

Please sign in to comment.