first commit

This commit is contained in:
2024-07-15 12:33:27 +02:00
commit ce50ae282b
22084 changed files with 2623791 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: "ubuntu-latest"
php: "8.0"
coverage: "none"
- os: "ubuntu-latest"
php: "8.1"
coverage: "pcov"
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
# Only report coverage once
coverage: ${{ matrix.coverage }}
- name: Validate composer.json and composer.lock
run: composer validate --strict
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer -n install --prefer-dist -o
- name: Run test suite
if: matrix.coverage == 'none'
run: composer run-script test
- name: Run coverage
if: matrix.coverage == 'pcov'
run: composer run-script coverage
- name: Upload coverage results to Coveralls
if: matrix.coverage == 'pcov'
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: composer run-script coveralls

51
vendor/grasmash/expander/.gitignore vendored Normal file
View File

@@ -0,0 +1,51 @@
# Cache and logs (Symfony2)
/app/cache/*
/app/logs/*
!app/cache/.gitkeep
!app/logs/.gitkeep
# Email spool folder
/app/spool/*
# Cache, session files and logs (Symfony3)
/var/cache/*
/var/logs/*
/var/sessions/*
!var/cache/.gitkeep
!var/logs/.gitkeep
!var/sessions/.gitkeep
# Parameters
/app/config/parameters.yml
/app/config/parameters.ini
# Managed by Composer
/app/bootstrap.php.cache
/var/bootstrap.php.cache
/bin/*
!bin/console
!bin/symfony_requirements
/vendor/
# Assets and user uploads
/web/bundles/
/web/uploads/
# Assets managed by Bower
/web/assets/vendor/
# PHPUnit
/app/phpunit.xml
/phpunit.xml
# Build data
/build/
# Composer PHAR
/composer.phar
# Backup entities generated with doctrine:generate:entities command
*/Entity/*~
.idea
.phpunit.result.cache

View File

21
vendor/grasmash/expander/LICENSE.md vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Matthew Grasmick
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

153
vendor/grasmash/expander/README.md vendored Normal file
View File

@@ -0,0 +1,153 @@
[![CI](https://github.com/grasmash/expander/actions/workflows/php.yml/badge.svg)](https://github.com/grasmash/expander/actions/workflows/php.yml) [![Packagist](https://img.shields.io/packagist/v/grasmash/expander.svg)](https://packagist.org/packages/grasmash/expander)
[![Total Downloads](https://poser.pugx.org/grasmash/expander/downloads)](https://packagist.org/packages/grasmash/expander) [![Coverage Status](https://coveralls.io/repos/github/grasmash/expander/badge.svg?branch=main)](https://coveralls.io/github/grasmash/expander?branch=main)
This tool expands dot-notated, string property references into their corresponding values. This is useful for run time expansion of property references in configuration files.
For example implementation, see [Yaml Expander](https://github.com/grasmash/yaml-expander).
### Installation
composer require grasmash/expander
### Example usage:
Property references use dot notation to indicate array keys, and must be wrapped in `${}`.
Expansion logic:
```php
<?php
$array = [
'type' => 'book',
'book' => [
'title' => 'Dune',
'author' => 'Frank Herbert',
'copyright' => '${book.author} 1965',
'protaganist' => '${characters.0.name}',
'media' => [
0 => 'hardcover',
1 => 'paperback',
],
'nested-reference' => '${book.sequel}',
],
'characters' => [
0 => [
'name' => 'Paul Atreides',
'occupation' => 'Kwisatz Haderach',
'aliases' => [
0 => 'Usul',
1 => 'Muad\'Dib',
2 => 'The Preacher',
],
],
1 => [
'name' => 'Duncan Idaho',
'occupation' => 'Swordmaster',
],
],
'summary' => '${book.title} by ${book.author}',
'publisher' => '${not.real.property}',
'sequels' => '${book.sequel}, and others.',
'available-products' => '${book.media.1}, ${book.media.0}',
'product-name' => '${${type}.title}',
'boolean-value' => true,
'expand-boolean' => '${boolean-value}',
'null-value' => NULL,
'inline-array' => [
0 => 'one',
1 => 'two',
2 => 'three',
],
'expand-array' => '${inline-array}',
'env-test' => '${env.test}',
];
$expander = new Expander();
// Optionally set a logger.
$expander->setLogger(new Psr\Log\NullLogger());
// Optionally set a Stringfier, used to convert array placeholders into strings. Defaults to using implode() with `,` delimeter.
// @see StringifierInterface.
$expander->setStringifier(new Grasmash\Expander\Stringifier());
// Parse an array, expanding internal property references.
$expanded = $expander->expandArrayProperties($array);
// Parse an array, expanding references using both internal and supplementary values.
$reference_properties = 'book' => ['sequel' => 'Dune Messiah'];
// Set an environmental variable.
putenv("test=gomjabbar");
$expanded = $expander->expandArrayProperties($array, $reference_properties);
print_r($expanded);
````
Resultant array:
```php
Array
(
[type] => book
[book] => Array
(
[title] => Dune
[author] => Frank Herbert
[copyright] => Frank Herbert 1965
[protaganist] => Paul Atreides
[media] => Array
(
[0] => hardcover
[1] => paperback
)
[nested-reference] => Dune Messiah
)
[characters] => Array
(
[0] => Array
(
[name] => Paul Atreides
[occupation] => Kwisatz Haderach
[aliases] => Array
(
[0] => Usul
[1] => Muad\'Dib
[2] => The Preacher
)
)
[1] => Array
(
[name] => Duncan Idaho
[occupation] => Swordmaster
)
)
[summary] => Dune by Frank Herbert
[publisher] => ${not.real.property}
[sequels] => Dune Messiah, and others.
[available-products] => paperback, hardcover
[product-name] => Dune
[boolean-value] => true,
[expand-boolean] => true,
[null-value] =>
[inline-array] => Array
(
[0] => one
[1] => two
[2] => three
)
[expand-array] => one,two,three
[env-test] => gomjabbar
[env] => Array
(
[test] => gomjabbar
)
)
```

11
vendor/grasmash/expander/RELEASE.md vendored Normal file
View File

@@ -0,0 +1,11 @@
# Releasing
### Execute tests
./scripts/run-tests.sh
To quickly fix PHPCS issues:
./scripts/clean-code.sh

60
vendor/grasmash/expander/composer.json vendored Normal file
View File

@@ -0,0 +1,60 @@
{
"name": "grasmash/expander",
"description": "Expands internal property references in PHP arrays file.",
"type": "library",
"require": {
"php": ">=8.0",
"dflydev/dot-access-data": "^3.0.0",
"psr/log": "^2 | ^3"
},
"license": "MIT",
"authors": [
{
"name": "Matthew Grasmick"
}
],
"minimum-stability": "stable",
"autoload": {
"psr-4": {
"Grasmash\\Expander\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Grasmash\\Expander\\Tests\\": "tests/src/"
}
},
"require-dev": {
"greg-1-anderson/composer-test-scenarios": "^1",
"php-coveralls/php-coveralls": "^2.5",
"phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "^3.3"
},
"scripts": {
"cs": "phpcs",
"cbf": "phpcbf",
"unit": "phpunit",
"lint": [
"find src -name '*.php' -print0 | xargs -0 -n1 php -l",
"find tests -name '*.php' -print0 | xargs -0 -n1 php -l"
],
"test": [
"@lint",
"@unit",
"@cs"
],
"coverage": "php -d pcov.enabled=1 vendor/bin/phpunit tests/src --coverage-clover build/logs/clover.xml",
"coveralls": [
"php-coveralls -vvv"
]
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "1.x-dev"
}
}
}

3935
vendor/grasmash/expander/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

26
vendor/grasmash/expander/phpcs.xml.dist vendored Normal file
View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Expander">
<description>Yaml CLI PHP CodeSniffer configuration.</description>
<arg name="extensions" value="php"/>
<arg name="colors"/>
<arg name="cache" value="build/.phpcs-cache"/>
<arg name="parallel" value="10"/>
<file>.</file>
<!-- Danger! Exclude patterns apply to the full file path, including parent directories of the current repository. -->
<!-- Don't exclude common directory names like `build`, which will fail on Travis CI because of /home/travis/build/acquia/<project>. -->
<!-- @see https://github.com/squizlabs/PHP_CodeSniffer/issues/981 -->
<exclude-pattern>var/</exclude-pattern>
<exclude-pattern>vendor/*</exclude-pattern>
<exclude-pattern>tests/resources/*</exclude-pattern>
<rule ref="PSR2">
<exclude name="Generic.Files.LineLength"/>
</rule>
</ruleset>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<!-- phpunit.xml.dist -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"/>
</report>
</coverage>
<testsuites>
<testsuite name="Yaml Expander Test Suite">
<directory>tests/src</directory>
</testsuite>
</testsuites>
<logging/>
</phpunit>

View File

@@ -0,0 +1,310 @@
<?php
namespace Grasmash\Expander;
use Dflydev\DotAccessData\Data;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
/**
* Class Expander
* @package Grasmash\Expander
*/
class Expander implements LoggerAwareInterface
{
/**
* @var \Grasmash\Expander\StringifierInterface
*/
protected StringifierInterface $stringifier;
/**
* @var \Psr\Log\LoggerInterface
*/
protected LoggerInterface $logger;
public function __construct()
{
$this->setLogger(new NullLogger());
$this->setStringifier(new Stringifier());
}
/**
* @return \Grasmash\Expander\StringifierInterface
*/
public function getStringifier(): StringifierInterface
{
return $this->stringifier;
}
/**
* @param \Grasmash\Expander\StringifierInterface $stringifier
*/
public function setStringifier(StringifierInterface $stringifier)
{
$this->stringifier = $stringifier;
}
/**
* @return \Psr\Log\LoggerInterface
*/
public function getLogger(): LoggerInterface
{
return $this->logger;
}
/**
* @param \Psr\Log\LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/**
* Expands property placeholders in an array.
*
* Placeholders should be formatted as ${parent.child}.
*
* @param array $array
* An array containing properties to expand.
*
* @return array
* The modified array in which placeholders have been replaced with
* values.
*/
public function expandArrayProperties(array $array, $reference_array = []): array
{
$data = new Data($array);
if ($reference_array) {
$reference_data = new Data($reference_array);
$this->doExpandArrayProperties($data, $array, '', $reference_data);
} else {
$this->doExpandArrayProperties($data, $array);
}
return $data->export();
}
/**
* Performs the actual property expansion.
*
* @param Data $data
* A data object, containing the $array.
* @param array $array
* The original, unmodified array.
* @param string $parent_keys
* The parent keys of the current key in dot notation. This is used to
* track the absolute path to the current key in recursive cases.
* @param Data|null $reference_data
* A reference data object. This is not operated upon but is used as a
* reference to provide supplemental values for property expansion.
*/
protected function doExpandArrayProperties(
Data $data,
array $array,
string $parent_keys = '',
Data $reference_data = null
) {
foreach ($array as $key => $value) {
// Boundary condition(s).
if ($value === null || is_bool($value)) {
continue;
}
// Recursive case.
if (is_array($value)) {
$this->doExpandArrayProperties($data, $value, $parent_keys . "$key.", $reference_data);
} else {
// Base case.
$this->expandStringProperties($data, $parent_keys, $reference_data, $value, $key);
}
}
}
/**
* Expand a single property.
*
* @param Data $data
* A data object, containing the $array.
* @param string $parent_keys
* The parent keys of the current key in dot notation. This is used to
* track the absolute path to the current key in recursive cases.
* @param Data|null $reference_data
* A reference data object. This is not operated upon but is used as a
* reference to provide supplemental values for property expansion.
* @param string $value
* The unexpanded property value.
* @param string $key
* The immediate key of the property.
*
* @return mixed
*/
protected function expandStringProperties(
Data $data,
string $parent_keys,
?Data $reference_data,
string $value,
string $key
): mixed {
$pattern = '/\$\{([^\$}]+)\}/';
// We loop through all placeholders in a given string.
// E.g., '${placeholder1} ${placeholder2}' requires two replacements.
while (str_contains((string) $value, '${')) {
$original_value = $value;
$value = preg_replace_callback(
$pattern,
function ($matches) use ($data, $reference_data) {
return $this->expandStringPropertiesCallback($matches, $data, $reference_data);
},
$value,
-1,
$count
);
// If the value was just a _single_ property reference, we have the opportunity to preserve the data type.
if ($count === 1) {
preg_match($pattern, $original_value, $matches);
if ($matches[0] === $original_value) {
$value = $this->expandStringPropertiesCallback($matches, $data, $reference_data);
}
}
// If no replacement occurred at all, break to prevent
// infinite loop.
if ($original_value === $value) {
break;
}
// Set value on $data object.
if ($parent_keys) {
$full_key = $parent_keys . "$key";
} else {
$full_key = $key;
}
$data->set($full_key, $value);
}
return $value;
}
/**
* Expansion callback used by preg_replace_callback() in expandProperty().
*
* @param array $matches
* An array of matches created by preg_replace_callback().
* @param Data $data
* A data object containing the complete array being operated upon.
* @param Data|null $reference_data
* A reference data object. This is not operated upon but is used as a
* reference to provide supplemental values for property expansion.
*
* @return mixed
*/
public function expandStringPropertiesCallback(
array $matches,
Data $data,
Data $reference_data = null
): mixed {
$property_name = $matches[1];
$unexpanded_value = $matches[0];
// Use only values within the subject array's data.
if (!$reference_data) {
return $this->expandProperty($property_name, $unexpanded_value, $data);
} else {
// Search both the subject array's data and the reference data for a value.
return $this->expandPropertyWithReferenceData(
$property_name,
$unexpanded_value,
$data,
$reference_data
);
}
}
/**
* Searches both the subject data and the reference data for value.
*
* @param string $property_name
* The name of the value for which to search.
* @param string $unexpanded_value
* The original, unexpanded value, containing the placeholder.
* @param Data $data
* A data object containing the complete array being operated upon.
* @param Data|null $reference_data
* A reference data object. This is not operated upon but is used as a
* reference to provide supplemental values for property expansion.
*
* @return string|null The expanded string.
* The expanded string.
*/
public function expandPropertyWithReferenceData(
string $property_name,
string $unexpanded_value,
Data $data,
?Data $reference_data
): ?string {
$expanded_value = $this->expandProperty(
$property_name,
$unexpanded_value,
$data
);
// If the string was not changed using the subject data, try using
// the reference data.
if ($expanded_value === $unexpanded_value) {
$expanded_value = $this->expandProperty(
$property_name,
$unexpanded_value,
$reference_data
);
}
return $expanded_value;
}
/**
* Searches a data object for a value.
*
* @param string $property_name
* The name of the value for which to search.
* @param string $unexpanded_value
* The original, unexpanded value, containing the placeholder.
* @param Data $data
* A data object containing possible replacement values.
*
* @return mixed
*/
public function expandProperty(string $property_name, string $unexpanded_value, Data $data): mixed
{
if (str_starts_with($property_name, "env.") &&
!$data->has($property_name)) {
$env_key = substr($property_name, 4);
if (isset($_SERVER[$env_key])) {
$data->set($property_name, $_SERVER[$env_key]);
} elseif (getenv($env_key)) {
$data->set($property_name, getenv($env_key));
}
}
if (!$data->has($property_name)) {
$this->log("Property \${'$property_name'} could not be expanded.");
return $unexpanded_value;
} else {
$expanded_value = $data->get($property_name);
if (is_array($expanded_value)) {
return $this->getStringifier()->stringifyArray($expanded_value);
}
$this->log("Expanding property \${'$property_name'} => $expanded_value.");
return $expanded_value;
}
}
/**
* Logs a message using the logger.
*
* @param string $message
* The message to log.
*/
public function log(string $message)
{
$this->getLogger()?->debug($message);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Grasmash\Expander;
/**
* Class Stringifier
* @package Grasmash\Expander
*/
class Stringifier implements StringifierInterface
{
/**
* Converts array to string.
*
* @param array $array
* The array to convert.
*
* @return string
* The resultant string.
*/
public static function stringifyArray(array $array): string
{
return implode(',', $array);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Grasmash\Expander;
interface StringifierInterface
{
/**
* Converts array to string.
*
* @param array $array
* The array to convert.
*
* @return string
* The resultant string.
*/
public static function stringifyArray(array $array): string;
}

View File

@@ -0,0 +1,142 @@
<?php
namespace Grasmash\Expander\Tests;
use Dflydev\DotAccessData\Data;
use Grasmash\Expander\Expander;
use Grasmash\Expander\Stringifier;
use PHPUnit\Framework\TestCase;
class ExpanderTest extends TestCase
{
/**
* Tests Expander::expandArrayProperties().
*
* @param array $array
* @param array $reference_array
*
* @dataProvider providerSourceData
*/
public function testExpandArrayProperties(array $array, array $reference_array)
{
$expander = new Expander();
$this->setEnvVarFixture('test', 'gomjabbar');
$expanded = $expander->expandArrayProperties($array);
$this->assertEquals('gomjabbar', $expanded['env-test']);
$this->assertEquals('Frank Herbert 1965', $expanded['book']['copyright']);
$this->assertEquals('Paul Atreides', $expanded['book']['protaganist']);
$this->assertEquals('Dune by Frank Herbert', $expanded['summary']);
$this->assertEquals('${book.media.1}, hardcover', $expanded['available-products']);
$this->assertEquals('Dune', $expanded['product-name']);
$this->assertEquals(Stringifier::stringifyArray($array['inline-array']), $expanded['expand-array']);
$this->assertEquals(true, $expanded['boolean-value']);
$this->assertIsBool($expanded['boolean-value']);
$this->assertEquals(true, $expanded['expand-boolean']);
$this->assertIsBool($expanded['expand-boolean']);
$expanded = $expander->expandArrayProperties($array, $reference_array);
$this->assertEquals('Dune Messiah, and others.', $expanded['sequels']);
$this->assertEquals('Dune Messiah', $expanded['book']['nested-reference']);
}
/**
* @return array
* An array of values to test.
*/
public function providerSourceData(): array
{
return [
[
[
'type' => 'book',
'book' => [
'title' => 'Dune',
'author' => 'Frank Herbert',
'copyright' => '${book.author} 1965',
'protaganist' => '${characters.0.name}',
'media' => [
0 => 'hardcover',
],
'nested-reference' => '${book.sequel}',
],
'characters' => [
0 => [
'name' => 'Paul Atreides',
'occupation' => 'Kwisatz Haderach',
'aliases' => [
0 => 'Usul',
1 => "Muad'Dib",
2 => 'The Preacher',
],
],
1 => [
'name' => 'Duncan Idaho',
'occupation' => 'Swordmaster',
],
],
'summary' => '${book.title} by ${book.author}',
'publisher' => '${not.real.property}',
'sequels' => '${book.sequel}, and others.',
'available-products' => '${book.media.1}, ${book.media.0}',
'product-name' => '${${type}.title}',
'boolean-value' => true,
'expand-boolean' => '${boolean-value}',
'null-value' => null,
'inline-array' => [
0 => 'one',
1 => 'two',
2 => 'three',
],
'expand-array' => '${inline-array}',
'env-test' => '${env.test}',
'test_expanded_to_null' => '${book.expanded_to_null}'
],
[
'book' => [
'sequel' => 'Dune Messiah',
'expanded_to_null' => null,
]
]
],
];
}
/**
* Tests Expander::expandProperty().
*
* @dataProvider providerTestExpandProperty
*/
public function testExpandProperty(array $array, $property_name, $unexpanded_string, $expected)
{
$data = new Data($array);
$expander = new Expander();
$expanded_value = $expander->expandProperty($property_name, $unexpanded_string, $data);
$this->assertEquals($expected, $expanded_value);
}
/**
* @return array
*/
public function providerTestExpandProperty(): array
{
return [
[ ['author' => 'Frank Herbert'], 'author', '${author}', 'Frank Herbert' ],
[ ['book' => ['author' => 'Frank Herbert' ]], 'book.author', '${book.author}', 'Frank Herbert' ],
];
}
/**
* @param $key
* @param $value
*/
protected function setEnvVarFixture($key, $value)
{
putenv("$key=$value");
$_SERVER[$key] = $value;
}
}

15
vendor/grasmash/yaml-cli/.editorconfig vendored Normal file
View File

@@ -0,0 +1,15 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# PHP PSR-2 Coding Standards
# http://www.php-fig.org/psr/psr-2/
root = true
[*.php]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

View File

@@ -0,0 +1,65 @@
name: CI
on:
push:
branches: [ 3.x ]
pull_request:
branches: [ 3.x ]
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: "ubuntu-latest"
php: "8.0"
coverage: "none"
- os: "ubuntu-latest"
php: "8.1"
coverage: "none"
- os: "ubuntu-latest"
php: "8.2"
coverage: "pcov"
- os: "ubuntu-latest"
php: "8.3"
coverage: "pcov"
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
# Only report coverage once
coverage: ${{ matrix.coverage }}
- name: Validate composer.json and composer.lock
run: composer validate --strict
- name: Un-pin PHP version used for dependency resolution
run: composer config --unset platform.php
- name: Install dependencies; use "update" so that we can get the right dependencies for our php version
run: composer -n update --prefer-dist -o
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md
- name: Run test suite
if: matrix.coverage == 'none'
run: composer run-script test
- name: Run coverage
if: matrix.coverage == 'pcov'
run: composer run-script coverage
- name: Upload coverage results to Coveralls
if: matrix.coverage == 'pcov'
env:
COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: composer run-script coveralls

44
vendor/grasmash/yaml-cli/.gitignore vendored Normal file
View File

@@ -0,0 +1,44 @@
# Created by .ignore support plugin (hsz.mobi)
### Symfony template
# Cache and logs (Symfony2)
/app/cache/*
/app/logs/*
!app/cache/.gitkeep
!app/logs/.gitkeep
# Cache and logs (Symfony3)
/var/cache/*
/var/logs/*
!var/cache/.gitkeep
!var/logs/.gitkeep
# Parameters
/app/config/parameters.yml
/app/config/parameters.ini
# Managed by Composer
/app/bootstrap.php.cache
/var/bootstrap.php.cache
/vendor/
# Assets and user uploads
/web/bundles/
/web/uploads/
# PHPUnit
/app/phpunit.xml
/phpunit.xml
# Build data
/build/
# Composer PHAR
/composer.phar
# Config file
/config/
.idea
.phpunit.result.cache

View File

16
vendor/grasmash/yaml-cli/LICENSE.md vendored Normal file
View File

@@ -0,0 +1,16 @@
MIT License
Copyright (c) 2017 Matthew Grasmick
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

62
vendor/grasmash/yaml-cli/README.md vendored Normal file
View File

@@ -0,0 +1,62 @@
[![CI](https://github.com/grasmash/yaml-cli/actions/workflows/php.yml/badge.svg)](https://github.com/grasmash/yaml-cli/actions/workflows/php.yml) [![Packagist](https://img.shields.io/packagist/v/grasmash/yaml-cli.svg)](https://packagist.org/packages/grasmash/yaml-cli) [![Total Downloads](https://poser.pugx.org/grasmash/yaml-cli/downloads)](https://packagist.org/packages/grasmash/yaml-cli) [![Coverage Status](https://coveralls.io/repos/github/grasmash/yaml-cli/badge.svg?branch=master)](https://coveralls.io/github/grasmash/yaml-cli?branch=master)
Yet another command line tool for reading and manipulating yaml files, built on
the [Symfony console component](http://symfony.com/doc/current/components/console.html).
### Commands:
| Command | Description |
|--------------| ----------------------------------------------------|
| get:value | Get a value for a specific key in a YAML file. |
| get:type | Get the data type of a value in a YAML file. |
| lint | Validates that a given YAML file has valid syntax. |
| unset:key | Unset a specific key in a YAML file. |
| update:key | Change a specific key in a YAML file. |
| update:value | Update the value for a specific key in a YAML file. |
### Installation
composer require grasmash/yaml-cli
### Example usage:
./vendor/bin/yaml-cli get:value somefile.yml some-key
./vendor/bin/yaml-cli get:type somefile.yml some-key
./vendor/bin/yaml-cli lint somefile.yml
./vendor/bin/yaml-cli unset:value somefile.yml some-key
./vendor/bin/yaml-cli update:key somefile.yml old-key new-key
./vendor/bin/yaml-cli update:value somefile.yml some-key some-value
# Cast to boolean.
./vendor/bin/yaml-cli update:value somefile.yml some-key false
./vendor/bin/yaml-cli update:value somefile.yml some-key true
./vendor/bin/yaml-cli update:value somefile.yml some-key 0 --type=boolean
./vendor/bin/yaml-cli update:value somefile.yml some-key 0 --type=bool
# Cast to null.
./vendor/bin/yaml-cli update:value somefile.yml some-key null
./vendor/bin/yaml-cli update:value somefile.yml some-key ~ --type=null
# Cast to integer.
./vendor/bin/yaml-cli update:value somefile.yml some-key 1 --type=integer
./vendor/bin/yaml-cli update:value somefile.yml some-key 1 --type=int
# Cast to float/double/real.
./vendor/bin/yaml-cli update:value somefile.yml some-key 1.0 --type=float
./vendor/bin/yaml-cli update:value somefile.yml some-key 1.0 --type=double
./vendor/bin/yaml-cli update:value somefile.yml some-key 1.0 --type=real
# Forcibly cast to string for values that would otherwise be boolean or null.
./vendor/bin/yaml-cli update:value somefile.yml some-key true --type=string
./vendor/bin/yaml-cli update:value somefile.yml some-key false --type=string
./vendor/bin/yaml-cli update:value somefile.yml some-key null --type=string
### Similar tools:
- Javascript - https://github.com/pandastrike/yaml-cli
- Ruby - https://github.com/rubyworks/yaml_command
- Python - https://github.com/0k/shyaml
### Recognition
This project was inspired by the yaml commands in [Drupal Console](https://drupalconsole.com/).

11
vendor/grasmash/yaml-cli/RELEASE.md vendored Normal file
View File

@@ -0,0 +1,11 @@
# Releasing
### Execute tests
./scripts/run-tests.sh
To quickly fix PHPCS issues:
./scripts/clean-code.sh

View File

@@ -0,0 +1,40 @@
<?php
set_time_limit(0);
$repo_root = __DIR__ . '/..';
$possible_autoloader_locations = [
$repo_root . '/../../autoload.php',
$repo_root . '/vendor/autoload.php',
];
foreach ($possible_autoloader_locations as $location) {
if (file_exists($location)) {
$autoloader = require_once $location;
break;
}
}
if (empty($autoloader)) {
echo 'Unable to autoload classes for yml-cli.' . PHP_EOL;
exit(1);
}
use Grasmash\YamlCli\Command\GetTypeCommand;
use Grasmash\YamlCli\Command\GetValueCommand;
use Grasmash\YamlCli\Command\LintCommand;
use Grasmash\YamlCli\Command\UnsetKeyCommand;
use Grasmash\YamlCli\Command\UpdateKeyCommand;
use Grasmash\YamlCli\Command\UpdateValueCommand;
use Symfony\Component\Console\Application;
$application = new Application('yaml-cli', '@package_version@');
$application->add(new GetValueCommand());
$application->add(new GetTypeCommand());
$application->add(new LintCommand());
$application->add(new UnsetKeyCommand());
$application->add(new UpdateKeyCommand());
$application->add(new UpdateValueCommand());
$application->run();

3
vendor/grasmash/yaml-cli/bin/yaml-cli vendored Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env php
<?php
require __DIR__ . '/application.php';

66
vendor/grasmash/yaml-cli/composer.json vendored Normal file
View File

@@ -0,0 +1,66 @@
{
"name": "grasmash/yaml-cli",
"description": "A command line tool for reading and manipulating yaml files.",
"type": "library",
"require": {
"php": ">=8.0",
"symfony/yaml": "^6 || ^7",
"symfony/console": "^6 || ^7",
"symfony/filesystem": "^6 || ^7",
"dflydev/dot-access-data": "^3"
},
"license": "MIT",
"authors": [
{
"name": "Matthew Grasmick"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"autoload": {
"psr-4": {
"Grasmash\\YamlCli\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Grasmash\\YamlCli\\Tests\\": "tests/src/"
}
},
"bin": [
"bin/yaml-cli"
],
"scripts": {
"cs": "phpcs",
"cbf": "phpcbf",
"unit": "phpunit",
"lint": [
"find src -name '*.php' -print0 | xargs -0 -n1 php -l",
"find tests -name '*.php' -print0 | xargs -0 -n1 php -l"
],
"test": [
"@lint",
"@unit",
"@cs"
],
"coverage": "php -d pcov.enabled=1 vendor/bin/phpunit tests/src --coverage-clover build/logs/clover.xml",
"coveralls": [
"php-coveralls -vvv"
]
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.0",
"phpunit/phpunit": "^9",
"php-coveralls/php-coveralls": "^2"
},
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"config": {
"platform": {
"php": "8.2.18"
}
}
}

3552
vendor/grasmash/yaml-cli/composer.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

26
vendor/grasmash/yaml-cli/phpcs.xml.dist vendored Normal file
View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="YamlCLI">
<description>Yaml CLI PHP CodeSniffer configuration.</description>
<arg name="extensions" value="php"/>
<arg name="colors"/>
<arg name="cache" value="build/.phpcs-cache"/>
<arg name="parallel" value="10"/>
<file>.</file>
<!-- Danger! Exclude patterns apply to the full file path, including parent directories of the current repository. -->
<!-- Don't exclude common directory names like `build`, which will fail on Travis CI because of /home/travis/build/acquia/<project>. -->
<!-- @see https://github.com/squizlabs/PHP_CodeSniffer/issues/981 -->
<exclude-pattern>var/</exclude-pattern>
<exclude-pattern>vendor/*</exclude-pattern>
<exclude-pattern>tests/resources/*</exclude-pattern>
<rule ref="PSR2">
<exclude name="Generic.Files.LineLength"/>
</rule>
</ruleset>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<!-- phpunit.xml.dist -->
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
cacheResultFile="build/.phpunit.result.cache"
failOnWarning="true"
failOnRisky="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"/>
</report>
</coverage>
<testsuites>
<testsuite name="Yaml CLI Test Suite">
<directory>tests/src</directory>
</testsuite>
</testsuites>
<logging/>
</phpunit>

View File

@@ -0,0 +1,140 @@
<?php
namespace Grasmash\YamlCli\Command;
use Dflydev\DotAccessData\Data;
use Grasmash\YamlCli\Loader\JsonFileLoader;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\FormatterHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Yaml\Yaml;
/**
* Class CommandBase
*
* @package Grasmash\YamlCli\Command
*/
abstract class CommandBase extends Command
{
/** @var Filesystem */
protected $fs;
/**
* @var InputInterface
*/
protected $input;
/**
* @var OutputInterface
*/
protected $output;
/** @var FormatterHelper */
protected $formatter;
/**
* Initializes the command just after the input has been validated.
*
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*/
protected function initialize(InputInterface $input, OutputInterface $output)
{
$this->input = $input;
$this->output = $output;
$this->formatter = $this->getHelper('formatter');
$this->fs = new Filesystem();
}
/**
* Loads a yaml file.
*
* @param $filename
* The file name.
*
* @return array|bool
* The parsed content of the yaml file. FALSE if an error occured.
*/
public function loadYamlFile($filename)
{
if (!file_exists($filename)) {
$this->output->writeln("<error>The file $filename does not exist.</error>");
return false;
}
try {
$contents = Yaml::parse(file_get_contents($filename));
} catch (\Exception $e) {
$this->output->writeln("<error>There was an error parsing $filename. The contents are not valid YAML.</error>");
$this->output->writeln($e->getMessage());
return false;
}
return $contents;
}
/**
* Writes YAML data to a file.
*
* @param string $filename
* The filename.
* @param Data $data
* The YAML file contents.
*
* @return bool
* TRUE if file was written successfully. Otherwise, FALSE.
*/
public function writeYamlFile($filename, $data)
{
try {
// @todo Allow the inline and indent variables to be set via command line option.
$yaml = Yaml::dump($data->export(), 3, 2);
} catch (\Exception $e) {
$this->output->writeln("<error>There was an error dumping the YAML contents for $filename.</error>");
$this->output->writeln($e->getMessage());
return false;
}
try {
// @todo Use Symfony file system instead so that exceptions can be caught.
file_put_contents($filename, $yaml);
} catch (\Exception $e) {
$this->output->writeln("<error>There was an writing to $filename.</error>");
$this->output->writeln($e->getMessage());
return false;
}
return true;
}
/**
* Checks if a key exists in an array.
*
* Supports dot notation for keys. E.g., first.second.parts.
*
* @param array $data
* The array of data that may contain key.
* @param string $key
* The array key, optionally in dot notation format.
*
* @return bool
*
*/
protected function checkKeyExists($data, $key)
{
if (!$data->has($key)) {
$this->output->writeln("<error>The key $key does not exist.");
return false;
}
return true;
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace Grasmash\YamlCli\Command;
use Dflydev\DotAccessData\Data;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class GetTypeCommand
*
* @package Grasmash\YamlCli\Command
*/
class GetTypeCommand extends CommandBase
{
/**
* {inheritdoc}
*/
protected function configure()
{
$this
->setName('get:type')
->setDescription('Get the type of a value for a specific key in a YAML file.')
->addUsage("path/to/file.yml example.key")
->addArgument(
'filename',
InputArgument::REQUIRED,
"The filename of the YAML file"
)
->addArgument(
'key',
InputArgument::REQUIRED,
"The key for the value to get the type of, in dot notation."
);
}
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$filename = $input->getArgument('filename');
$key = $input->getArgument('key');
$yaml_parsed = $this->loadYamlFile($filename);
if (!$yaml_parsed) {
// Exit with a status of 1.
return 1;
}
$data = new Data($yaml_parsed);
if (!$this->checkKeyExists($data, $key)) {
return 1;
}
$value = $data->get($key);
$output->writeln(trim(gettype($value)));
return 0;
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Grasmash\YamlCli\Command;
use Dflydev\DotAccessData\Data;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Yaml\Yaml;
/**
* Class CreateProjectCommand
*
* @package Grasmash\YamlCli\Command
*/
class GetValueCommand extends CommandBase
{
/**
* {inheritdoc}
*/
protected function configure()
{
$this
->setName('get:value')
->setDescription('Get a value for a specific key in a YAML file.')
->addUsage("path/to/file.yml example.key")
->addArgument(
'filename',
InputArgument::REQUIRED,
"The filename of the YAML file"
)
->addArgument(
'key',
InputArgument::REQUIRED,
"The key for the value to get, in dot notation."
);
}
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$filename = $input->getArgument('filename');
$key = $input->getArgument('key');
$yaml_parsed = $this->loadYamlFile($filename);
if (!$yaml_parsed) {
// Exit with a status of 1.
return 1;
}
$data = new Data($yaml_parsed);
if (!$this->checkKeyExists($data, $key)) {
return 1;
}
$value = $data->get($key);
$output->writeln(trim(Yaml::dump($value)));
return 0;
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Grasmash\YamlCli\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class CreateProjectCommand
*
* @package Grasmash\YamlCli\Command
*/
class LintCommand extends CommandBase
{
/**
* {inheritdoc}
*/
protected function configure()
{
$this
->setName('lint')
->setDescription('Validates that a given YAML file has valid syntax.')
->addUsage("path/to/file.yml")
->addArgument(
'filename',
InputArgument::REQUIRED,
"The filename of the YAML file"
);
}
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$filename = $input->getArgument('filename');
$yaml_parsed = $this->loadYamlFile($filename);
if (!$yaml_parsed) {
// Exit with a status of 1.
return 1;
}
if (OutputInterface::VERBOSITY_VERBOSE === $output->getVerbosity()) {
$output->writeln("<info>The file $filename contains valid YAML.</info>");
}
return 0;
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace Grasmash\YamlCli\Command;
use Dflydev\DotAccessData\Data;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class CreateProjectCommand
*
* @package Grasmash\YamlCli\Command
*/
class UnsetKeyCommand extends CommandBase
{
/**
* {inheritdoc}
*/
protected function configure()
{
$this
->setName('unset:key')
->setDescription('Unset a specific key in a YAML file.')
->addUsage("path/to/file.yml")
->addArgument(
'filename',
InputArgument::REQUIRED,
"The filename of the YAML file"
)
->addArgument(
'key',
InputArgument::REQUIRED,
"The key to unset, in dot notation"
);
}
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$filename = $input->getArgument('filename');
$key = $input->getArgument('key');
$yaml_parsed = $this->loadYamlFile($filename);
if (!$yaml_parsed) {
// Exit with a status of 1.
return 1;
}
$data = new Data($yaml_parsed);
if (!$this->checkKeyExists($data, $key)) {
$this->output->writeln("<error>The key '$key' does not exist in $filename.</error>");
return 1;
}
$data->remove($key);
if ($this->writeYamlFile($filename, $data)) {
$this->output->writeln("<info>The key '$key' was removed from $filename.</info>");
return 0;
}
return 1;
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace Grasmash\YamlCli\Command;
use Dflydev\DotAccessData\Data;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class CreateProjectCommand
*
* @package Grasmash\YamlCli\Command
*/
class UpdateKeyCommand extends CommandBase
{
/**
* {inheritdoc}
*/
protected function configure()
{
$this
->setName('update:key')
->setDescription('Update a specific key in a YAML file.')
->addUsage("path/to/file.yml example.key example.new-key")
->addArgument(
'filename',
InputArgument::REQUIRED,
"The filename of the YAML file"
)
->addArgument(
'key',
InputArgument::REQUIRED,
"The original key, in dot notation"
)
->addArgument(
'new-key',
InputArgument::REQUIRED,
"The new key, in dot notation"
);
}
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$filename = $input->getArgument('filename');
$key = $input->getArgument('key');
$new_key = $input->getArgument('new-key');
$yaml_parsed = $this->loadYamlFile($filename);
if (!$yaml_parsed) {
// Exit with a status of 1.
return 1;
}
$data = new Data($yaml_parsed);
if (!$this->checkKeyExists($data, $key)) {
$this->output->writeln("<error>The key '$key' does not exist in $filename.</error>");
return 1;
}
$value = $data->get($key);
$data->set($new_key, $value);
$data->remove($key);
if ($this->writeYamlFile($filename, $data)) {
$this->output->writeln("<info>The key '$key' was changed to '$new_key' in $filename.</info>");
return 0;
}
return 1;
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Grasmash\YamlCli\Command;
use Dflydev\DotAccessData\Data;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class CreateProjectCommand
*
* @package Grasmash\YamlCli\Command
*/
class UpdateValueCommand extends CommandBase
{
/**
* {inheritdoc}
*/
protected function configure()
{
$this
->setName('update:value')
->setDescription('Update the value for a specific key in a YAML file.')
->addUsage("path/to/file.yml example.key 'new value for example.key'")
->addArgument(
'filename',
InputArgument::REQUIRED,
"The filename of the YAML file"
)
->addArgument(
'key',
InputArgument::REQUIRED,
"The key for the value to set, in dot notation"
)
->addArgument(
'value',
InputArgument::REQUIRED,
"The new value"
)
->addOption('type', 't', InputOption::VALUE_REQUIRED, 'Set the variable type for the value. Accepted types are int, integer, bool, boolean, str, and string.');
}
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return int 0 if everything went fine, or an exit code
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$filename = $input->getArgument('filename');
$key = $input->getArgument('key');
$raw_value = $input->getArgument('value');
$yaml_parsed = $this->loadYamlFile($filename);
if ($yaml_parsed === false) {
// Exit with a status of 1.
return 1;
}
$data = new Data($yaml_parsed);
$value = $raw_value;
if ($type = $input->getOption('type')) {
$value = match ($type) {
'int', 'integer' => (int) $raw_value,
'bool', 'boolean' => (bool) $raw_value,
'float', 'double', 'real' => (float) $raw_value,
'str', 'string' => (string) $raw_value,
'null' => null,
default => throw new RuntimeException('The option type must have a value of int, integer, bool, or boolean.'),
};
} elseif (strtolower($value) === 'false') {
$value = false;
} elseif (strtolower($value) === 'true') {
$value = true;
} elseif (strtolower($value) === 'null') {
$value = null;
}
$data->set($key, $value);
if ($this->writeYamlFile($filename, $data)) {
$this->output->writeln("<info>The value for key '$key' was set to '$raw_value' (" . gettype($value) . ") in $filename.</info>");
return 0;
}
return 1;
}
}

View File

@@ -0,0 +1,6 @@
# This file contains invalid YAML.
- test:
something: {
}
else: this

View File

@@ -0,0 +1,13 @@
deep-array:
second:
third:
fourth: hello world
flat-array:
- one
- two
- three
null-value: ~
inline-array: [ one, two, three ]
bool-value: true
int-value: 1
float-value: 1.0

View File

@@ -0,0 +1,39 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Grasmash\YamlCli\Tests\TestBase;
class ApplicationTest extends TestBase
{
/**
* Tests that all expected commands are available in the application.
*
* @dataProvider getValueProvider
*/
public function testApplication($expected)
{
$bin = realpath(__DIR__ . '/../../../bin/yaml-cli');
$output = shell_exec("$bin list");
$this->assertStringContainsString($expected, $output);
}
/**
* Provides values to testApplication().
*
* @return array
* An array of values to test.
*/
public function getValueProvider(): array
{
return [
['get:value'],
['get:type'],
['lint'],
['unset:key'],
['update:key'],
['update:value'],
];
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Grasmash\YamlCli\Command\GetTypeCommand;
use Grasmash\YamlCli\Tests\TestBase;
use Symfony\Component\Console\Tester\CommandTester;
class GetTypeCommandTest extends TestBase
{
/**
* Tests the 'get:value' command.
*
* @dataProvider getValueProvider
*/
public function testGetValue($file, $key, $expected_output, $expected_exit_code)
{
$this->application->add(new GetTypeCommand());
$command = $this->application->find('get:type');
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'filename' => $file,
'key' => $key,
]);
$output = $commandTester->getDisplay();
$this->assertStringContainsString($expected_output, $output);
$this->assertEquals($expected_exit_code, $commandTester->getStatusCode());
}
/**
* Provides values to testGetValue().
*
* @return array
* An array of values to test.
*/
public function getValueProvider()
{
$file = 'tests/resources/good.yml';
return [
[$file, 'not-real', "The key not-real does not exist.", 1],
[
'missing.yml',
'not-real',
"The file missing.yml does not exist.",
1,
],
[$file, 'deep-array.second.third.fourth', 'string', 0],
[$file, 'flat-array', 'array', 0],
[$file, 'inline-array', 'array', 0],
[$file, 'null-value', 'NULL', 0],
[$file, 'bool-value', 'boolean', 0],
[$file, 'int-value', 'integer', 0],
[$file, 'float-value', 'double', 0],
];
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Grasmash\YamlCli\Command\GetValueCommand;
use Grasmash\YamlCli\Tests\TestBase;
use Symfony\Component\Console\Tester\CommandTester;
class GetValueCommandTest extends TestBase
{
/**
* Tests the 'get:value' command.
*
* @dataProvider getValueProvider
*/
public function testGetValue($file, $key, $expected_output, $expected_exit_code)
{
$this->application->add(new GetValueCommand());
$command = $this->application->find('get:value');
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'filename' => $file,
'key' => $key,
]);
$output = $commandTester->getDisplay();
$this->assertStringContainsString($expected_output, $output);
$this->assertEquals($expected_exit_code, $commandTester->getStatusCode());
}
/**
* Provides values to testGetValue().
*
* @return array
* An array of values to test.
*/
public function getValueProvider()
{
$file = 'tests/resources/good.yml';
return [
[$file, 'not-real', "The key not-real does not exist.", 1],
[
'missing.yml',
'not-real',
"The file missing.yml does not exist.",
1,
],
[$file, 'deep-array.second.third.fourth', 'hello world', 0],
[
$file,
'flat-array',
'- one
- two
- three',
0,
],
[
$file,
'inline-array',
'- one
- two
- three',
0,
],
];
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Grasmash\YamlCli\Command\LintCommand;
use Grasmash\YamlCli\Tests\TestBase;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Tester\CommandTester;
class LintCommandTest extends TestBase
{
/**
* Tests the 'lint' command.
*
* @dataProvider getValueProvider
*/
public function testLint($file, $expected_output, $expected_exit_code)
{
$this->application->add(new LintCommand());
$command = $this->application->find('lint');
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'filename' => $file,
], ['verbosity' => Output::VERBOSITY_VERBOSE]);
$output = $commandTester->getDisplay();
$this->assertStringContainsString($expected_output, $output);
$this->assertEquals($expected_exit_code, $commandTester->getStatusCode());
}
/**
* Provides values to testLint().
*
* @return array
* An array of values to test.
*/
public function getValueProvider()
{
return [
[
'tests/resources/good.yml',
"The file tests/resources/good.yml contains valid YAML.",
0,
],
[
'tests/resources/bad.yml',
"There was an error parsing tests/resources/bad.yml. The contents are not valid YAML.",
1,
],
['missing.yml', "The file missing.yml does not exist.", 1],
];
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Dflydev\DotAccessData\Data;
use Grasmash\YamlCli\Command\UnsetKeyCommand;
use Grasmash\YamlCli\Tests\TestBase;
use Symfony\Component\Console\Tester\CommandTester;
class UnsetKeyCommandTest extends TestBase
{
/** @var string */
protected $temp_file;
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
parent::setUp();
$this->setupTemporaryConfigFiles();
}
/**
* Tests the 'unset:key' command.
*
* @dataProvider getValueProvider
*/
public function testUnsetKey($filename, $key, $expected_output, $expected_exit_code)
{
$commandTester = $this->runCommand($filename, $key);
$output = $commandTester->getDisplay();
$this->assertStringContainsString($expected_output, $output);
$contents = $this->getCommand()->loadYamlFile($filename);
$data = new Data($contents);
$this->assertNotTrue($data->has($key), "The file $filename contains the old key $key. It should not.");
$this->assertEquals($expected_exit_code, $commandTester->getStatusCode());
}
/**
* Tests that passing a missing file outputs expected error.
*/
public function testMissingFile()
{
$commandTester = $this->runCommand('missing.yml', 'not-real');
$this->assertStringContainsString("The file missing.yml does not exist.", $commandTester->getDisplay());
}
/**
* Gets the unset:key command.
*
* @return UnsetKeyCommand
*/
protected function getCommand()
{
$this->application->add(new UnsetKeyCommand());
$command = $this->application->find('unset:key');
return $command;
}
/**
* Runs the unset:key command.
*
* @param string $filename
* The filename.
* @param string $key
* The key to unset.
*
* @return \Symfony\Component\Console\Tester\CommandTester
*/
protected function runCommand($filename, $key)
{
$command = $this->getCommand();
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'filename' => $filename,
'key' => $key,
]);
return $commandTester;
}
/**
* Provides values to testUnsetKey().
*
* @return array
* An array of values to test.
*/
public function getValueProvider()
{
$filename = 'tests/resources/temp.yml';
return [
[
$filename,
'deep-array.second.third.fourth',
"The key 'deep-array.second.third.fourth' was removed from $filename.",
0,
],
[
$filename,
'flat-array.0',
"The key 'flat-array.0' was removed from $filename.",
0,
],
[
$filename,
'inline-array.0',
"The key 'inline-array.0' was removed from $filename.",
0,
],
[
$filename,
'null-value',
"The key 'null-value' was removed from $filename.",
0,
],
[
$filename,
'fake-value',
"The key 'fake-value' does not exist in $filename.",
1,
],
];
}
}

View File

@@ -0,0 +1,144 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Dflydev\DotAccessData\Data;
use Grasmash\YamlCli\Command\UpdateKeyCommand;
use Grasmash\YamlCli\Tests\TestBase;
use Symfony\Component\Console\Tester\CommandTester;
class UpdateKeyCommandTest extends TestBase
{
/** @var string */
protected $temp_file;
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
parent::setUp();
$this->setupTemporaryConfigFiles();
}
/**
* Tests the 'update:key' command.
*
* @dataProvider getValueProvider
*/
public function testUpdateKey($file, $key, $new_key, $expected_output, $expected_exit_code)
{
$contents = $this->getCommand()->loadYamlFile($file);
$data = new Data($contents);
$value = $data->get($key, null);
$commandTester = $this->runCommand($file, $key, $new_key);
$output = $commandTester->getDisplay();
$this->assertStringContainsString($expected_output, $output);
$this->assertEquals($expected_exit_code, $commandTester->getStatusCode());
// If we expected the command to be successful, test the file contents.
if (!$expected_exit_code) {
$contents = $this->getCommand()->loadYamlFile($file);
$data = new Data($contents);
$this->assertTrue($data->has($new_key), "The file $file does not contain the new key $new_key. It should.");
$this->assertNotTrue($data->has($key), "The file $file contains the old key $key. It should not.");
$this->assertEquals(
$value,
$data->get($new_key),
"The value of key $new_key does not equal the value of the original key $key"
);
}
}
/**
* Tests that passing a missing file outputs expected error.
*/
public function testMissingFile()
{
$commandTester = $this->runCommand('missing.yml', 'not-real', 'still-not-real');
$this->assertStringContainsString("The file missing.yml does not exist.", $commandTester->getDisplay());
}
/**
* Gets the update:key command.
*
* @return UpdateKeyCommand
*/
protected function getCommand()
{
$this->application->add(new UpdateKeyCommand());
$command = $this->application->find('update:key');
return $command;
}
/**
* Runs the update:key command.
*
* @param string $file
* The filename.
* @param string $key
* The original key.
* @param string $new_key
* The new key.
*
* @return \Symfony\Component\Console\Tester\CommandTester
*/
protected function runCommand($file, $key, $new_key)
{
$command = $this->getCommand();
$commandTester = new CommandTester($command);
$commandTester->execute([
'command' => $command->getName(),
'filename' => $file,
'key' => $key,
'new-key' => $new_key,
]);
return $commandTester;
}
/**
* Provides values to testUpdateKey().
*
* @return array
* An array of values to test.
*/
public function getValueProvider()
{
$file = 'tests/resources/temp.yml';
return [
[
$file,
'deep-array.second.third.fourth',
'deep-array.second.third.fifth',
"The key 'deep-array.second.third.fourth' was changed to 'deep-array.second.third.fifth' in $file.",
0,
],
[
$file,
'flat-array.0',
'flat-array.10',
"The key 'flat-array.0' was changed to 'flat-array.10' in $file.",
0,
],
[
$file,
'inline-array.0',
'inline-array.10',
"The key 'inline-array.0' was changed to 'inline-array.10' in $file.",
0,
],
[
$file,
'fake-key',
'new-key',
"The key 'fake-key' does not exist in $file.",
1,
],
];
}
}

View File

@@ -0,0 +1,269 @@
<?php
namespace Grasmash\YamlCli\Tests\Command;
use Dflydev\DotAccessData\Data;
use Grasmash\YamlCli\Command\UpdateValueCommand;
use Grasmash\YamlCli\Tests\TestBase;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
class UpdateValueCommandTest extends TestBase
{
/** @var string */
protected $temp_file;
/**
* {@inheritdoc}
*/
protected function setUp(): void
{
parent::setUp();
$this->setupTemporaryConfigFiles();
}
/**
* Tests the 'update:value' command.
*
* @dataProvider getValueProvider
*/
public function testUpdateValue($file, $key, $value, $type, $expected_value, $expected_output, $expected_exit_code)
{
$commandTester = $this->runCommand($file, $key, $value, $type);
$output = $commandTester->getDisplay();
$this->assertStringContainsString($expected_output, $output);
$contents = $this->getCommand()->loadYamlFile($file);
$data = new Data($contents);
$this->assertEquals($expected_value, $data->get($key));
$this->assertEquals($expected_exit_code, $commandTester->getStatusCode());
}
/**
* Tests that passing a missing file outputs expected error.
*/
public function testMissingFile()
{
$commandTester = $this->runCommand('missing.yml', 'not-real', 'still-not-real', null);
$this->assertStringContainsString("The file missing.yml does not exist.", $commandTester->getDisplay());
}
/**
* Gets the update:value command.
*
* @return \Symfony\Component\Console\Command\Command
*/
protected function getCommand(): Command
{
$this->application->add(new UpdateValueCommand());
return $this->application->find('update:value');
}
/**
* Runs the update:value commnd.
*
* @param string $file
* The filename.
* @param string $key
* The key for which to update the value.
* @param string $value
* The new value.
* @param string $type
*
* @return \Symfony\Component\Console\Tester\CommandTester
*/
protected function runCommand(string $file, string $key, string $value, $type): CommandTester
{
$command = $this->getCommand();
$commandTester = new CommandTester($command);
$params = [
'command' => $command->getName(),
'filename' => $file,
'key' => $key,
'value' => $value,
];
if ($type) {
$params['--type'] = $type;
}
$commandTester->execute($params);
return $commandTester;
}
/**
* Provides values to testUpdateValue().
*
* @return array
* An array of values to test.
*/
public function getValueProvider(): array
{
$file = 'tests/resources/temp.yml';
return [
[
$file,
'deep-array.second.third.fourth',
'goodbye world',
null,
'goodbye world',
"The value for key 'deep-array.second.third.fourth' was set to 'goodbye world' (string) in $file.",
0,
],
[
$file,
'flat-array.0',
'goodbye world',
null,
'goodbye world',
"The value for key 'flat-array.0' was set to 'goodbye world' (string) in $file.",
0,
],
[
$file,
'inline-array.0',
'goodbye world',
null,
'goodbye world',
"The value for key 'inline-array.0' was set to 'goodbye world' (string) in $file.",
0,
],
[
$file,
'new-key.sub-key',
'hello world',
null,
'hello world',
"The value for key 'new-key.sub-key' was set to 'hello world' (string) in $file.",
0,
],
[
$file,
'integer.0',
'0',
'int',
0,
"The value for key 'integer.0' was set to '0' (integer) in $file.",
0,
],
[
$file,
'integer.1',
'1',
'integer',
1,
"The value for key 'integer.1' was set to '1' (integer) in $file.",
0,
],
[
$file,
'boolean.0',
'false',
null,
false,
"The value for key 'boolean.0' was set to 'false' (boolean) in $file.",
0,
],
[
$file,
'boolean.1',
'true',
null,
true,
"The value for key 'boolean.1' was set to 'true' (boolean) in $file.",
0,
],
[
$file,
'boolean.0',
'0',
'bool',
false,
"The value for key 'boolean.0' was set to '0' (boolean) in $file.",
0,
],
[
$file,
'boolean.1',
'1',
'boolean',
true,
"The value for key 'boolean.1' was set to '1' (boolean) in $file.",
0,
],
[
$file,
'string.0',
'false',
'string',
'false',
"The value for key 'string.0' was set to 'false' (string) in $file.",
0,
],
[
$file,
'string.1',
'true',
'string',
'true',
"The value for key 'string.1' was set to 'true' (string) in $file.",
0,
],
[
$file,
'string.2',
'null',
'string',
'null',
"The value for key 'string.2' was set to 'null' (string) in $file.",
0,
],
[
$file,
'null.0',
'null',
null,
null,
"The value for key 'null.0' was set to 'null' (NULL) in $file.",
0,
],
[
$file,
'null.0',
'~',
'null',
null,
"The value for key 'null.0' was set to '~' (NULL) in $file.",
0,
],
[
$file,
'float.0',
'1.0',
'float',
1.0,
"The value for key 'float.0' was set to '1.0' (double) in $file.",
0,
],
[
$file,
'float.1',
'1.0',
'double',
1.0,
"The value for key 'float.1' was set to '1.0' (double) in $file.",
0,
],
[
$file,
'float.2',
'1.0',
'real',
1.0,
"The value for key 'float.2' was set to '1.0' (double) in $file.",
0,
],
];
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace Grasmash\YamlCli\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
/**
* Class BltTestBase.
*
* Base class for all tests that are executed for BLT itself.
*/
abstract class TestBase extends TestCase
{
/** @var Application */
protected $application;
/** @var string */
protected $temp_file = '';
/**
* {@inheritdoc}
*
* @see https://symfony.com/doc/current/console.html#testing-commands
*/
protected function setUp(): void
{
parent::setUp();
$this->application = new Application();
}
/**
* Removes temporary file.
*/
protected function tearDown(): void
{
parent::tearDown();
// This will only exist if a test called setupTemporaryConfigFiles().
if ($this->temp_file && file_exists($this->temp_file)) {
unlink($this->temp_file);
}
}
/**
* Creates a temporary copy of a file and assigns it to $this->temp_file.
*
* @param string $source
* The filename of the source file.
* @param string $destination
* The filename of the destination file.
*
* @return bool
* TRUE if the file was created. Otherwise, FALSE.
*/
protected function createTemporaryFile($source, $destination)
{
$source_path = realpath($source);
if (file_exists($source_path)) {
copy($source_path, $destination);
$destination_path = realpath($destination);
$this->temp_file = $destination_path;
return true;
}
return false;
}
/**
* Creates a temporary copy of config files so that they can be modified.
*/
protected function setupTemporaryConfigFiles()
{
// Make a temporary copy of good.yml so that we can update a value
// without destroying the original.
$this->createTemporaryFile(__DIR__ . '/../resources/good.yml', __DIR__ . '/../resources/temp.yml');
}
}