Skip to content

Commit eb15924

Browse files
Fixed bug that exit code of Command is incorrect when throwing an exception. (#4068)
Co-authored-by: 李铭昕 <715557344@qq.com>
1 parent 805df76 commit eb15924

5 files changed

Lines changed: 137 additions & 3 deletions

File tree

src/Command.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ abstract class Command extends SymfonyCommand
9292
'normal' => OutputInterface::VERBOSITY_NORMAL,
9393
];
9494

95+
/**
96+
* The exit code of the command.
97+
*
98+
* @var int
99+
*/
100+
protected $exitCode = 0;
101+
95102
public function __construct(string $name = null)
96103
{
97104
if (! $name && $this->name) {
@@ -438,15 +445,15 @@ protected function execute(InputInterface $input, OutputInterface $output)
438445
$this->eventDispatcher && $this->eventDispatcher->dispatch(new Event\AfterHandle($this));
439446
} catch (\Throwable $exception) {
440447
if (class_exists(ExitException::class) && $exception instanceof ExitException) {
441-
return 0;
448+
return $this->exitCode = (int) $exception->getStatus();
442449
}
443450

444451
if (! $this->eventDispatcher) {
445452
throw $exception;
446453
}
447454

448455
$this->eventDispatcher->dispatch(new Event\FailToHandle($this, $exception));
449-
return $exception->getCode();
456+
return $this->exitCode = $exception->getCode();
450457
} finally {
451458
$this->eventDispatcher && $this->eventDispatcher->dispatch(new Event\AfterExecute($this));
452459
}
@@ -456,7 +463,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
456463

457464
if ($this->coroutine && ! Coroutine::inCoroutine()) {
458465
run($callback, $this->hookFlags);
459-
return 0;
466+
return $this->exitCode;
460467
}
461468

462469
return $callback();

tests/Command/FooCommand.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Command\Command;
13+
14+
use Hyperf\Command\Command;
15+
16+
class FooCommand extends Command
17+
{
18+
public function handle()
19+
{
20+
}
21+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Command\Command;
13+
14+
use Hyperf\Command\Command;
15+
use Hyperf\Event\EventDispatcher;
16+
use Hyperf\Event\ListenerProvider;
17+
18+
class FooExceptionCommand extends Command
19+
{
20+
public function __construct(string $name = null)
21+
{
22+
parent::__construct($name);
23+
24+
$this->eventDispatcher = new EventDispatcher(
25+
new ListenerProvider()
26+
);
27+
}
28+
29+
public function handle()
30+
{
31+
throw new \RuntimeException('xxx', 99);
32+
}
33+
}

tests/Command/FooExitCommand.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* This file is part of Hyperf.
6+
*
7+
* @link https://www.hyperf.io
8+
* @document https://hyperf.wiki
9+
* @contact group@hyperf.io
10+
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
11+
*/
12+
namespace HyperfTest\Command\Command;
13+
14+
use Hyperf\Command\Command;
15+
use Hyperf\Event\EventDispatcher;
16+
use Hyperf\Event\ListenerProvider;
17+
18+
class FooExitCommand extends Command
19+
{
20+
public function __construct(string $name = null)
21+
{
22+
parent::__construct($name);
23+
24+
$this->eventDispatcher = new EventDispatcher(
25+
new ListenerProvider()
26+
);
27+
}
28+
29+
public function handle()
30+
{
31+
exit('11xxx');
32+
}
33+
}

tests/CommandTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,28 @@
1111
*/
1212
namespace HyperfTest\Command;
1313

14+
use Hyperf\Utils\Reflection\ClassInvoker;
1415
use HyperfTest\Command\Command\DefaultSwooleFlagsCommand;
16+
use HyperfTest\Command\Command\FooCommand;
17+
use HyperfTest\Command\Command\FooExceptionCommand;
18+
use HyperfTest\Command\Command\FooExitCommand;
1519
use HyperfTest\Command\Command\SwooleFlagsCommand;
20+
use Mockery;
1621
use PHPUnit\Framework\TestCase;
22+
use Symfony\Component\Console\Input\InputInterface;
23+
use Symfony\Component\Console\Output\OutputInterface;
1724

1825
/**
1926
* @internal
2027
* @coversNothing
2128
*/
2229
class CommandTest extends TestCase
2330
{
31+
protected function tearDown(): void
32+
{
33+
Mockery::close();
34+
}
35+
2436
public function testHookFlags()
2537
{
2638
$command = new DefaultSwooleFlagsCommand('test:demo');
@@ -29,4 +41,32 @@ public function testHookFlags()
2941
$command = new SwooleFlagsCommand('test:demo2');
3042
$this->assertSame(SWOOLE_HOOK_ALL | SWOOLE_HOOK_CURL, $command->getHookFlags());
3143
}
44+
45+
/**
46+
* @group NonCoroutine
47+
*/
48+
public function testExitCodeWhenThrowException()
49+
{
50+
/** @var FooExceptionCommand $command */
51+
$command = new ClassInvoker(new FooExceptionCommand());
52+
$input = Mockery::mock(InputInterface::class);
53+
$input->shouldReceive('getOption')->andReturnFalse();
54+
$exitCode = $command->execute($input, Mockery::mock(OutputInterface::class));
55+
$this->assertSame(99, $exitCode);
56+
57+
/** @var FooExitCommand $command */
58+
$command = new ClassInvoker(new FooExitCommand());
59+
$exitCode = $command->execute($input, Mockery::mock(OutputInterface::class));
60+
$this->assertSame(11, $exitCode);
61+
62+
/** @var FooCommand $command */
63+
$command = new ClassInvoker(new FooCommand());
64+
$exitCode = $command->execute($input, Mockery::mock(OutputInterface::class));
65+
$this->assertSame(0, $exitCode);
66+
}
67+
68+
public function testExitCodeWhenThrowExceptionInCoroutine()
69+
{
70+
$this->testExitCodeWhenThrowException();
71+
}
3272
}

0 commit comments

Comments
 (0)