mirror of
https://github.com/php/pie.git
synced 2026-03-23 23:12:17 +01:00
Validate schema for PIE settings file
This commit is contained in:
@@ -432,12 +432,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Platform/TargetPlatform.php
|
||||
|
||||
-
|
||||
message: '#^Parameter \#1 \$callback of function array_map expects \(callable\(mixed\)\: mixed\)\|null, Closure\(array\)\: non\-empty\-array given\.$#'
|
||||
identifier: argument.type
|
||||
count: 1
|
||||
path: src/SelfManage/Update/FetchPieReleaseFromGitHub.php
|
||||
|
||||
-
|
||||
message: '#^Dead catch \- Php\\Pie\\SelfManage\\Verify\\GithubCliNotAvailable is never thrown in the try block\.$#'
|
||||
identifier: catch.neverThrown
|
||||
@@ -675,7 +669,7 @@ parameters:
|
||||
-
|
||||
message: '#^Parameter \#4 \$body of class Composer\\Util\\Http\\Response constructor expects string\|null, string\|false given\.$#'
|
||||
identifier: argument.type
|
||||
count: 2
|
||||
count: 1
|
||||
path: test/unit/SelfManage/Update/FetchPieReleaseFromGitHubTest.php
|
||||
|
||||
-
|
||||
|
||||
18
resources/pie-settings-schema.json
Normal file
18
resources/pie-settings-schema.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://raw.githubusercontent.com/php/pie/main/resources/pie-config-schema.json",
|
||||
"title": "PIE configuration file schema",
|
||||
"description": "Schema for PIE tool configuration file",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"channel": {
|
||||
"type": "string",
|
||||
"description": "Which update channel to use when running self-update",
|
||||
"enum": [
|
||||
"nightly",
|
||||
"preview",
|
||||
"stable"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,15 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace Php\Pie;
|
||||
|
||||
use Composer\Json\JsonFile;
|
||||
use Php\Pie\SelfManage\Update\Channel;
|
||||
|
||||
use function array_key_exists;
|
||||
use function file_exists;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function is_array;
|
||||
use function json_decode;
|
||||
use function json_encode;
|
||||
use function mkdir;
|
||||
use function rtrim;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
use const JSON_PRETTY_PRINT;
|
||||
@@ -27,16 +29,39 @@ use const JSON_THROW_ON_ERROR;
|
||||
*/
|
||||
class Settings
|
||||
{
|
||||
private const PIE_SETTINGS_FILE_NAME = 'pie-settings.json';
|
||||
private const PIE_SETTINGS_SCHEMA_FILE_NAME = __DIR__ . '/../resources/pie-settings-schema.json';
|
||||
private const PIE_SETTINGS_FILE_NAME = 'pie-settings.json';
|
||||
|
||||
public function __construct(private readonly string $pieWorkingDirectory)
|
||||
{
|
||||
}
|
||||
|
||||
private function pieSettingsFullPath(): string
|
||||
{
|
||||
$workDir = rtrim($this->pieWorkingDirectory, DIRECTORY_SEPARATOR);
|
||||
|
||||
if (! file_exists($workDir)) {
|
||||
mkdir($workDir, recursive: true);
|
||||
}
|
||||
|
||||
return $workDir . DIRECTORY_SEPARATOR . self::PIE_SETTINGS_FILE_NAME;
|
||||
}
|
||||
|
||||
/** @phpstan-assert PieSettings $settingsBlob */
|
||||
private function validateSchema(mixed $settingsBlob): void
|
||||
{
|
||||
JsonFile::validateJsonSchema(
|
||||
self::PIE_SETTINGS_FILE_NAME,
|
||||
$settingsBlob,
|
||||
JsonFile::STRICT_SCHEMA,
|
||||
self::PIE_SETTINGS_SCHEMA_FILE_NAME,
|
||||
);
|
||||
}
|
||||
|
||||
/** @phpstan-return PieSettings */
|
||||
private function read(): array
|
||||
{
|
||||
$pieSettingsFileName = $this->pieWorkingDirectory . DIRECTORY_SEPARATOR . self::PIE_SETTINGS_FILE_NAME;
|
||||
$pieSettingsFileName = $this->pieSettingsFullPath();
|
||||
if (! file_exists($pieSettingsFileName)) {
|
||||
return [];
|
||||
}
|
||||
@@ -48,18 +73,17 @@ class Settings
|
||||
|
||||
$config = json_decode($content, true, flags: JSON_THROW_ON_ERROR);
|
||||
|
||||
// @todo schema validation
|
||||
$this->validateSchema($config);
|
||||
|
||||
return is_array($config) ? $config : [];
|
||||
return $config;
|
||||
}
|
||||
|
||||
/** @param PieSettings $config */
|
||||
/** @param array<array-key, mixed> $config */
|
||||
private function write(array $config): void
|
||||
{
|
||||
// @todo schema validation
|
||||
$this->validateSchema($config);
|
||||
|
||||
$pieSettingsFileName = $this->pieWorkingDirectory . DIRECTORY_SEPARATOR . self::PIE_SETTINGS_FILE_NAME;
|
||||
file_put_contents($pieSettingsFileName, json_encode($config, flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
file_put_contents($this->pieSettingsFullPath(), json_encode($config, flags: JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
||||
}
|
||||
|
||||
public function updateChannel(): Channel
|
||||
|
||||
84
test/unit/SettingsTest.php
Normal file
84
test/unit/SettingsTest.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Php\PieUnitTest;
|
||||
|
||||
use Composer\Json\JsonValidationException;
|
||||
use Composer\Util\Filesystem;
|
||||
use Php\Pie\SelfManage\Update\Channel;
|
||||
use Php\Pie\Settings;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function mkdir;
|
||||
use function str_replace;
|
||||
use function sys_get_temp_dir;
|
||||
use function trim;
|
||||
use function uniqid;
|
||||
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
||||
#[CoversClass(Settings::class)]
|
||||
final class SettingsTest extends TestCase
|
||||
{
|
||||
public function testReadingInvalidConfigThrowsException(): void
|
||||
{
|
||||
$workingDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('pie_settings_test', true) . DIRECTORY_SEPARATOR;
|
||||
mkdir($workingDir, recursive: true);
|
||||
file_put_contents($workingDir . 'pie-settings.json', '{"channel":"surprise! not a valid value"}');
|
||||
|
||||
$settings = new Settings($workingDir);
|
||||
|
||||
$this->expectException(JsonValidationException::class);
|
||||
$settings->updateChannel();
|
||||
}
|
||||
|
||||
public function testNewSettingsJsonCanBeCreated(): void
|
||||
{
|
||||
$workingDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('pie_settings_test', true) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$settings = new Settings($workingDir);
|
||||
self::assertSame(Channel::Stable, $settings->updateChannel());
|
||||
|
||||
$settings->changeUpdateChannel(Channel::Preview);
|
||||
self::assertSame(Channel::Preview, $settings->updateChannel());
|
||||
|
||||
self::assertSame(
|
||||
trim(<<<'JSON'
|
||||
{
|
||||
"channel": "preview"
|
||||
}
|
||||
JSON),
|
||||
str_replace("\r\n", "\n", (string) file_get_contents($workingDir . 'pie-settings.json')),
|
||||
);
|
||||
|
||||
(new Filesystem())->remove($workingDir);
|
||||
}
|
||||
|
||||
public function testExistingSettingsCanBeUpdated(): void
|
||||
{
|
||||
$workingDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('pie_settings_test', true) . DIRECTORY_SEPARATOR;
|
||||
mkdir($workingDir, recursive: true);
|
||||
file_put_contents($workingDir . 'pie-settings.json', '{"channel": "stable"}');
|
||||
|
||||
$settings = new Settings($workingDir);
|
||||
self::assertSame(Channel::Stable, $settings->updateChannel());
|
||||
|
||||
$settings->changeUpdateChannel(Channel::Preview);
|
||||
self::assertSame(Channel::Preview, $settings->updateChannel());
|
||||
|
||||
self::assertSame(
|
||||
trim(<<<'JSON'
|
||||
{
|
||||
"channel": "preview"
|
||||
}
|
||||
JSON),
|
||||
str_replace("\r\n", "\n", (string) file_get_contents($workingDir . 'pie-settings.json')),
|
||||
);
|
||||
|
||||
(new Filesystem())->remove($workingDir);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user