diff --git a/src/Tempest/Console/src/Actions/ExecuteConsoleCommand.php b/src/Tempest/Console/src/Actions/ExecuteConsoleCommand.php
index a799c3105..c2c6466c4 100644
--- a/src/Tempest/Console/src/Actions/ExecuteConsoleCommand.php
+++ b/src/Tempest/Console/src/Actions/ExecuteConsoleCommand.php
@@ -21,7 +21,7 @@ public function __construct(
) {
}
- public function __invoke(string $commandName): ExitCode
+ public function __invoke(string $commandName): ExitCode|int
{
$callable = $this->getCallable($this->resolveCommandMiddleware($commandName));
diff --git a/src/Tempest/Console/src/Console.php b/src/Tempest/Console/src/Console.php
index f5d6ffac1..11dc075d3 100644
--- a/src/Tempest/Console/src/Console.php
+++ b/src/Tempest/Console/src/Console.php
@@ -9,7 +9,7 @@
interface Console
{
- public function call(string $command): ExitCode;
+ public function call(string $command): ExitCode|int;
public function readln(): string;
diff --git a/src/Tempest/Console/src/ConsoleApplication.php b/src/Tempest/Console/src/ConsoleApplication.php
index be1e155af..315c4ce4a 100644
--- a/src/Tempest/Console/src/ConsoleApplication.php
+++ b/src/Tempest/Console/src/ConsoleApplication.php
@@ -57,7 +57,13 @@ public function run(): void
try {
$exitCode = ($this->container->get(ExecuteConsoleCommand::class))($this->argumentBag->getCommandName());
- $this->container->get(Kernel::class)->shutdown($exitCode->value);
+ $exitCode = is_int($exitCode) ? $exitCode : $exitCode->value;
+
+ if ($exitCode < 0 || $exitCode > 255) {
+ throw new InvalidExitCode($exitCode);
+ }
+
+ $this->container->get(Kernel::class)->shutdown($exitCode);
} catch (Throwable $throwable) {
foreach ($this->appConfig->errorHandlers as $exceptionHandler) {
$exceptionHandler->handleException($throwable);
diff --git a/src/Tempest/Console/src/ConsoleMiddleware.php b/src/Tempest/Console/src/ConsoleMiddleware.php
index ebd140461..f955431bd 100644
--- a/src/Tempest/Console/src/ConsoleMiddleware.php
+++ b/src/Tempest/Console/src/ConsoleMiddleware.php
@@ -8,5 +8,5 @@
interface ConsoleMiddleware
{
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode;
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int;
}
diff --git a/src/Tempest/Console/src/ConsoleMiddlewareCallable.php b/src/Tempest/Console/src/ConsoleMiddlewareCallable.php
index caeea0611..91edbafee 100644
--- a/src/Tempest/Console/src/ConsoleMiddlewareCallable.php
+++ b/src/Tempest/Console/src/ConsoleMiddlewareCallable.php
@@ -14,7 +14,7 @@ public function __construct(
) {
}
- public function __invoke(Invocation $invocation): ExitCode
+ public function __invoke(Invocation $invocation): ExitCode|int
{
return ($this->closure)($invocation);
}
diff --git a/src/Tempest/Console/src/Exceptions/ConsoleErrorHandler.php b/src/Tempest/Console/src/Exceptions/ConsoleErrorHandler.php
index dab363c1b..d0e315685 100644
--- a/src/Tempest/Console/src/Exceptions/ConsoleErrorHandler.php
+++ b/src/Tempest/Console/src/Exceptions/ConsoleErrorHandler.php
@@ -5,9 +5,12 @@
namespace Tempest\Console\Exceptions;
use Tempest\Console\Console;
+use Tempest\Console\ExitCode;
+use Tempest\Console\HasExitCode;
use Tempest\Console\Input\ConsoleArgumentBag;
use Tempest\Container\Tag;
use Tempest\Core\ErrorHandler;
+use Tempest\Core\Kernel;
use Tempest\Highlight\Escape;
use Tempest\Highlight\Highlighter;
use Throwable;
@@ -15,6 +18,7 @@
final readonly class ConsoleErrorHandler implements ErrorHandler
{
public function __construct(
+ private Kernel $kernel,
#[Tag('console')]
private Highlighter $highlighter,
private Console $console,
@@ -53,6 +57,10 @@ public function handleException(Throwable $throwable): void
->writeln('-v show more')
->writeln();
}
+
+ $exitCode = $throwable instanceof HasExitCode ? $throwable->getExitCode() : ExitCode::ERROR;
+
+ $this->kernel->shutdown($exitCode->value);
}
public function handleError(int $errNo, string $errstr, string $errFile, int $errLine): void
diff --git a/src/Tempest/Console/src/ExitCode.php b/src/Tempest/Console/src/ExitCode.php
index 4fe2807ec..a08a391f3 100644
--- a/src/Tempest/Console/src/ExitCode.php
+++ b/src/Tempest/Console/src/ExitCode.php
@@ -4,10 +4,20 @@
namespace Tempest\Console;
+/**
+ * You're free to return any int between 0 and 255 from a console command as exit code.
+ * The meaning of these integer values will be determined by your application.
+ * Alternatively, Tempest provides a closed set of predefined exit codes via this enum.
+ * The exit codes listed here are used by Tempest and assigned a fixed meaning.
+ */
enum ExitCode: int
{
case SUCCESS = 0;
case ERROR = 1;
case INVALID = 2;
case CANCELLED = 25;
+ case CANNOT_EXECUTE = 126;
+ case COMMAND_NOT_FOUND = 127;
+ case INVALID_EXIT_CODE = 128;
+ case TERMINATED = 130;
}
diff --git a/src/Tempest/Console/src/GenericConsole.php b/src/Tempest/Console/src/GenericConsole.php
index f5f8e11de..504db2b07 100644
--- a/src/Tempest/Console/src/GenericConsole.php
+++ b/src/Tempest/Console/src/GenericConsole.php
@@ -43,7 +43,7 @@ public function __construct(
) {
}
- public function call(string $command): ExitCode
+ public function call(string $command): ExitCode|int
{
return ($this->executeConsoleCommand)($command);
}
diff --git a/src/Tempest/Console/src/HasExitCode.php b/src/Tempest/Console/src/HasExitCode.php
new file mode 100644
index 000000000..642739739
--- /dev/null
+++ b/src/Tempest/Console/src/HasExitCode.php
@@ -0,0 +1,10 @@
+appConfig->environment;
diff --git a/src/Tempest/Console/src/Middleware/ConsoleExceptionMiddleware.php b/src/Tempest/Console/src/Middleware/ConsoleExceptionMiddleware.php
index 4fb7abf30..95aaf76a1 100644
--- a/src/Tempest/Console/src/Middleware/ConsoleExceptionMiddleware.php
+++ b/src/Tempest/Console/src/Middleware/ConsoleExceptionMiddleware.php
@@ -18,7 +18,7 @@ public function __construct(
) {
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
try {
return $next($invocation);
diff --git a/src/Tempest/Console/src/Middleware/ForceMiddleware.php b/src/Tempest/Console/src/Middleware/ForceMiddleware.php
index 6efedc126..449200feb 100644
--- a/src/Tempest/Console/src/Middleware/ForceMiddleware.php
+++ b/src/Tempest/Console/src/Middleware/ForceMiddleware.php
@@ -17,7 +17,7 @@ public function __construct(private Console $console)
{
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
if ($invocation->argumentBag->get('-f') || $invocation->argumentBag->get('force')) {
if ($this->console instanceof GenericConsole) {
diff --git a/src/Tempest/Console/src/Middleware/HelpMiddleware.php b/src/Tempest/Console/src/Middleware/HelpMiddleware.php
index 0d53ca383..73a414a06 100644
--- a/src/Tempest/Console/src/Middleware/HelpMiddleware.php
+++ b/src/Tempest/Console/src/Middleware/HelpMiddleware.php
@@ -19,7 +19,7 @@ public function __construct(
) {
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
if ($invocation->argumentBag->get('-h') || $invocation->argumentBag->get('help')) {
$this->renderHelp($invocation->consoleCommand);
diff --git a/src/Tempest/Console/src/Middleware/InvalidCommandMiddleware.php b/src/Tempest/Console/src/Middleware/InvalidCommandMiddleware.php
index d70bb3276..806ed5c97 100644
--- a/src/Tempest/Console/src/Middleware/InvalidCommandMiddleware.php
+++ b/src/Tempest/Console/src/Middleware/InvalidCommandMiddleware.php
@@ -22,7 +22,7 @@ public function __construct(
) {
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
try {
return $next($invocation);
@@ -31,7 +31,7 @@ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next
}
}
- private function retry(Invocation $invocation, InvalidCommandException $exception): ExitCode
+ private function retry(Invocation $invocation, InvalidCommandException $exception): ExitCode|int
{
$this->console->writeln("Provide missing input:");
diff --git a/src/Tempest/Console/src/Middleware/OverviewMiddleware.php b/src/Tempest/Console/src/Middleware/OverviewMiddleware.php
index 3381e4d81..89a7cdeed 100644
--- a/src/Tempest/Console/src/Middleware/OverviewMiddleware.php
+++ b/src/Tempest/Console/src/Middleware/OverviewMiddleware.php
@@ -22,7 +22,7 @@ public function __construct(
) {
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
if (! $invocation->argumentBag->getCommandName()) {
$this->renderOverview(showHidden: $invocation->argumentBag->has('--all', '-a'));
diff --git a/src/Tempest/Console/src/Middleware/ResolveOrRescueMiddleware.php b/src/Tempest/Console/src/Middleware/ResolveOrRescueMiddleware.php
index 0d363989f..01a9f7d24 100644
--- a/src/Tempest/Console/src/Middleware/ResolveOrRescueMiddleware.php
+++ b/src/Tempest/Console/src/Middleware/ResolveOrRescueMiddleware.php
@@ -21,7 +21,7 @@ public function __construct(
) {
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
$consoleCommand = $this->consoleConfig->commands[$invocation->argumentBag->getCommandName()] ?? null;
@@ -35,7 +35,7 @@ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next
));
}
- private function rescue(string $commandName): ExitCode
+ private function rescue(string $commandName): ExitCode|int
{
$this->console->writeln("Command {$commandName} not found");
@@ -86,7 +86,7 @@ private function getSimilarCommands(string $name): array
return $similarCommands;
}
- private function runIntendedCommand(string $commandName): ExitCode
+ private function runIntendedCommand(string $commandName): ExitCode|int
{
return ($this->executeConsoleCommand)($commandName);
}
diff --git a/tests/Integration/Console/Fixtures/SpecificMiddleware.php b/tests/Integration/Console/Fixtures/SpecificMiddleware.php
index 73441766b..22cf51c10 100644
--- a/tests/Integration/Console/Fixtures/SpecificMiddleware.php
+++ b/tests/Integration/Console/Fixtures/SpecificMiddleware.php
@@ -16,7 +16,7 @@ public function __construct(private Console $console)
{
}
- public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode
+ public function __invoke(Invocation $invocation, ConsoleMiddlewareCallable $next): ExitCode|int
{
$this->console->writeln('from middleware');