diff --git a/system/Commands/Utilities/Publish.php b/system/Commands/Utilities/Publish.php index 0fc6ef44efc8..2a7fc52e239e 100644 --- a/system/Commands/Utilities/Publish.php +++ b/system/Commands/Utilities/Publish.php @@ -13,8 +13,11 @@ namespace CodeIgniter\Commands\Utilities; -use CodeIgniter\CLI\BaseCommand; +use CodeIgniter\CLI\AbstractCommand; +use CodeIgniter\CLI\Attributes\Command; use CodeIgniter\CLI\CLI; +use CodeIgniter\CLI\Input\Argument; +use CodeIgniter\CLI\Input\Option; use CodeIgniter\Publisher\Publisher; /** @@ -22,100 +25,81 @@ * across namespaces. Executes `publish()` from each instance, parsing * each result. */ -class Publish extends BaseCommand +#[Command( + name: 'publish', + description: 'Discovers and executes all predefined Publisher classes.', + group: 'CodeIgniter', +)] +class Publish extends AbstractCommand { - /** - * The group the command is lumped under - * when listing commands. - * - * @var string - */ - protected $group = 'CodeIgniter'; - - /** - * The Command's name - * - * @var string - */ - protected $name = 'publish'; - - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Discovers and executes all predefined Publisher classes.'; - - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'publish []'; - - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'directory' => '[Optional] The directory to scan within each namespace. Default: "Publishers".', - ]; - - /** - * the Command's Options - * - * @var array - */ - protected $options = [ - '--namespace' => 'The namespace from which to search for files to publish. By default, all namespaces are analysed.', - ]; - - /** - * Displays the help for the spark cli script itself. - */ - public function run(array $params) + protected function configure(): void { - $directory = $params[0] ?? 'Publishers'; - $namespace = $params['namespace'] ?? ''; + $this + ->addArgument(new Argument( + name: 'directory', + description: 'The directory to scan within each namespace.', + default: 'Publishers', + )) + ->addOption(new Option( + name: 'namespace', + description: 'The namespace from which to search for files to publish. By default, all namespaces are analysed.', + requiresValue: true, + default: '', + )); + } + + protected function execute(array $arguments, array $options): int + { + $directory = $arguments['directory']; + $namespace = $options['namespace']; + + $publishers = Publisher::discover($directory, $namespace); - if ([] === $publishers = Publisher::discover($directory, $namespace)) { - if ($namespace === '') { - CLI::write(lang('Publisher.publishMissing', [$directory])); - } else { - CLI::write(lang('Publisher.publishMissingNamespace', [$directory, $namespace])); - } + if ($publishers === []) { + CLI::write($namespace === '' + ? lang('Publisher.publishMissing', [$directory]) + : lang('Publisher.publishMissingNamespace', [$directory, $namespace])); return EXIT_ERROR; } - $exit = EXIT_SUCCESS; + $failed = array_reduce( + $publishers, + function (bool $carry, Publisher $publisher): bool { + // Kept out of the return expression so `||` cannot skip publishing after a failure. + $published = $this->publishOne($publisher); - foreach ($publishers as $publisher) { - if ($publisher->publish()) { - CLI::write(lang('Publisher.publishSuccess', [ - $publisher::class, - count($publisher->getPublished()), - $publisher->getDestination(), - ]), 'green'); + return $carry || ! $published; + }, + false, + ); - continue; - } + return (int) $failed; + } - CLI::error(lang('Publisher.publishFailure', [ + private function publishOne(Publisher $publisher): bool + { + if ($publisher->publish()) { + CLI::write(lang('Publisher.publishSuccess', [ $publisher::class, + count($publisher->getPublished()), $publisher->getDestination(), - ]), 'light_gray', 'red'); + ]), 'green'); + + return true; + } - foreach ($publisher->getErrors() as $file => $exception) { - CLI::write($file); - CLI::error($exception->getMessage()); - CLI::newLine(); - } + CLI::error(lang('Publisher.publishFailure', [ + $publisher::class, + $publisher->getDestination(), + ]), 'light_gray', 'red'); - $exit = EXIT_ERROR; + foreach ($publisher->getErrors() as $file => $exception) { + CLI::write($file); + CLI::error($exception->getMessage()); + CLI::newLine(); } - return $exit; + return false; } } diff --git a/tests/system/Commands/Utilities/PublishCommandTest.php b/tests/system/Commands/Utilities/PublishCommandTest.php index ad35865367ec..737b55f7ef0c 100644 --- a/tests/system/Commands/Utilities/PublishCommandTest.php +++ b/tests/system/Commands/Utilities/PublishCommandTest.php @@ -55,4 +55,24 @@ public function testFailure(): void WRITEPATH, ]), $this->getStreamFilterBuffer()); } + + public function testNoPublishersInDirectory(): void + { + command('publish NoSuchDirectory'); + + $this->assertStringContainsString( + lang('Publisher.publishMissing', ['NoSuchDirectory']), + $this->getStreamFilterBuffer(), + ); + } + + public function testNoPublishersInNamespace(): void + { + command('publish --namespace NoSuchNamespace'); + + $this->assertStringContainsString( + lang('Publisher.publishMissingNamespace', ['Publishers', 'NoSuchNamespace']), + $this->getStreamFilterBuffer(), + ); + } }