bug #28545 [Console] Send the right exit code to console.terminate listeners (mpdude)
This PR was squashed before being merged into the 2.8 branch (closes #28545).
Discussion
----------
[Console] Send the right exit code to console.terminate listeners
| Q | A
| ------------- | ---
| Branch? | 2.8
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets |
| License | MIT
| Doc PR |
When a Console command throws an exception without a status code, `Application::run()` takes care of setting the exit code to `1` when the exception does not provide a code itself.
This happens slightly too late, as `console.terminate` event listeners that are called from within `Application::doRunCommand()` are given the plain exeception code, before this conversion.
The result is that `console.*` event listeners that you might be using to log exit code e. g. for cron jobs will see a `0` code instead of the real value used to terminate the script.
***Todo:***
- [x] Make sure we've got tests covering this, i. e. do not mock out `doRunCommand()`.
Commits
-------
b90a3f1
[Console] Send the right exit code to console.terminate listeners
This commit is contained in:
commit
54bd905cb0
@ -129,15 +129,7 @@ class Application
|
||||
$this->renderException($e, $output);
|
||||
}
|
||||
|
||||
$exitCode = $e->getCode();
|
||||
if (is_numeric($exitCode)) {
|
||||
$exitCode = (int) $exitCode;
|
||||
if (0 === $exitCode) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
} else {
|
||||
$exitCode = 1;
|
||||
}
|
||||
$exitCode = $this->getExitCodeForThrowable($e);
|
||||
}
|
||||
|
||||
if ($this->autoExit) {
|
||||
@ -873,7 +865,8 @@ class Application
|
||||
if ($x !== $event->getException()) {
|
||||
$e = $event->getException();
|
||||
}
|
||||
$exitCode = $e->getCode();
|
||||
|
||||
$exitCode = $this->getExitCodeForThrowable($e);
|
||||
}
|
||||
|
||||
$event = new ConsoleTerminateEvent($command, $input, $output, $exitCode);
|
||||
@ -1148,4 +1141,26 @@ class Application
|
||||
$this->add($command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type hint omitted to be PHP5 compatible.
|
||||
*
|
||||
* @param \Exception|\Throwable $throwable
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getExitCodeForThrowable($throwable)
|
||||
{
|
||||
$exitCode = $throwable->getCode();
|
||||
if (is_numeric($exitCode)) {
|
||||
$exitCode = (int) $exitCode;
|
||||
if (0 === $exitCode) {
|
||||
$exitCode = 1;
|
||||
}
|
||||
} else {
|
||||
$exitCode = 1;
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
}
|
||||
|
@ -774,6 +774,31 @@ class ApplicationTest extends TestCase
|
||||
$this->assertSame(4, $exitCode, '->run() returns integer exit code extracted from raised exception');
|
||||
}
|
||||
|
||||
public function testRunDispatchesIntegerExitCode()
|
||||
{
|
||||
$passedRightValue = false;
|
||||
|
||||
// We can assume here that some other test asserts that the event is dispatched at all
|
||||
$dispatcher = new EventDispatcher();
|
||||
$self = $this;
|
||||
$dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($self, &$passedRightValue) {
|
||||
$passedRightValue = (4 === $event->getExitCode());
|
||||
});
|
||||
|
||||
$application = new Application();
|
||||
$application->setDispatcher($dispatcher);
|
||||
$application->setAutoExit(false);
|
||||
|
||||
$application->register('test')->setCode(function (InputInterface $input, OutputInterface $output) {
|
||||
throw new \Exception('', 4);
|
||||
});
|
||||
|
||||
$tester = new ApplicationTester($application);
|
||||
$tester->run(array('command' => 'test'));
|
||||
|
||||
$this->assertTrue($passedRightValue, '-> exit code 4 was passed in the console.terminate event');
|
||||
}
|
||||
|
||||
public function testRunReturnsExitCodeOneForExceptionCodeZero()
|
||||
{
|
||||
$exception = new \Exception('', 0);
|
||||
@ -789,6 +814,31 @@ class ApplicationTest extends TestCase
|
||||
$this->assertSame(1, $exitCode, '->run() returns exit code 1 when exception code is 0');
|
||||
}
|
||||
|
||||
public function testRunDispatchesExitCodeOneForExceptionCodeZero()
|
||||
{
|
||||
$passedRightValue = false;
|
||||
|
||||
// We can assume here that some other test asserts that the event is dispatched at all
|
||||
$dispatcher = new EventDispatcher();
|
||||
$self = $this;
|
||||
$dispatcher->addListener('console.terminate', function (ConsoleTerminateEvent $event) use ($self, &$passedRightValue) {
|
||||
$passedRightValue = (1 === $event->getExitCode());
|
||||
});
|
||||
|
||||
$application = new Application();
|
||||
$application->setDispatcher($dispatcher);
|
||||
$application->setAutoExit(false);
|
||||
|
||||
$application->register('test')->setCode(function (InputInterface $input, OutputInterface $output) {
|
||||
throw new \Exception();
|
||||
});
|
||||
|
||||
$tester = new ApplicationTester($application);
|
||||
$tester->run(array('command' => 'test'));
|
||||
|
||||
$this->assertTrue($passedRightValue, '-> exit code 1 was passed in the console.terminate event');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage An option with shortcut "e" already exists.
|
||||
|
Reference in New Issue
Block a user