Skip to content

Commit a18ed8f

Browse files
committed
feature symfony#53632 [Console] Add silent verbosity suppressing all output, including errors (wouterj)
This PR was merged into the 7.2 branch. Discussion ---------- [Console] Add silent verbosity suppressing all output, including errors | Q | A | ------------- | --- | Branch? | 7.2 | Bug fix? | no | New feature? | yes | Deprecations? | yes | Issues | Fix symfony#52777 | License | MIT <details> <summary>Original PR description</summary> Alternative to symfony#53126 In Symfony 2.8, we decided to still show exceptions/errors when running a command with `--quiet` or `SHELL_VERBOSITY=-1` (symfony#15680). Since that time, we've introduced the ConsoleLogger and 12-factor app logic. In todays landscape, it's more common to run commands that only output computer-readable text (e.g. JSON), which is ingested and displayed by services like Datadog and Kibana. Our decision from 2.8 breaks this, as the JSON is interrupted by human-readable exception output that users can't disable. At the same time, this information is duplicated as errors are always logged (and thus shown as JSON). I think we should revert the 2.8 decision, rather than adding a new "extremely quiet" verbosity mode. As far as I'm aware, this is also more consistent with normal unix commands which also don't output anything when passing `--quiet`. I don't think this warrants as a BC break, as the errors are human readable and we don't promise BC on human readable console output (afaik, we don't promise BC on any console output, but I think we should be careful when changing e.g. the JSON logging). </details> This updated PR adds a new `--silent` verbosity mode that suppresses all output, including exceptions caught by the Application. I went back and forth between simply passing `NullOutput` to the command in silent mode or not ignoring everything written to silent mode in `Output`. In the end, I've decided for the last to avoid bug reports from people silently expecting a `ConsoleOutputInterface` in their commands (e.g. for sections) without properly guarding it. The new `isSilent()` methods can be used by commands to e.g. write important messages to the logger instead of command output when running in silent mode. Commits ------- 57fe0bd [Console] Add silent verbosity mode suppressing all output, including errors
2 parents 3f02756 + 57fe0bd commit a18ed8f

29 files changed

+392
-61
lines changed

UPGRADE-7.2.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ Cache
1414
* `igbinary_serialize()` is not used by default when the igbinary extension is installed
1515
* Deprecate making `cache.app` adapter taggable, use the `cache.app.taggable` adapter instead
1616

17+
Console
18+
-------
19+
20+
* [BC BREAK] Add ``--silent`` global option to enable the silent verbosity mode (suppressing all output, including errors)
21+
If a custom command defines the `silent` option, it must be renamed before upgrading.
22+
* Add `isSilent()` method to `OutputInterface`
23+
1724
DependencyInjection
1825
-------------------
1926

src/Symfony/Component/Console/Application.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,9 @@ protected function configureIO(InputInterface $input, OutputInterface $output):
913913
}
914914

915915
switch ($shellVerbosity = (int) getenv('SHELL_VERBOSITY')) {
916+
case -2:
917+
$output->setVerbosity(OutputInterface::VERBOSITY_SILENT);
918+
break;
916919
case -1:
917920
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
918921
break;
@@ -930,7 +933,10 @@ protected function configureIO(InputInterface $input, OutputInterface $output):
930933
break;
931934
}
932935

933-
if (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
936+
if (true === $input->hasParameterOption(['--silent'], true)) {
937+
$output->setVerbosity(OutputInterface::VERBOSITY_SILENT);
938+
$shellVerbosity = -2;
939+
} elseif (true === $input->hasParameterOption(['--quiet', '-q'], true)) {
934940
$output->setVerbosity(OutputInterface::VERBOSITY_QUIET);
935941
$shellVerbosity = -1;
936942
} else {
@@ -946,7 +952,7 @@ protected function configureIO(InputInterface $input, OutputInterface $output):
946952
}
947953
}
948954

