Skip to content

Commit

Permalink
Config component
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrkreft committed Jun 11, 2020
0 parents commit b726861
Show file tree
Hide file tree
Showing 57 changed files with 3,234 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CI

on:
push:
branches: [ master ]

jobs:
ci:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
coverage: pcov

- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-suggest --prefer-stable

- name: PHPUnit with coverage
run: vendor/bin/phpunit --coverage-clover=build/logs/clover.xml tests

- name: Report coverage
run: vendor/bin/php-coveralls
env:
COVERALLS_RUN_LOCALLY: yes
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

- name: Infection mutations
run: vendor/bin/infection --show-mutations
env:
INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }}
32 changes: 32 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['7.2','7.3','7.4']
composer-opts: ['--prefer-lowest', '']

steps:
- uses: actions/checkout@v2

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}

- name: Validate dependencies
run: composer validate

- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-suggest ${{ matrix.composer-opts }} --prefer-stable

- name: Run test suite
run: composer test
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/vendor/
var/
.idea
composer.lock
.php_cs.cache
.phpunit.result.cache
.php-code-sniffer.cache
infection.log
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Config

![Tests](https://github.com/piotrkreft/config/workflows/Tests/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/piotrkreft/config/badge.svg?branch=master)](https://coveralls.io/github/piotrkreft/config?branch=master)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fpiotrkreft%2Fconfig%2Fmaster)](https://infection.github.io)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/piotrkreft/config/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/piotrkreft/config/?branch=master)

Component for fetching, merging, and validating configuration from various sources.

## Introduction
Whenever you have various environments for multiple purposes: production, staging, test, local and more
the need arises to keep the configuration of those consistent across possibly different platforms like
local environments and some external storage like AWS Simple Systems Manager and not to fail during critical deploy.

This component allows you to keep it tight in one source with a predefined yaml solution.

## Example
```php
use PK\Config\ConfigFactory;

$config = ConfigFactory::create(realpath('/configuration/config.yaml'));

$config->validate('dev');

$config->fetch('dev');
```

[example configuration](tests/Fixtures/Resources/config/config.yaml)

:information_source: Variables declared within envs scope take the precedence over global ones.

:information_source: Global variables can be disabled in specific env with the `disable` flag.

## Adapters
To be able to use different configuration sources adapters are needed.
By default package provides:

* aws_ssm (`PK\Config\StorageAdapter\AwsSsm`) - for AWS Simple Systems Manager parameters
* local_env (`PK\Config\StorageAdapter\LocalEnv`) - for local environment variables

and each of those is available to be instantiated via component configuration.

If needed a new adapter can be easily created. Just remember to interface it with `PK\Config\StorageAdapterInterface` and to instantiate it.

:information_source: Order of the adapters in each environment is also a priority. If the first adapter provides value, the following will be ignored.

## CLI
Validation of entries:
```bash
bin/pk-config -c tests/Fixtures/Resources/config/config.yaml validate dev
```

Displaying of entries:
```bash
bin/pk-config -c tests/Fixtures/Resources/config/config.yaml display dev
```

## Symfony Bundle
It's possible to use the component as a Symfony Bundle. Just make sure you have `symfony/http-kernel` installed.

If used as such commands will receive `pk:config:` (i.e. `pk:config:validate`) prefix.
15 changes: 15 additions & 0 deletions bin/pk-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

if (!file_exists($autoload = __DIR__ . '/../../autoload.php') && !file_exists($autoload = __DIR__ . '/../vendor/autoload.php')) {
exit('Dependencies should be installed via Composer!' . \PHP_EOL);
}

require $autoload;

$application = new \PK\Config\Console\Application(
new \PK\Config\DependencyInjection\ContainerFactory()
);
$application->run();
50 changes: 50 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "piotrkreft/config",
"type": "library",
"description": "Component for fetching, merging, and validating configuration from various sources",
"license": "MIT",
"authors": [
{
"name": "Piotr Kreft",
"email": "[email protected]"
}
],
"bin": ["bin/pk-config"],
"require": {
"php": ">=7.2.5",
"symfony/config": "^4.2|^5.0",
"symfony/console": "^3.4|^4.0|^5.0",
"symfony/dependency-injection": "^4.0|^5.0",
"symfony/yaml": "^4.0|^5.0",
"symfony/polyfill-php80": "^1.15"
},
"require-dev": {
"aws/aws-sdk-php": "^3.0",
"piotrkreft/ci": "^0.2",
"symfony/http-kernel": "^4.0|^5.0",
"symfony/framework-bundle": "^4.0|^5.0"
},
"suggest": {
"aws/aws-sdk-ph": "For using AWS System Manager configuration",
"symfony/http-kernel": "For using the component as Symfony Bundle"
},
"autoload": {
"psr-4": {
"PK\\Config\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"PK\\Tests\\Config\\": "tests/"
}
},
"minimum-stability": "dev",
"scripts": {
"test": [
"vendor/bin/pk-tests --cache-dir=. run"
],
"fix": [
"vendor/bin/pk-tests --cache-dir=. fix"
]
}
}
13 changes: 13 additions & 0 deletions infection.json.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"source": {
"directories": [
"src"
]
},
"logs": {
"text": "infection.log",
"badge": {
"branch": "master"
}
}
}
20 changes: 20 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true"
>

<testsuites>
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>

<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
55 changes: 55 additions & 0 deletions src/Command/DisplayCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace PK\Config\Command;

use PK\Config\ConfigInterface;
use PK\Config\Exception\ExceptionInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class DisplayCommand extends Command
{
/**
* @var ConfigInterface
*/
private $config;

public function __construct(ConfigInterface $config, ?string $name = null)
{
parent::__construct($name);
$this->config = $config;
}

protected function configure(): void
{
$this
->setDescription('Displays configuration entries.')
->addArgument('env', InputArgument::OPTIONAL, 'Environment for fetching');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
if (!$env = $input->getArgument('env')) {
$output->writeln('<error>env argument missing</error>');

return 1;
}
try {
$entries = $this->config->fetch($env);
} catch (ExceptionInterface $exception) {
$output->writeln("<error>{$exception->getMessage()}</error>");

return 2;
}

foreach ($entries as $entry) {
$output->writeln("<info>{$entry->getName()}</info> {$entry->getValue()}");
}

return 0;
}
}
62 changes: 62 additions & 0 deletions src/Command/ValidateCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace PK\Config\Command;

use PK\Config\ConfigInterface;
use PK\Config\Exception\ExceptionInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ValidateCommand extends Command
{
/**
* @var ConfigInterface
*/
private $config;

public function __construct(ConfigInterface $config, ?string $name = null)
{
parent::__construct($name);
$this->config = $config;
}

protected function configure(): void
{
$this
->setDescription('Validates configuration entries.')
->addArgument('env', InputArgument::OPTIONAL, 'Environment for validation');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
if (!$env = $input->getArgument('env')) {
$output->writeln('<error>env argument missing</error>');

return 1;
}
try {
$invalid = $this->config->validate($env);
} catch (ExceptionInterface $exception) {
$output->writeln("<error>{$exception->getMessage()}</error>");

return 2;
}

if (empty($invalid)) {
$output->writeln('<info>Configuration valid</info>');

return 0;
}

$output->writeln('<error>Following variables missing:</error>');
foreach ($invalid as $variable) {
$output->writeln($variable);
}

return 3;
}
}
Loading

0 comments on commit b726861

Please sign in to comment.