From cf25359c7b063242add51a1620efffc7db4f5211 Mon Sep 17 00:00:00 2001 From: Oliver Davies Date: Mon, 13 Mar 2023 01:19:12 +0000 Subject: [PATCH] refactor: use mnapoli/silly --- bin/build-configs | 186 +++++++++++++++-- composer.json | 1 + composer.lock | 117 ++++++++++- .../Command/BuildConfigurationCommand.php | 191 ------------------ 4 files changed, 291 insertions(+), 204 deletions(-) delete mode 100644 src/Console/Command/BuildConfigurationCommand.php diff --git a/bin/build-configs b/bin/build-configs index 4c3268f..9170c1b 100755 --- a/bin/build-configs +++ b/bin/build-configs @@ -1,25 +1,187 @@ #!/usr/bin/env php command( + 'run [-c|--config-file=] [-o|--output-dir=]', + function ( + SymfonyStyle $io, + string $configFile = 'build.yaml', + string $outputDir = '.', + ): void { + $configurationData = array_merge( + Yaml::parseFile(__DIR__ . '/../resources/build.defaults.yaml'), + Yaml::parseFile($configFile), + ); -$application = new Application(); -$command = new BuildConfigurationCommand($twig, $filesystem, $configurationValidator); + $violations = (new ConfigurationValidator())->validate($configurationData); -$application->addCommands([ - new BuildConfigurationCommand($twig, $filesystem, $configurationValidator), + if (0 < $violations->count()) { + $io->error('Configuration is invalid.'); + + $io->listing( + collect($violations) + ->map(fn (ConstraintViolationInterface $v) => "{$v->getInvalidValue()} - {$v->getMessage()}") + ->toArray() + ); + + return; + } + + if (isset($configurationData['docker-compose'])) { + $configurationData['dockerCompose'] = $configurationData['docker-compose']; + $configurationData['docker-compose'] = null; + } + + $io->info("Building configuration for {$configurationData['name']}."); + + $filesToGenerate = collect([ + ['env.example', '.env.example'], + ]); + + if (false !== Arr::get($configurationData, "justfile", true)) { + $filesToGenerate->push(['justfile', 'justfile']); + } + + if (isset($configurationData['dockerCompose']) && $configurationData['dockerCompose'] !== null) { + $filesToGenerate->push(['docker-compose.yaml', 'docker-compose.yaml']); + } + + if (isPhp(Arr::get($configurationData, 'language'))) { + $filesToGenerate->push(['php/Dockerfile', 'Dockerfile']); + $filesToGenerate->push(['php/phpcs.xml', 'phpcs.xml.dist']); + $filesToGenerate->push(['php/phpstan.neon', 'phpstan.neon.dist']); + $filesToGenerate->push(['php/phpunit.xml', 'phpunit.xml.dist']); + $filesToGenerate->push(['php/docker-entrypoint-php', 'tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php']); + } + + if (isNode(Arr::get($configurationData, 'language'))) { + $filesToGenerate->push(['node/.yarnrc', '.yarnrc']); + $filesToGenerate->push(['node/Dockerfile', 'Dockerfile']); + } + + if (isCaddy(Arr::get($configurationData, 'web.type'))) { + $filesToGenerate->push(['web/caddy/Caddyfile', 'tools/docker/images/web/root/etc/caddy/Caddyfile']); + } + + if (isNginx(Arr::get($configurationData, 'web.type'))) { + $filesToGenerate->push(['web/nginx/default.conf', 'tools/docker/images/web/root/etc/nginx/conf.d/default.conf']); + } + + if ('drupal-project' === Arr::get($configurationData, 'type')) { + // Ensure a "docroot" value is set. + if (null === Arr::get($configurationData, 'drupal.docroot')) { + Arr::set($configurationData, 'drupal.docroot', 'web'); + } + + // Add a Drupal version of phpunit.xml.dist. + $filesToGenerate->push(['drupal-project/phpunit.xml.dist', 'phpunit.xml.dist']); + } + + $configurationData['managedText'] = 'Do not edit this file. It is automatically generated by \'build-configs\'.'; + + generateFiles( + configurationData: $configurationData, + filesToGenerate: $filesToGenerate, + outputDir: $outputDir, + ); + } +)->descriptions('Generate project-specific configuration files.', [ + '--config-file' => 'The path to the project\'s build.yaml file', + '--output-dir' => 'The directory to create files in', ]); -$application->setDefaultCommand('build-configs', true); -$application->run(); +$app->setDefaultCommand('run'); + +$app->run(); + +/** + * @param array $configurationData + */ +function generateFiles( + Collection $filesToGenerate, + string $outputDir, + array $configurationData, +): void +{ + $filesystem = new Filesystem(); + $twig = new Environment(new FilesystemLoader([__DIR__ . '/../templates'])); + + if (isPhp(Arr::get($configurationData, 'language'))) { + $filesystem->mkdir("{$outputDir}/tools/docker/images/php/root/usr/local/bin"); + } + + if (isCaddy(Arr::get($configurationData, 'web.type'))) { + $filesystem->mkdir("{$outputDir}/tools/docker/images/web/root/etc/caddy"); + } elseif (isNginx(Arr::get($configurationData, 'web.type'))) { + $filesystem->mkdir("{$outputDir}/tools/docker/images/web/root/etc/nginx/conf.d"); + } + + $filesToGenerate->map(function(array $filenames) use ($outputDir): array { + $filenames[0] = "{$filenames[0]}.twig"; + $filenames[1] = "{$outputDir}/${filenames[1]}"; + + return $filenames; + })->each(function(array $filenames) use ($configurationData, $filesystem, $twig): void { + $filesystem->dumpFile($filenames[1], $twig->render($filenames[0], $configurationData)); + }); + + // If the Docker entrypoint file is generated, ensure it is executable. + if ($filesystem->exists("{$outputDir}/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php")) { + $filesystem->chmod("{$outputDir}/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php", 0755); + } +} + +function isCaddy(?string $webServer): bool +{ + if (is_null($webServer)) { + return false; + } + + return strtoupper($webServer) === WebServer::CADDY->name; +} + +function isNginx(?string $webServer): bool +{ + if (is_null($webServer)) { + return false; + } + + return strtoupper($webServer) === WebServer::NGINX->name; +} + +function isNode(?string $language): bool +{ + if (is_null($language)) { + return false; + } + + return strtoupper($language) === Language::NODE->name; +} + +function isPhp(?string $language): bool +{ + if (is_null($language)) { + return false; + } + + return strtoupper($language) === Language::PHP->name; +} diff --git a/composer.json b/composer.json index ecab7c8..6e8fe60 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "require": { "illuminate/support": "^9.50", + "mnapoli/silly": "^1.8", "symfony/console": "^6.2", "symfony/filesystem": "^6.2", "symfony/validator": "^6.2", diff --git a/composer.lock b/composer.lock index 479268e..a46d98c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ae32eb37ca9e97c13ba60c2f1523f8f3", + "content-hash": "f061fa0f45e2799ba4d741d3232d9b00", "packages": [ { "name": "amphp/amp", @@ -1580,6 +1580,66 @@ }, "time": "2022-09-08T13:45:54+00:00" }, + { + "name": "mnapoli/silly", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/mnapoli/silly.git", + "reference": "3ff92aab46f365eb341c581dcba074f812420827" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mnapoli/silly/zipball/3ff92aab46f365eb341c581dcba074f812420827", + "reference": "3ff92aab46f365eb341c581dcba074f812420827", + "shasum": "" + }, + "require": { + "php": ">=7.4", + "php-di/invoker": "~2.0", + "psr/container": "^1.0|^2.0", + "symfony/console": "~3.0|~4.0|~5.0|~6.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.12", + "mnapoli/phpunit-easymock": "~1.0", + "phpunit/phpunit": "^6.4|^7|^8|^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "Silly\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Silly CLI micro-framework based on Symfony Console", + "keywords": [ + "PSR-11", + "cli", + "console", + "framework", + "micro-framework", + "silly" + ], + "support": { + "issues": "https://github.com/mnapoli/silly/issues", + "source": "https://github.com/mnapoli/silly/tree/1.8.1" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/mnapoli/silly", + "type": "tidelift" + } + ], + "time": "2022-09-06T14:21:36+00:00" + }, { "name": "nesbot/carbon", "version": "2.66.0", @@ -1915,6 +1975,61 @@ }, "time": "2020-12-03T04:57:05+00:00" }, + { + "name": "php-di/invoker", + "version": "2.3.3", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/cd6d9f267d1a3474bdddf1be1da079f01b942786", + "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.3" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2021-12-13T09:22:56+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", diff --git a/src/Console/Command/BuildConfigurationCommand.php b/src/Console/Command/BuildConfigurationCommand.php deleted file mode 100644 index 20b0956..0000000 --- a/src/Console/Command/BuildConfigurationCommand.php +++ /dev/null @@ -1,191 +0,0 @@ -filesToGenerate = new Collection(); - } - - protected function configure(): void - { - $this - ->addOption('config', 'c', InputOption::VALUE_REQUIRED, 'The configuration file to use', 'build.yaml') - ->addOption('output-dir', 'o', InputOption::VALUE_REQUIRED, 'The directory to create files in', '.'); - } - - public function execute(InputInterface $input, OutputInterface $output): int - { - $configFile = $input->getOption('config'); - $this->outputDir = $input->getOption('output-dir'); - - $io = new SymfonyStyle($input, $output); - - $configurationData = array_merge( - Yaml::parseFile(__DIR__.'/../../../resources/build.defaults.yaml'), - Yaml::parseFile($configFile), - ); - - $violations = $this->configurationValidator->validate($configurationData); - - if (0 < $violations->count()) { - $io->error('Configuration is invalid.'); - - $io->listing( - collect($violations) - ->map(fn (ConstraintViolationInterface $v) => "{$v->getInvalidValue()} - {$v->getMessage()}") - ->toArray() - ); - - return Command::FAILURE; - } - - if (isset($configurationData['docker-compose'])) { - $configurationData['dockerCompose'] = $configurationData['docker-compose']; - $configurationData['docker-compose'] = null; - } - - $io->info("Building configuration for {$configurationData['name']}."); - - $this->filesToGenerate->push(['env.example', '.env.example']); - - if (false !== Arr::get($configurationData, "justfile", true)) { - $this->filesToGenerate->push(['justfile', 'justfile']); - } - - if (isset($configurationData['dockerCompose']) && $configurationData['dockerCompose'] !== null) { - $this->filesToGenerate->push(['docker-compose.yaml', 'docker-compose.yaml']); - } - - if (self::isPhp(Arr::get($configurationData, 'language'))) { - $this->filesToGenerate->push(['php/Dockerfile', 'Dockerfile']); - $this->filesToGenerate->push(['php/phpcs.xml', 'phpcs.xml.dist']); - $this->filesToGenerate->push(['php/phpstan.neon', 'phpstan.neon.dist']); - $this->filesToGenerate->push(['php/phpunit.xml', 'phpunit.xml.dist']); - - $this->filesystem->mkdir("{$this->outputDir}/tools/docker/images/php/root/usr/local/bin"); - $this->filesToGenerate->push(['php/docker-entrypoint-php', 'tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php']); - } - - if (self::isNode(Arr::get($configurationData, 'language'))) { - $this->filesToGenerate->push(['node/.yarnrc', '.yarnrc']); - $this->filesToGenerate->push(['node/Dockerfile', 'Dockerfile']); - } - - if (self::isCaddy(Arr::get($configurationData, 'web.type'))) { - $this->filesystem->mkdir("{$this->outputDir}/tools/docker/images/web/root/etc/caddy"); - $this->filesToGenerate->push(['web/caddy/Caddyfile', 'tools/docker/images/web/root/etc/caddy/Caddyfile']); - } - - if (self::isNginx(Arr::get($configurationData, 'web.type'))) { - $this->filesystem->mkdir("{$this->outputDir}/tools/docker/images/web/root/etc/nginx/conf.d"); - $this->filesToGenerate->push(['web/nginx/default.conf', 'tools/docker/images/web/root/etc/nginx/conf.d/default.conf']); - } - - if ('drupal-project' === Arr::get($configurationData, 'type')) { - // Ensure a "docroot" value is set. - if (null === Arr::get($configurationData, 'drupal.docroot')) { - Arr::set($configurationData, 'drupal.docroot', 'web'); - } - - // Add a Drupal version of phpunit.xml.dist. - $this->filesToGenerate->push(['drupal-project/phpunit.xml.dist', 'phpunit.xml.dist']); - } - - $configurationData['managedText'] = 'Do not edit this file. It is automatically generated by \'build-configs\'.'; - - $this->generateFiles($configurationData); - - return Command::SUCCESS; - } - - /** - * @param array $configurationData - */ - private function generateFiles(array $configurationData): void - { - $this->filesToGenerate->map(function(array $filenames): array { - $filenames[0] = "{$filenames[0]}.twig"; - $filenames[1] = "{$this->outputDir}/${filenames[1]}"; - - return $filenames; - })->each(function(array $filenames) use ($configurationData): void { - $this->filesystem->dumpFile($filenames[1], $this->twig->render($filenames[0], $configurationData)); - }); - - // If the Docker entrypoint file is generated, ensure it is executable. - if ($this->filesystem->exists("{$this->outputDir}/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php")) { - $this->filesystem->chmod("{$this->outputDir}/tools/docker/images/php/root/usr/local/bin/docker-entrypoint-php", 0755); - } - } - - private static function isCaddy(?string $webServer): bool - { - if (is_null($webServer)) { - return false; - } - - return strtoupper($webServer) === WebServer::CADDY->name; - } - - private static function isNginx(?string $webServer): bool - { - if (is_null($webServer)) { - return false; - } - - return strtoupper($webServer) === WebServer::NGINX->name; - } - - private static function isNode(?string $language): bool - { - if (is_null($language)) { - return false; - } - - return strtoupper($language) === Language::NODE->name; - } - - private static function isPhp(?string $language): bool - { - if (is_null($language)) { - return false; - } - - return strtoupper($language) === Language::PHP->name; - } -}