949-
if (-1 === $shellVerbosity) {
955+
if (0 > $shellVerbosity) {
950956
$input->setInteractive(false);
951957
}
952958

@@ -1082,7 +1088,8 @@ protected function getDefaultInputDefinition(): InputDefinition
10821088
return new InputDefinition([
10831089
new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'),
10841090
new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the <info>'.$this->defaultCommand.'</info> command'),
1085-
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'),
1091+
new InputOption('--silent', null, InputOption::VALUE_NONE, 'Do not output any message'),
1092+
new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Only errors are displayed. All other output is suppressed'),
10861093
new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'),
10871094
new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'),
10881095
new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null),

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ CHANGELOG
66

77
* Add support for `FORCE_COLOR` environment variable
88
* Add `verbosity` argument to `mustRun` process helper method
9+
* [BC BREAK] Add silent verbosity (`--silent`/`SHELL_VERBOSITY=-2`) to suppress all output, including errors
10+
* Add `OutputInterface::isSilent()`, `Output::isSilent()`, `OutputStyle::isSilent()` methods
911

1012
7.1
1113
---

src/Symfony/Component/Console/Descriptor/ReStructuredTextDescriptor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ private function getNonDefaultOptions(InputDefinition $definition): array
217217
{
218218
$globalOptions = [
219219
'help',
220+
'silent',
220221
'quiet',
221222
'verbose',
222223
'version',

src/Symfony/Component/Console/Output/NullOutput.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ public function setVerbosity(int $level): void
5454

5555
public function getVerbosity(): int
5656
{
57-
return self::VERBOSITY_QUIET;
57+
return self::VERBOSITY_SILENT;
5858
}
5959

60-
public function isQuiet(): bool
60+
public function isSilent(): bool
6161
{
6262
return true;
6363
}
6464

65+
public function isQuiet(): bool
66+
{
67+
return false;
68+
}
69+
6570
public function isVerbose(): bool
6671
{
6772
return false;

src/Symfony/Component/Console/Output/Output.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
/**
1818
* Base class for output classes.
1919
*
20-
* There are five levels of verbosity:
20+
* There are six levels of verbosity:
2121
*
2222
* * normal: no option passed (normal output)
2323
* * verbose: -v (more output)
2424
* * very verbose: -vv (highly extended output)
2525
* * debug: -vvv (all debug output)
26-
* * quiet: -q (no output)
26+
* * quiet: -q (only output errors)
27+
* * silent: --silent (no output)
2728
*
2829
* @author Fabien Potencier <[email protected]>
2930
*/
@@ -74,6 +75,11 @@ public function getVerbosity(): int
7475
return $this->verbosity;
7576
}
7677

78+
public function isSilent(): bool
79+
{
80+
return self::VERBOSITY_SILENT === $this->verbosity;
81+
}
82+
7783
public function isQuiet(): bool
7884
{
7985
return self::VERBOSITY_QUIET === $this->verbosity;

src/Symfony/Component/Console/Output/OutputInterface.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@
1717
* OutputInterface is the interface implemented by all Output classes.
1818
*
1919
* @author Fabien Potencier <[email protected]>
20+
*
21+
* @method bool isSilent()
2022
*/
2123
interface OutputInterface
2224
{
25+
public const VERBOSITY_SILENT = 8;
2326
public const VERBOSITY_QUIET = 16;
2427
public const VERBOSITY_NORMAL = 32;
2528
public const VERBOSITY_VERBOSE = 64;

src/Symfony/Component/Console/Style/OutputStyle.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ public function getFormatter(): OutputFormatterInterface
7878
return $this->output->getFormatter();
7979
}
8080

81+
public function isSilent(): bool
82+
{
83+
// @deprecated since Symfony 7.2, change to $this->output->isSilent() in 8.0
84+
return method_exists($this->output, 'isSilent') ? $this->output->isSilent() : self::VERBOSITY_SILENT === $this->output->getVerbosity();
85+
}
86+
8187
public function isQuiet(): bool
8288
{
8389
return $this->output->isQuiet();

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,12 +851,15 @@ public function testRenderException()
851851
putenv('COLUMNS=120');
852852
$tester = new ApplicationTester($application);
853853

854-
$tester->run(['command' => 'foo'], ['decorated' => false, 'capture_stderr_separately' => true]);
854+
$tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_QUIET, 'capture_stderr_separately' => true]);
855855
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception1.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exception');
856856

857857
$tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE, 'capture_stderr_separately' => true]);
858858
$this->assertStringContainsString('Exception trace', $tester->getErrorOutput(), '->renderException() renders a pretty exception with a stack trace when verbosity is verbose');
859859

860+
$tester->run(['command' => 'foo'], ['decorated' => false, 'verbosity' => Output::VERBOSITY_SILENT, 'capture_stderr_separately' => true]);
861+
$this->assertSame('', $tester->getErrorOutput(true), '->renderException() renders nothing in SILENT verbosity');
862+
860863
$tester->run(['command' => 'list', '--foo' => true], ['decorated' => false, 'capture_stderr_separately' => true]);
861864
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception2.txt', $tester->getErrorOutput(true), '->renderException() renders the command synopsis when an exception occurs in the context of a command');
862865

src/Symfony/Component/Console/Tests/Command/CompleteCommandTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ public function testCompleteCommandInputDefinition(array $input, array $suggesti
119119

120120
public static function provideCompleteCommandInputDefinitionInputs()
121121
{
122-
yield 'definition' => [['bin/console', 'hello', '-'], ['--help', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']];
122+
yield 'definition' => [['bin/console', 'hello', '-'], ['--help', '--silent', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']];
123123
yield 'custom' => [['bin/console', 'hello'], ['Fabien', 'Robin', 'Wouter']];
124-
yield 'definition-aliased' => [['bin/console', 'ahoy', '-'], ['--help', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']];
124+
yield 'definition-aliased' => [['bin/console', 'ahoy', '-'], ['--help', '--silent', '--quiet', '--verbose', '--version', '--ansi', '--no-ansi', '--no-interaction']];
125125
yield 'custom-aliased' => [['bin/console', 'ahoy'], ['Fabien', 'Robin', 'Wouter']];
126126
}
127127

0 commit comments

Comments
 (0)