mirror of
https://github.com/opdavies/build-configs.git
synced 2025-03-13 05:26:56 +00:00
refactor: use mnapoli/silly
This commit is contained in:
parent
5c4ddd52a4
commit
cf25359c7b
|
@ -1,25 +1,187 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use OliverDaviesLtd\BuildConfigs\Console\Command\BuildConfigurationCommand;
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use OliverDaviesLtd\BuildConfigs\Enum\Language;
|
||||
use OliverDaviesLtd\BuildConfigs\Enum\WebServer;
|
||||
use OliverDaviesLtd\BuildConfigs\Validator\ConfigurationValidator;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Silly\Application;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
$app = new Application();
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
$twig = new Environment(new FilesystemLoader([__DIR__.'/../templates']));
|
||||
$configurationValidator = new ConfigurationValidator();
|
||||
$app->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<string, string> $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;
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
117
composer.lock
generated
117
composer.lock
generated
|
@ -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",
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OliverDaviesLtd\BuildConfigs\Console\Command;
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use OliverDaviesLtd\BuildConfigs\Enum\Language;
|
||||
use OliverDaviesLtd\BuildConfigs\Enum\WebServer;
|
||||
use OliverDaviesLtd\BuildConfigs\Validator\ConfigurationValidator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Twig\Environment;
|
||||
|
||||
#[AsCommand(
|
||||
description: 'Build configuration files',
|
||||
name: 'build-configs'
|
||||
)]
|
||||
final class BuildConfigurationCommand extends Command
|
||||
{
|
||||
/** @phpstan-ignore-next-line */
|
||||
private Collection $filesToGenerate;
|
||||
|
||||
private string $outputDir;
|
||||
|
||||
public function __construct(
|
||||
private Environment $twig,
|
||||
private Filesystem $filesystem,
|
||||
private ConfigurationValidator $configurationValidator,
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->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<string, string> $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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue