Skip to content

Commit

Permalink
[9.x] Return non-zero exit code for uncaught exceptions (laravel#46541)
Browse files Browse the repository at this point in the history
* wip

* Update MakesArtisanScript.php

* artisanScript function

* Update MakesArtisanScript.php

* styleci

* change to PhpExecutableFinder

* move `exit(1)` call up to only console applications

* styleci

* wip

Signed-off-by: Mior Muhammad Zaki <[email protected]>

* imports

* formatting

---------

Signed-off-by: Mior Muhammad Zaki <[email protected]>
Co-authored-by: Mior Muhammad Zaki <[email protected]>
Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
3 people authored Apr 6, 2023
1 parent 4307b85 commit 6114330
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/Illuminate/Foundation/Bootstrap/HandleExceptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,15 @@ public function handleException(Throwable $e)
try {
$this->getExceptionHandler()->report($e);
} catch (Exception $e) {
//
$exceptionHandlerFailed = true;
}

if (static::$app->runningInConsole()) {
$this->renderForConsole($e);

if ($exceptionHandlerFailed ?? false) {
exit(1);
}
} else {
$this->renderHttpResponse($e);
}
Expand Down
44 changes: 44 additions & 0 deletions tests/Integration/Foundation/ExceptionHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,21 @@
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Route;
use Orchestra\Testbench\TestCase;
use Symfony\Component\Process\PhpProcess;

class ExceptionHandlerTest extends TestCase
{
/**
* Resolve application HTTP exception handler.
*
* @param \Illuminate\Foundation\Application $app
* @return void
*/
protected function resolveApplicationExceptionHandler($app)
{
$app->singleton('Illuminate\Contracts\Debug\ExceptionHandler', 'Illuminate\Foundation\Exceptions\Handler');
}

public function testItRendersAuthorizationExceptions()
{
Route::get('test-route', fn () => Response::deny('expected message', 321)->authorize());
Expand Down Expand Up @@ -107,4 +119,36 @@ public function testItHasFallbackErrorMessageForUnknownStatusCodes()
'message' => 'Whoops, looks like something went wrong.',
]);
}

/**
* @dataProvider exitCodesProvider
*/
public function testItReturnsNonZeroExitCodesForUncaughtExceptions($providers, $successful)
{
$basePath = static::applicationBasePath();
$providers = json_encode($providers, true);

$process = new PhpProcess(<<<EOF
<?php
require 'vendor/autoload.php';
\$laravel = Orchestra\Testbench\Foundation\Application::create(basePath: '$basePath', options: ['extra' => ['providers' => $providers]]);
\$laravel->singleton('Illuminate\Contracts\Debug\ExceptionHandler', 'Illuminate\Foundation\Exceptions\Handler');
\$kernel = \$laravel[Illuminate\Contracts\Console\Kernel::class];
return \$kernel->call('throw-exception-command');
EOF, __DIR__.'/../../../', ['APP_RUNNING_IN_CONSOLE' => true]);

$process->run();

$this->assertSame($successful, $process->isSuccessful());
}

public static function exitCodesProvider()
{
yield 'Throw exception' => [[Fixtures\Providers\ThrowUncaughtExceptionServiceProvider::class], false];
yield 'Do not throw exception' => [[Fixtures\Providers\ThrowExceptionServiceProvider::class], true];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Illuminate\Tests\Integration\Foundation\Fixtures\Console;

use Exception;
use Illuminate\Console\Command;

class ThrowExceptionCommand extends Command
{
protected $signature = 'throw-exception-command';

public function handle()
{
throw new Exception('Thrown inside ThrowExceptionCommand');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Illuminate\Tests\Integration\Foundation\Fixtures\Logs;

use Exception;
use Monolog\Handler\AbstractProcessingHandler;

class ThrowExceptionLogHandler extends AbstractProcessingHandler
{
protected function write(array $record): void
{
throw new Exception('Thrown inside ThrowExceptionLogHandler');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Illuminate\Tests\Integration\Foundation\Fixtures\Providers;

use Illuminate\Console\Application;
use Illuminate\Support\ServiceProvider;
use Illuminate\Tests\Integration\Foundation\Fixtures\Console\ThrowExceptionCommand;

class ThrowExceptionServiceProvider extends ServiceProvider
{
public function boot()
{
Application::starting(function ($artisan) {
$artisan->add(new ThrowExceptionCommand);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Illuminate\Tests\Integration\Foundation\Fixtures\Providers;

use Illuminate\Console\Application;
use Illuminate\Support\ServiceProvider;
use Illuminate\Tests\Integration\Foundation\Fixtures\Console\ThrowExceptionCommand;
use Illuminate\Tests\Integration\Foundation\Fixtures\Logs\ThrowExceptionLogHandler;

class ThrowUncaughtExceptionServiceProvider extends ServiceProvider
{
public function register()
{
$config = $this->app['config'];

$config->set('logging.default', 'throw_exception');

$config->set('logging.channels.throw_exception', [
'driver' => 'monolog',
'handler' => ThrowExceptionLogHandler::class,
]);
}

public function boot()
{
Application::starting(function ($artisan) {
$artisan->add(new ThrowExceptionCommand);
});
}
}

0 comments on commit 6114330

Please sign in to comment.