Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Implement concept for artifact migration #138

Merged
merged 15 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
use Cocur\Slugify;
use CPSIT\ProjectBuilder\Builder;
use CPSIT\ProjectBuilder\IO;
use CPSIT\ProjectBuilder\Template;
use CPSIT\ProjectBuilder\Twig;
use GuzzleHttp\Client as GuzzleClient;
use Nyholm\Psr7;
use Opis\JsonSchema;
use Psr\Http\Client;
use Psr\Http\Message;
use SebastianFeldmann\Cli;
Expand All @@ -43,6 +43,9 @@
DependencyInjection\Loader\Configurator\ContainerConfigurator $configurator,
DependencyInjection\ContainerBuilder $container,
): void {
$container->registerForAutoconfiguration(Builder\Artifact\Migration\Migration::class)
->addTag('artifact.migration')
;
$container->registerForAutoconfiguration(Builder\Writer\WriterInterface::class)
->addTag('builder.writer')
;
Expand All @@ -55,9 +58,6 @@
$container->registerForAutoconfiguration(IO\Validator\ValidatorInterface::class)
->addTag('io.validator')
;
$container->registerForAutoconfiguration(Template\Provider\ProviderInterface::class)
->addTag('template.provider')
;
$container->registerForAutoconfiguration(Twig\Filter\TwigFilterInterface::class)
->addTag('twig.filter')
;
Expand All @@ -84,6 +84,7 @@
// Add external services
$services->set(ExpressionLanguage\ExpressionLanguage::class);
$services->set(Filesystem\Filesystem::class);
$services->set(JsonSchema\Validator::class);
$services->set(Slugify\Slugify::class);
$services->set(Client\ClientInterface::class, GuzzleClient::class);
$services->set(Loader\LoaderInterface::class, Loader\FilesystemLoader::class);
Expand Down
10 changes: 5 additions & 5 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
CPSIT\ProjectBuilder\:
resource: '../src/*'
exclude:
- '../src/Builder/Artifact/*'
- '../src/Builder/Artifact/*.php'
- '../src/Builder/Config/*'
- '../src/Builder/Generator/Step/CleanUpStep.php'
- '../src/Builder/Generator/Step/DumpBuildArtifactStep.php'
Expand All @@ -21,6 +21,10 @@ services:
- '../src/Resource/Local/ProcessedFile.php'
- '../src/Template/TemplateSource.php'

CPSIT\ProjectBuilder\Builder\ArtifactReader:
arguments:
$migrations: !tagged_iterator artifact.migration

CPSIT\ProjectBuilder\Builder\Config\Config:
alias: 'app.config'

Expand All @@ -45,10 +49,6 @@ services:
CPSIT\ProjectBuilder\IO\Messenger:
alias: 'app.messenger'

CPSIT\ProjectBuilder\Template\Provider\ProviderFactory:
arguments:
$providers: !tagged_iterator template.provider

CPSIT\ProjectBuilder\Twig\Extension\ProjectBuilderExtension:
arguments:
$filters: !tagged_iterator twig.filter
Expand Down
18 changes: 18 additions & 0 deletions docs/development/architecture/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ Each validator implements [`ValidatorInterface`](https://github.com/CPS-IT/proje
Not all validators can be used for each interaction with the `InputReader`.
```

## JSON schema validation

While working with JSON files, it's often useful to validate them against a defined
JSON schema. For this, the [**`Json\SchemaValidator`**](https://github.com/CPS-IT/project-builder/blob/main/src/Json/SchemaValidator.php)
component can be used.

Example:

```php
/** @var \CPSIT\ProjectBuilder\Json\SchemaValidator $schemaValidator */

$data = json_decode($json);
$validationResult = $schemaValidator->validate($data, $schemaFile);

$isValid = $validationResult->isValid(); // Check if JSON is valid
$error = $validationResult->error(); // Get validation errors
```

## Naming

With the [**`Naming\NameVariantBuilder`**](https://github.com/CPS-IT/project-builder/blob/main/src/Naming/NameVariantBuilder.php)
Expand Down
5 changes: 5 additions & 0 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

use Rector\Config\RectorConfig;
use Rector\Core\ValueObject\PhpVersion;
use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector;
use Rector\Php74\Rector\LNumber\AddLiteralSeparatorToNumberRector;
use Rector\Php80\Rector\Class_\AnnotationToAttributeRector;
use Rector\Php81\Rector\FuncCall\NullToStrictStringFuncCallArgRector;
Expand Down Expand Up @@ -51,6 +52,10 @@
__DIR__.'/src/DependencyInjection/ContainerFactory.php',
__DIR__.'/src/ProjectBuilderPlugin.php',
],
JsonThrowOnErrorRector::class => [
__DIR__.'/src/Builder/ArtifactGenerator.php',
__DIR__.'/src/Builder/ArtifactReader.php',
],
NullToStrictStringFuncCallArgRector::class => [
__DIR__.'/src/Builder/Generator/Step/ProcessingFilesTrait.php',
],
Expand Down
2 changes: 1 addition & 1 deletion resources/build-artifact.schema.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://json-schema.org/draft-04/schema",
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"type": "object",
"title": "Build artifact for projects generated with the Project Builder",
"properties": {
Expand Down
31 changes: 26 additions & 5 deletions src/Builder/Artifact/Artifact.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,38 @@
*
* @internal
*
* @template T of array<string, mixed>
* @phpstan-type ArtifactType array{
* artifact: BuildArtifact,
* template: TemplateArtifact,
* generator: GeneratorArtifact,
* result: ResultArtifact
* }
*/
abstract class Artifact implements JsonSerializable
final class Artifact implements JsonSerializable
{
public function __construct(
public readonly BuildArtifact $artifact,
public readonly TemplateArtifact $template,
public readonly GeneratorArtifact $generator,
public readonly ResultArtifact $result,
) {
}

/**
* @return T
* @phpstan-return ArtifactType
*/
abstract public function dump(): array;
public function dump(): array
{
return [
'artifact' => $this->artifact,
'template' => $this->template,
'generator' => $this->generator,
'result' => $this->result,
];
}

/**
* @return T
* @phpstan-return ArtifactType
*/
public function jsonSerialize(): array
{
Expand Down
49 changes: 16 additions & 33 deletions src/Builder/Artifact/BuildArtifact.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,7 @@

namespace CPSIT\ProjectBuilder\Builder\Artifact;

use Composer\Package;
use CPSIT\ProjectBuilder\Builder;
use CPSIT\ProjectBuilder\Helper;
use Symfony\Component\Finder;

use function time;
use JsonSerializable;

/**
* BuildArtifact.
Expand All @@ -37,41 +32,29 @@
* @license GPL-3.0-or-later
*
* @internal
*
* @extends Artifact<array{
* artifact: array{version: int, file: string, date: int},
* template: TemplateArtifact,
* generator: GeneratorArtifact,
* result: ResultArtifact
* }>
*/
final class BuildArtifact extends Artifact
final class BuildArtifact implements JsonSerializable
{
private const VERSION = 1;

public function __construct(
private readonly string $file,
private readonly Builder\BuildResult $buildResult,
private readonly Package\RootPackageInterface $rootPackage,
public readonly int $version,
public readonly string $path,
public readonly int $date,
) {
}

public function dump(): array
/**
* @return array{
* version: int,
* path: string,
* date: int,
* }
*/
public function jsonSerialize(): array
{
return [
'artifact' => [
'version' => self::VERSION,
'file' => $this->file,
'date' => time(),
],
'template' => new TemplateArtifact($this->buildResult),
'generator' => new GeneratorArtifact($this->rootPackage),
'result' => new ResultArtifact($this->buildResult),
'version' => $this->version,
'path' => $this->path,
'date' => $this->date,
];
}

public function getFile(): Finder\SplFileInfo
{
return Helper\FilesystemHelper::createFileObject($this->buildResult->getWrittenDirectory(), $this->file);
}
}
32 changes: 13 additions & 19 deletions src/Builder/Artifact/GeneratorArtifact.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

namespace CPSIT\ProjectBuilder\Builder\Artifact;

use Composer\Package;
use JsonSerializable;

/**
* GeneratorArtifact.
Expand All @@ -32,32 +32,26 @@
* @license GPL-3.0-or-later
*
* @internal
*
* @extends Artifact<array{
* package: PackageArtifact,
* executor: string
* }>
*/
final class GeneratorArtifact extends Artifact
final class GeneratorArtifact implements JsonSerializable
{
public function __construct(
private readonly Package\RootPackageInterface $rootPackage,
public readonly PackageArtifact $package,
public readonly string $executor,
) {
}

public function dump(): array
/**
* @return array{
* package: PackageArtifact,
* executor: string,
* }
*/
public function jsonSerialize(): array
{
return [
'package' => new PackageArtifact($this->rootPackage),
'executor' => $this->determineExecutor(),
'package' => $this->package,
'executor' => $this->executor,
];
}

private function determineExecutor(): string
{
return match (getenv('PROJECT_BUILDER_EXECUTOR')) {
'docker' => 'docker',
default => 'composer',
};
}
}
64 changes: 64 additions & 0 deletions src/Builder/Artifact/Migration/BaseMigration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Composer package "cpsit/project-builder".
*
* Copyright (C) 2023 Elias H盲u脽ler <e.haeussler@familie-redlich.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace CPSIT\ProjectBuilder\Builder\Artifact\Migration;

use CPSIT\ProjectBuilder\Helper;

use function is_callable;

/**
* BaseMigration.
*
* @author Elias H盲u脽ler <e.haeussler@familie-redlich.de>
* @license GPL-3.0-or-later
*/
abstract class BaseMigration implements Migration
{
/**
* @param array<string, mixed> $artifact
* @param non-empty-string $path
* @param non-empty-string|null $targetPath
*/
protected function remapValue(
array &$artifact,
string $path,
string $targetPath = null,
mixed $newValue = null,
): void {
$currentValue = Helper\ArrayHelper::getValueByPath($artifact, $path);

if (is_callable($newValue)) {
$newValue = $newValue($currentValue);
} elseif (null === $newValue) {
$newValue = $currentValue;
}

if (null === $targetPath) {
Helper\ArrayHelper::setValueByPath($artifact, $path, $newValue);
} else {
Helper\ArrayHelper::setValueByPath($artifact, $targetPath, $newValue);
Helper\ArrayHelper::removeByPath($artifact, $path);
}
}
}
Loading
Loading