mirror of
https://github.com/opdavies/build-configs.git
synced 2025-02-02 13:57:33 +00:00
refactor: use Illuminate Pipelines
This commit is contained in:
parent
830c37c681
commit
d19fcbdede
|
@ -7,6 +7,7 @@
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"doctrine/annotations": "^2.0",
|
"doctrine/annotations": "^2.0",
|
||||||
"illuminate/collections": "*",
|
"illuminate/collections": "*",
|
||||||
|
"illuminate/pipeline": "^10.8",
|
||||||
"illuminate/support": "^10.8",
|
"illuminate/support": "^10.8",
|
||||||
"phpdocumentor/reflection-docblock": "^5.3",
|
"phpdocumentor/reflection-docblock": "^5.3",
|
||||||
"phpstan/phpdoc-parser": "^1.20",
|
"phpstan/phpdoc-parser": "^1.20",
|
||||||
|
|
50
composer.lock
generated
50
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e6d53e1562c0a12390e51255801e7799",
|
"content-hash": "b98fa3983e5852c95b6d69ad0c556e29",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "doctrine/annotations",
|
"name": "doctrine/annotations",
|
||||||
|
@ -488,6 +488,54 @@
|
||||||
},
|
},
|
||||||
"time": "2023-03-17T13:33:11+00:00"
|
"time": "2023-03-17T13:33:11+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "illuminate/pipeline",
|
||||||
|
"version": "v10.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/illuminate/pipeline.git",
|
||||||
|
"reference": "f2119ae9a26e420bf0ed9d5e7e7aa4548547e7b1"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/illuminate/pipeline/zipball/f2119ae9a26e420bf0ed9d5e7e7aa4548547e7b1",
|
||||||
|
"reference": "f2119ae9a26e420bf0ed9d5e7e7aa4548547e7b1",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"illuminate/contracts": "^10.0",
|
||||||
|
"illuminate/support": "^10.0",
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "10.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Illuminate\\Pipeline\\": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Otwell",
|
||||||
|
"email": "taylor@laravel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The Illuminate Pipeline package.",
|
||||||
|
"homepage": "https://laravel.com",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
|
"source": "https://github.com/laravel/framework"
|
||||||
|
},
|
||||||
|
"time": "2023-03-03T15:55:44+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "illuminate/support",
|
"name": "illuminate/support",
|
||||||
"version": "v10.8.0",
|
"version": "v10.8.0",
|
||||||
|
|
26
src/Action/CreateFinalConfigurationData.php
Normal file
26
src/Action/CreateFinalConfigurationData.php
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Action;
|
||||||
|
|
||||||
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
|
final class CreateFinalConfigurationData
|
||||||
|
{
|
||||||
|
public function handle(string $configFile, \Closure $next) {
|
||||||
|
$configurationData = array_merge(
|
||||||
|
Yaml::parseFile(filename: __DIR__ . '/../../resources/build.defaults.yaml'),
|
||||||
|
Yaml::parseFile(filename: $configFile),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($configurationData['docker-compose'])) {
|
||||||
|
$configurationData['dockerCompose'] = $configurationData['docker-compose'];
|
||||||
|
$configurationData['docker-compose'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$configurationData['managedText'] = 'Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs.';
|
||||||
|
|
||||||
|
return $next($configurationData);
|
||||||
|
}
|
||||||
|
}
|
134
src/Action/CreateListOfFilesToGenerate.php
Normal file
134
src/Action/CreateListOfFilesToGenerate.php
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Action;
|
||||||
|
|
||||||
|
use App\DataTransferObject\TemplateFile;
|
||||||
|
use App\Enum\Language;
|
||||||
|
use App\Enum\WebServer;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
|
final class CreateListOfFilesToGenerate
|
||||||
|
{
|
||||||
|
public function handle(array $configurationData, \Closure $next) {
|
||||||
|
/** @var Collection<int, TemplateFile> */
|
||||||
|
$filesToGenerate = collect([
|
||||||
|
new TemplateFile(data: 'common/.dockerignore', name: '.dockerignore'),
|
||||||
|
new TemplateFile(data: 'common/.hadolint.yaml', name: '.hadolint.yaml'),
|
||||||
|
new TemplateFile(data: 'env.example', name: '.env.example'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$extraDatabases = Arr::get($configurationData, 'database.extra_databases', []);
|
||||||
|
if (count($extraDatabases) > 0) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(
|
||||||
|
data: 'extra-databases.sql',
|
||||||
|
name: 'extra-databases.sql',
|
||||||
|
path: 'tools/docker/images/database/root/docker-entrypoint-initdb.d',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false !== Arr::get($configurationData, "justfile", true)) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'justfile', name: 'justfile');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($configurationData['dockerCompose']) && $configurationData['dockerCompose'] !== null) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'docker-compose.yaml', name: 'docker-compose.yaml');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::isPhp(Arr::get($configurationData, 'language'))) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'php/Dockerfile', name: 'Dockerfile');
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'php/phpcs.xml', name: 'phpcs.xml.dist');
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'php/phpunit.xml', name: 'phpunit.xml.dist');
|
||||||
|
$filesToGenerate[] = new TemplateFile(
|
||||||
|
data: 'php/docker-entrypoint-php',
|
||||||
|
name: 'docker-entrypoint-php',
|
||||||
|
path: 'tools/docker/images/php/root/usr/local/bin',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Arr::has(array: $configurationData, keys: 'php.phpstan')) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'php/phpstan.neon', name: 'phpstan.neon.dist');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::isNode(Arr::get($configurationData, 'language'))) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'node/.yarnrc', name: '.yarnrc');
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'node/Dockerfile', name: 'Dockerfile');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::isCaddy(Arr::get($configurationData, 'web.type'))) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(
|
||||||
|
data: 'web/caddy/Caddyfile',
|
||||||
|
name: 'Caddyfile',
|
||||||
|
path: 'tools/docker/images/web/root/etc/caddy',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static::isNginx(Arr::get($configurationData, 'web.type'))) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(
|
||||||
|
data: 'web/nginx/default.conf',
|
||||||
|
name: 'default.conf',
|
||||||
|
path: 'tools/docker/images/web/root/etc/nginx/conf.d',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('drupal-project' === Arr::get($configurationData, 'type')) {
|
||||||
|
// Add a Drupal version of phpunit.xml.dist.
|
||||||
|
$filesToGenerate[] = new TemplateFile(data: 'drupal-project/phpunit.xml.dist', name: 'phpunit.xml.dist');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Arr::get($configurationData, 'experimental.createGitHubActionsConfiguration', false) === true) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(
|
||||||
|
data: 'ci/github-actions/ci.yml',
|
||||||
|
name: 'ci.yml',
|
||||||
|
path: '.github/workflows',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Arr::get($configurationData, 'experimental.runGitHooksBeforePush', false) === true) {
|
||||||
|
$filesToGenerate[] = new TemplateFile(
|
||||||
|
data: 'git-hooks/pre-push',
|
||||||
|
name: 'pre-push',
|
||||||
|
path: '.githooks',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next([$configurationData, $filesToGenerate]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
58
src/Action/GenerateConfigurationFiles.php
Normal file
58
src/Action/GenerateConfigurationFiles.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Action;
|
||||||
|
|
||||||
|
use App\DataTransferObject\TemplateFile;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
|
use Twig\Environment;
|
||||||
|
|
||||||
|
final class GenerateConfigurationFiles
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private Filesystem $filesystem,
|
||||||
|
private Environment $twig,
|
||||||
|
private string $outputDir,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(array $filesToGenerateAndConfigurationData, \Closure $next)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Collection<int,TemplateFile> $filesToGenerate
|
||||||
|
* @var array<string,mixed> $configurationData
|
||||||
|
*/
|
||||||
|
[$configurationData, $filesToGenerate] = $filesToGenerateAndConfigurationData;
|
||||||
|
|
||||||
|
$filesToGenerate->each(function(TemplateFile $templateFile) use ($configurationData): void {
|
||||||
|
if ($templateFile->path !== null) {
|
||||||
|
if (!$this->filesystem->exists($templateFile->path)) {
|
||||||
|
$this->filesystem->mkdir("{$this->outputDir}/{$templateFile->path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceFile = "{$templateFile->data}.twig";
|
||||||
|
|
||||||
|
$outputFile = collect([
|
||||||
|
$this->outputDir,
|
||||||
|
$templateFile->path,
|
||||||
|
$templateFile->name,
|
||||||
|
])->filter()->implode('/');
|
||||||
|
|
||||||
|
$this->filesystem->dumpFile($outputFile, $this->twig->render($sourceFile, $configurationData));
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the Docker entrypoint file is generated, ensure it is executable.
|
||||||
|
if ($this->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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->filesystem->exists("{$outputDir}/.githooks/pre-push")) {
|
||||||
|
$this->filesystem->chmod("{$outputDir}/.githooks/pre-push", 0755);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next([$configurationData, $filesToGenerate]);
|
||||||
|
}
|
||||||
|
}
|
40
src/Action/ValidateBuildConfigurationData.php
Normal file
40
src/Action/ValidateBuildConfigurationData.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Action;
|
||||||
|
|
||||||
|
use App\DataTransferObject\Config;
|
||||||
|
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||||
|
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Serializer;
|
||||||
|
use Symfony\Component\Validator\ConstraintViolationInterface;
|
||||||
|
use Symfony\Component\Validator\Validation;
|
||||||
|
|
||||||
|
final class ValidateBuildConfigurationData
|
||||||
|
{
|
||||||
|
public function handle(array $configurationData, \Closure $next) {
|
||||||
|
// Convert the input to a configuration data object.
|
||||||
|
$normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter());
|
||||||
|
$serializer = new Serializer([$normalizer], [new JsonEncoder()]);
|
||||||
|
$configurationDataObject = $serializer->deserialize(json_encode($configurationData), Config::class, 'json');
|
||||||
|
|
||||||
|
$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
|
||||||
|
$violations = $validator->validate($configurationDataObject);
|
||||||
|
|
||||||
|
if (0 < $violations->count()) {
|
||||||
|
$io->error('Configuration is invalid.');
|
||||||
|
|
||||||
|
$io->listing(
|
||||||
|
collect($violations)
|
||||||
|
->map(fn (ConstraintViolationInterface $v) => "{$v->getPropertyPath()} - {$v->getMessage()}")
|
||||||
|
->toArray()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($configurationData);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,12 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Command;
|
namespace App\Command;
|
||||||
|
|
||||||
use App\DataTransferObject\Config;
|
use App\Action\CreateFinalConfigurationData;
|
||||||
|
use App\Action\CreateListOfFilesToGenerate;
|
||||||
|
use App\Action\GenerateConfigurationFiles;
|
||||||
|
use App\Action\ValidateBuildConfigurationData;
|
||||||
use App\DataTransferObject\TemplateFile;
|
use App\DataTransferObject\TemplateFile;
|
||||||
use App\Enum\Language;
|
use Illuminate\Pipeline\Pipeline;
|
||||||
use App\Enum\WebServer;
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Symfony\Component\Console\Attribute\AsCommand;
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
@ -17,15 +18,7 @@ use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
use Symfony\Component\Filesystem\Filesystem;
|
use Symfony\Component\Filesystem\Filesystem;
|
||||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
|
||||||
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
|
|
||||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
|
||||||
use Symfony\Component\Serializer\Serializer;
|
|
||||||
use Symfony\Component\Validator\ConstraintViolationInterface;
|
|
||||||
use Symfony\Component\Validator\Validation;
|
|
||||||
use Symfony\Component\Yaml\Yaml;
|
|
||||||
use Twig\Environment;
|
use Twig\Environment;
|
||||||
use Twig\Loader\FilesystemLoader;
|
|
||||||
|
|
||||||
#[AsCommand(
|
#[AsCommand(
|
||||||
name: 'app:generate',
|
name: 'app:generate',
|
||||||
|
@ -33,6 +26,13 @@ use Twig\Loader\FilesystemLoader;
|
||||||
)]
|
)]
|
||||||
class GenerateCommand extends Command
|
class GenerateCommand extends Command
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private Filesystem $filesystem,
|
||||||
|
private Environment $twig,
|
||||||
|
) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
protected function configure(): void
|
protected function configure(): void
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
|
@ -60,222 +60,47 @@ class GenerateCommand extends Command
|
||||||
$configFile = $input->getOption(name: 'config-file');
|
$configFile = $input->getOption(name: 'config-file');
|
||||||
$outputDir = $input->getOption(name: 'output-dir');
|
$outputDir = $input->getOption(name: 'output-dir');
|
||||||
|
|
||||||
$configurationData = array_merge(
|
$pipes = [
|
||||||
Yaml::parseFile(filename: __DIR__ . '/../../resources/build.defaults.yaml'),
|
new CreateFinalConfigurationData(),
|
||||||
Yaml::parseFile(filename: $configFile),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Convert the input to a configuration data object.
|
new ValidateBuildConfigurationData(),
|
||||||
$normalizer = new ObjectNormalizer(null, new CamelCaseToSnakeCaseNameConverter());
|
|
||||||
$serializer = new Serializer([$normalizer], [new JsonEncoder()]);
|
|
||||||
$configurationDataObject = $serializer->deserialize(json_encode($configurationData), Config::class, 'json');
|
|
||||||
|
|
||||||
$validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
|
new CreateListOfFilesToGenerate(),
|
||||||
$violations = $validator->validate($configurationDataObject);
|
|
||||||
|
|
||||||
if (0 < $violations->count()) {
|
new GenerateConfigurationFiles(
|
||||||
$io->error('Configuration is invalid.');
|
$this->filesystem,
|
||||||
|
$this->twig,
|
||||||
|
$outputDir,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
$io->listing(
|
/**
|
||||||
collect($violations)
|
* @var Collection<int,TemplateFile> $generatedFiles
|
||||||
->map(fn (ConstraintViolationInterface $v) => "{$v->getPropertyPath()} - {$v->getMessage()}")
|
* @var array<string,mixed> $configurationData
|
||||||
->toArray()
|
*/
|
||||||
);
|
[$configurationData, $generatedFiles] = (new Pipeline())
|
||||||
|
->send($configFile)
|
||||||
return Command::FAILURE;
|
->through($pipes)
|
||||||
}
|
->thenReturn();
|
||||||
|
|
||||||
if (isset($configurationData['docker-compose'])) {
|
|
||||||
$configurationData['dockerCompose'] = $configurationData['docker-compose'];
|
|
||||||
$configurationData['docker-compose'] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$configurationData['managedText'] = 'Do not edit this file. It is automatically generated by https://www.oliverdavies.uk/build-configs.';
|
|
||||||
|
|
||||||
$filesToGenerate = $this->getFiles(configurationData: $configurationData);
|
|
||||||
|
|
||||||
$io->info("Building configuration for {$configurationData['name']}.");
|
$io->info("Building configuration for {$configurationData['name']}.");
|
||||||
|
|
||||||
$io->write('Generated files:');
|
$io->write('Generated files:');
|
||||||
$io->listing($this->getListOfFiles(filesToGenerate: $filesToGenerate)->toArray());
|
$io->listing(static::getListOfFiles(filesToGenerate: $generatedFiles)->toArray());
|
||||||
|
|
||||||
$this->generateFiles(
|
|
||||||
configurationData: $configurationData,
|
|
||||||
filesToGenerate: $filesToGenerate,
|
|
||||||
outputDir: $outputDir,
|
|
||||||
);
|
|
||||||
//
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static function buildFilePath(TemplateFile $templateFile): string
|
||||||
* @param array<string, string> $configurationData
|
|
||||||
* @param Collection<int, TemplateFile> $filesToGenerate
|
|
||||||
*/
|
|
||||||
function generateFiles(
|
|
||||||
Collection $filesToGenerate,
|
|
||||||
string $outputDir,
|
|
||||||
array $configurationData,
|
|
||||||
): void
|
|
||||||
{
|
{
|
||||||
$filesystem = new Filesystem();
|
return collect([$templateFile->path, $templateFile->name])->filter()->implode('/');
|
||||||
$twig = new Environment(new FilesystemLoader([__DIR__ . '/../../templates']));
|
|
||||||
|
|
||||||
$filesToGenerate->each(function(TemplateFile $templateFile) use ($configurationData, $filesystem, $outputDir, $twig): void {
|
|
||||||
if ($templateFile->path !== null) {
|
|
||||||
if (!$filesystem->exists($templateFile->path)) {
|
|
||||||
$filesystem->mkdir("{$outputDir}/{$templateFile->path}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sourceFile = "{$templateFile->data}.twig";
|
private static function getListOfFiles(Collection $filesToGenerate): Collection
|
||||||
$outputFile = collect([
|
|
||||||
$outputDir,
|
|
||||||
$templateFile->path,
|
|
||||||
$templateFile->name,
|
|
||||||
])->filter()->implode('/');
|
|
||||||
|
|
||||||
$filesystem->dumpFile($outputFile, $twig->render($sourceFile, $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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($filesystem->exists("{$outputDir}/.githooks/pre-push")) {
|
|
||||||
$filesystem->chmod("{$outputDir}/.githooks/pre-push", 0755);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFiles(array $configurationData): Collection
|
|
||||||
{
|
|
||||||
/** @var Collection<int, TemplateFile> */
|
|
||||||
$filesToGenerate = collect([
|
|
||||||
new TemplateFile(data: 'common/.dockerignore', name: '.dockerignore'),
|
|
||||||
new TemplateFile(data: 'common/.hadolint.yaml', name: '.hadolint.yaml'),
|
|
||||||
new TemplateFile(data: 'env.example', name: '.env.example'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$extraDatabases = Arr::get($configurationData, 'database.extra_databases', []);
|
|
||||||
if (count($extraDatabases) > 0) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(
|
|
||||||
data: 'extra-databases.sql',
|
|
||||||
name: 'extra-databases.sql',
|
|
||||||
path: 'tools/docker/images/database/root/docker-entrypoint-initdb.d',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (false !== Arr::get($configurationData, "justfile", true)) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'justfile', name: 'justfile');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($configurationData['dockerCompose']) && $configurationData['dockerCompose'] !== null) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'docker-compose.yaml', name: 'docker-compose.yaml');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::isPhp(Arr::get($configurationData, 'language'))) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'php/Dockerfile', name: 'Dockerfile');
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'php/phpcs.xml', name: 'phpcs.xml.dist');
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'php/phpunit.xml', name: 'phpunit.xml.dist');
|
|
||||||
$filesToGenerate[] = new TemplateFile(
|
|
||||||
data: 'php/docker-entrypoint-php',
|
|
||||||
name: 'docker-entrypoint-php',
|
|
||||||
path: 'tools/docker/images/php/root/usr/local/bin',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (Arr::has(array: $configurationData, keys: 'php.phpstan')) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'php/phpstan.neon', name: 'phpstan.neon.dist');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::isNode(Arr::get($configurationData, 'language'))) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'node/.yarnrc', name: '.yarnrc');
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'node/Dockerfile', name: 'Dockerfile');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::isCaddy(Arr::get($configurationData, 'web.type'))) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(
|
|
||||||
data: 'web/caddy/Caddyfile',
|
|
||||||
name: 'Caddyfile',
|
|
||||||
path: 'tools/docker/images/web/root/etc/caddy',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static::isNginx(Arr::get($configurationData, 'web.type'))) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(
|
|
||||||
data: 'web/nginx/default.conf',
|
|
||||||
name: 'default.conf',
|
|
||||||
path: 'tools/docker/images/web/root/etc/nginx/conf.d',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('drupal-project' === Arr::get($configurationData, 'type')) {
|
|
||||||
// Add a Drupal version of phpunit.xml.dist.
|
|
||||||
$filesToGenerate[] = new TemplateFile(data: 'drupal-project/phpunit.xml.dist', name: 'phpunit.xml.dist');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Arr::get($configurationData, 'experimental.createGitHubActionsConfiguration', false) === true) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(
|
|
||||||
data: 'ci/github-actions/ci.yml',
|
|
||||||
name: 'ci.yml',
|
|
||||||
path: '.github/workflows',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Arr::get($configurationData, 'experimental.runGitHooksBeforePush', false) === true) {
|
|
||||||
$filesToGenerate[] = new TemplateFile(
|
|
||||||
data: 'git-hooks/pre-push',
|
|
||||||
name: 'pre-push',
|
|
||||||
path: '.githooks',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $filesToGenerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getListOfFiles(Collection $filesToGenerate): Collection
|
|
||||||
{
|
{
|
||||||
return $filesToGenerate
|
return $filesToGenerate
|
||||||
->map(fn (TemplateFile $templateFile): string =>
|
->map(fn (TemplateFile $templateFile): string => static::buildFilePath($templateFile))
|
||||||
collect([$templateFile->path, $templateFile->name])->filter()->implode('/'))
|
|
||||||
->unique()
|
->unique()
|
||||||
->sort();
|
->sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue