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:
Robin Chalas 2018-09-23 12:04:26 +02:00
commit 54bd905cb0
2 changed files with 75 additions and 10 deletions

View File

@ -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;
}
}

View File

@ -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.