Verified Commit 82477805 authored by Elias Häußler's avatar Elias Häußler 🐛
Browse files

[!!!][FEATURE] Streamline service configuration resolving

parent 4007ca7b
<?php
declare(strict_types=1);
namespace EliasHaeussler\ComposerUpdateReporter\Exception;
/*
* This file is part of the Composer package "eliashaeussler/composer-update-reporter".
*
* Copyright (C) 2021 Elias Häußler <elias@haeussler.dev>
*
* 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/>.
*/
/**
* MissingConfigurationException.
*
* @author Elias Häußler <elias@haeussler.dev>
* @license GPL-3.0-or-later
*/
class MissingConfigurationException extends \Exception
{
public static function create(string $serviceIdentifier, string $key): self
{
return new self(
sprintf('Configuration "%s" is missing for service "%s".', $key, $serviceIdentifier),
1617805421
);
}
}
......@@ -29,6 +29,7 @@ use EliasHaeussler\ComposerUpdateCheck\IO\Style;
use EliasHaeussler\ComposerUpdateCheck\IO\Verbosity;
use EliasHaeussler\ComposerUpdateCheck\Options;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Traits\ServiceConfigurationTrait;
use Spatie\Emoji\Emoji;
use Spatie\Emoji\Exceptions\UnknownCharacter;
......@@ -40,6 +41,8 @@ use Spatie\Emoji\Exceptions\UnknownCharacter;
*/
abstract class AbstractService implements ServiceInterface
{
use ServiceConfigurationTrait;
/**
* @var OutputBehavior
*/
......
......@@ -79,41 +79,14 @@ class Email extends AbstractService
public static function fromConfiguration(array $configuration): ServiceInterface
{
$extra = $configuration['email'] ?? null;
// Parse Email DSN
if (is_array($extra) && array_key_exists('dsn', $extra)) {
$dsn = (string) $extra['dsn'];
} elseif (false !== getenv('EMAIL_DSN')) {
$dsn = getenv('EMAIL_DSN');
} else {
throw new \RuntimeException('Email DSN is not defined. Define it either in composer.json or as $EMAIL_DSN.', 1601391909);
}
// Parse Email receivers
if (is_array($extra) && array_key_exists('receivers', $extra)) {
$receivers = explode(',', (string) $extra['receivers']);
} elseif (false !== getenv('EMAIL_RECEIVERS')) {
$receivers = explode(',', getenv('EMAIL_RECEIVERS'));
} else {
throw new \RuntimeException('Email receivers are not defined. Define it either in composer.json or as $EMAIL_RECEIVERS.', 1601391943);
}
// Parse Email sender
if (is_array($extra) && array_key_exists('sender', $extra)) {
$sender = (string) $extra['sender'];
} elseif (false !== getenv('EMAIL_SENDER')) {
$sender = getenv('EMAIL_SENDER');
} else {
throw new \RuntimeException('Email sender is not defined. Define it either in composer.json or as $EMAIL_SENDER.', 1601391961);
}
$dsn = (string) static::resolveConfigurationKey($configuration, 'dsn');
$receivers = explode(',', (string) static::resolveConfigurationKey($configuration, 'receivers'));
$sender = (string) static::resolveConfigurationKey($configuration, 'sender');
return new self($dsn, array_map('trim', array_filter($receivers)), $sender);
}
/**
* {@inheritDoc}
*
* @throws TransportExceptionInterface
*/
protected function sendReport(UpdateCheckResult $result): bool
......
......@@ -76,32 +76,13 @@ class GitLab extends AbstractService
public static function fromConfiguration(array $configuration): ServiceInterface
{
$extra = $configuration['gitlab'] ?? null;
// Parse GitLab URL
if (is_array($extra) && array_key_exists('url', $extra)) {
$uri = new Uri((string) $extra['url']);
} elseif (false !== getenv('GITLAB_URL')) {
$uri = new Uri(getenv('GITLAB_URL'));
} else {
throw new \RuntimeException('GitLab URL is not defined. Define it either in composer.json or as $GITLAB_URL.', 1600852917);
}
// Parse GitLab authorization key
if (is_array($extra) && array_key_exists('authKey', $extra)) {
$authKey = (string) $extra['authKey'];
} elseif (false !== getenv('GITLAB_AUTH_KEY')) {
$authKey = getenv('GITLAB_AUTH_KEY');
} else {
throw new \RuntimeException('GitLab authorization key is not defined. Define it either in composer.json or as $GITLAB_AUTH_KEY.', 1600852990);
}
$uri = new Uri((string) static::resolveConfigurationKey($configuration, 'url'));
$authKey = (string) static::resolveConfigurationKey($configuration, 'authKey');
return new self($uri, $authKey);
}
/**
* {@inheritDoc}
*
* @throws ClientExceptionInterface
*/
protected function sendReport(UpdateCheckResult $result): bool
......
......@@ -82,40 +82,14 @@ class Mattermost extends AbstractService
public static function fromConfiguration(array $configuration): ServiceInterface
{
$extra = $configuration['mattermost'] ?? null;
// Parse Mattermost URL
if (is_array($extra) && array_key_exists('url', $extra)) {
$uri = new Uri((string) $extra['url']);
} elseif (false !== getenv('MATTERMOST_URL')) {
$uri = new Uri(getenv('MATTERMOST_URL'));
} else {
throw new \RuntimeException('Mattermost URL is not defined. Define it either in composer.json or as $MATTERMOST_URL.', 1600283681);
}
// Parse Mattermost channel name
if (is_array($extra) && array_key_exists('channel', $extra)) {
$channelName = (string) $extra['channel'];
} elseif (false !== getenv('MATTERMOST_CHANNEL')) {
$channelName = getenv('MATTERMOST_CHANNEL');
} else {
throw new \RuntimeException('Mattermost channel name is not defined. Define it either in composer.json or as $MATTERMOST_CHANNEL.', 1600284246);
}
// Parse Mattermost username
$username = null;
if (is_array($extra) && array_key_exists('username', $extra)) {
$username = (string) $extra['username'];
} elseif (false !== getenv('MATTERMOST_USERNAME')) {
$username = getenv('MATTERMOST_USERNAME');
}
$uri = new Uri((string) static::resolveConfigurationKey($configuration, 'url'));
$channelName = (string) static::resolveConfigurationKey($configuration, 'channel');
$username = (string) static::resolveConfigurationKey($configuration, 'username');
return new self($uri, $channelName, $username);
}
/**
* {@inheritDoc}
*
* @throws ClientExceptionInterface
*/
protected function sendReport(UpdateCheckResult $result): bool
......
......@@ -26,6 +26,7 @@ namespace EliasHaeussler\ComposerUpdateReporter\Service;
use EliasHaeussler\ComposerUpdateCheck\IO\OutputBehavior;
use EliasHaeussler\ComposerUpdateCheck\Options;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
/**
* ServiceInterface.
......@@ -39,6 +40,8 @@ interface ServiceInterface
/**
* @param array<string, mixed> $configuration
*
* @throws MissingConfigurationException
*/
public static function fromConfiguration(array $configuration): self;
......
......@@ -69,23 +69,12 @@ class Slack extends AbstractService
public static function fromConfiguration(array $configuration): ServiceInterface
{
$extra = $configuration['slack'] ?? null;
// Parse Slack URL
if (is_array($extra) && array_key_exists('url', $extra)) {
$uri = new Uri((string) $extra['url']);
} elseif (false !== getenv('SLACK_URL')) {
$uri = new Uri(getenv('SLACK_URL'));
} else {
throw new \RuntimeException('Slack URL is not defined. Define it either in composer.json or as $SLACK_URL.', 1602496964);
}
$uri = new Uri((string) static::resolveConfigurationKey($configuration, 'url'));
return new self($uri);
}
/**
* {@inheritDoc}
*
* @throws ClientExceptionInterface
*/
protected function sendReport(UpdateCheckResult $result): bool
......
......@@ -69,23 +69,12 @@ class Teams extends AbstractService
public static function fromConfiguration(array $configuration): ServiceInterface
{
$extra = $configuration['teams'] ?? null;
// Parse MS Teams URL
if (is_array($extra) && array_key_exists('url', $extra)) {
$uri = new Uri((string) $extra['url']);
} elseif (false !== getenv('TEAMS_URL')) {
$uri = new Uri(getenv('TEAMS_URL'));
} else {
throw new \RuntimeException('MS Teams URL is not defined. Define it either in composer.json or as $TEAMS_URL.', 1612865679);
}
$uri = new Uri((string) static::resolveConfigurationKey($configuration, 'url'));
return new self($uri);
}
/**
* {@inheritDoc}
*
* @throws ClientExceptionInterface
*/
protected function sendReport(UpdateCheckResult $result): bool
......
<?php
declare(strict_types=1);
namespace EliasHaeussler\ComposerUpdateReporter\Traits;
/*
* This file is part of the Composer package "eliashaeussler/composer-update-reporter".
*
* Copyright (C) 2021 Elias Häußler <elias@haeussler.dev>
*
* 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/>.
*/
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
use EliasHaeussler\ComposerUpdateReporter\Util;
/**
* ServiceConfigurationTrait.
*
* @author Elias Häußler <elias@haeussler.dev>
* @license GPL-3.0-or-later
*/
trait ServiceConfigurationTrait
{
/**
* @param array<string, mixed> $configuration
*
* @return mixed
*
* @throws MissingConfigurationException
*/
protected static function resolveConfigurationKey(array $configuration, string $key)
{
$serviceIdentifier = static::getIdentifier();
$serviceConfiguration = $configuration[$serviceIdentifier] ?? null;
if (is_array($serviceConfiguration) && isset($serviceConfiguration[$key])) {
return $serviceConfiguration[$key];
}
$underscoredKey = Util::camelCaseToUnderscored($key);
$envName = strtoupper($serviceIdentifier.'_'.$underscoredKey);
if (false !== getenv($envName)) {
return getenv($envName);
}
throw MissingConfigurationException::create($serviceIdentifier, $key);
}
}
......@@ -31,6 +31,11 @@ namespace EliasHaeussler\ComposerUpdateReporter;
*/
class Util
{
public static function camelCaseToUnderscored(string $string): string
{
return preg_replace('/(?<!^)([A-Z])/', '_$1', $string);
}
/**
* @param array<string, mixed> $array1
* @param array<string, mixed> $array2
......
......@@ -25,6 +25,7 @@ namespace EliasHaeussler\ComposerUpdateReporter\Tests\Unit\Service;
use EliasHaeussler\ComposerUpdateCheck\Package\OutdatedPackage;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
use EliasHaeussler\ComposerUpdateReporter\Service\Email;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\AbstractTestCase;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\OutputBehaviorTrait;
......@@ -151,8 +152,8 @@ class EmailTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('EMAIL_DSN');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1601391909);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
Email::fromConfiguration($configuration);
}
......@@ -164,8 +165,8 @@ class EmailTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('EMAIL_RECEIVERS');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1601391943);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
$configuration = [
'email' => [
......@@ -182,8 +183,8 @@ class EmailTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('EMAIL_SENDER');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1601391961);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
$configuration = [
'email' => [
......@@ -196,6 +197,8 @@ class EmailTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromComposerJson(): void
{
......@@ -229,6 +232,8 @@ class EmailTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromEnvironmentVariables(): void
{
......
......@@ -25,6 +25,7 @@ namespace EliasHaeussler\ComposerUpdateReporter\Tests\Unit\Service;
use EliasHaeussler\ComposerUpdateCheck\Package\OutdatedPackage;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
use EliasHaeussler\ComposerUpdateReporter\Service\GitLab;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\AbstractTestCase;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\ClientMockTrait;
......@@ -99,8 +100,8 @@ class GitLabTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('GITLAB_URL');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1600852917);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
GitLab::fromConfiguration($configuration);
}
......@@ -112,8 +113,8 @@ class GitLabTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('GITLAB_AUTH_KEY');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1600852990);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
$configuration = [
'gitlab' => [
......@@ -125,6 +126,8 @@ class GitLabTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromComposerJson(): void
{
......@@ -147,6 +150,8 @@ class GitLabTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromEnvironmentVariables(): void
{
......
......@@ -25,6 +25,7 @@ namespace EliasHaeussler\ComposerUpdateReporter\Tests\Unit\Service;
use EliasHaeussler\ComposerUpdateCheck\Package\OutdatedPackage;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
use EliasHaeussler\ComposerUpdateReporter\Service\Mattermost;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\AbstractTestCase;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\ClientMockTrait;
......@@ -99,8 +100,8 @@ class MattermostTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('MATTERMOST_URL');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1600283681);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
Mattermost::fromConfiguration($configuration);
}
......@@ -112,8 +113,8 @@ class MattermostTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('MATTERMOST_CHANNEL');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1600284246);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
$configuration = [
'mattermost' => [
......@@ -125,6 +126,8 @@ class MattermostTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromComposerJson(): void
{
......@@ -150,6 +153,8 @@ class MattermostTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromEnvironmentVariables(): void
{
......
......@@ -25,6 +25,7 @@ namespace EliasHaeussler\ComposerUpdateReporter\Tests\Unit\Service;
use EliasHaeussler\ComposerUpdateCheck\Package\OutdatedPackage;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
use EliasHaeussler\ComposerUpdateReporter\Service\Slack;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\AbstractTestCase;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\ClientMockTrait;
......@@ -88,14 +89,16 @@ class SlackTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('SLACK_URL');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1602496964);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
Slack::fromConfiguration($configuration);
}
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromComposerJson(): void
{
......@@ -115,6 +118,8 @@ class SlackTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromEnvironmentVariables(): void
{
......
......@@ -25,6 +25,7 @@ namespace EliasHaeussler\ComposerUpdateReporter\Tests\Unit\Service;
use EliasHaeussler\ComposerUpdateCheck\Package\OutdatedPackage;
use EliasHaeussler\ComposerUpdateCheck\Package\UpdateCheckResult;
use EliasHaeussler\ComposerUpdateReporter\Exception\MissingConfigurationException;
use EliasHaeussler\ComposerUpdateReporter\Service\Teams;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\AbstractTestCase;
use EliasHaeussler\ComposerUpdateReporter\Tests\Unit\ClientMockTrait;
......@@ -89,14 +90,16 @@ class TeamsTest extends AbstractTestCase
{
$this->modifyEnvironmentVariable('TEAMS_URL');
$this->expectException(\RuntimeException::class);
$this->expectExceptionCode(1612865679);
$this->expectException(MissingConfigurationException::class);
$this->expectExceptionCode(1617805421);
Teams::fromConfiguration($configuration);
}
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromComposerJson(): void
{
......@@ -116,6 +119,8 @@ class TeamsTest extends AbstractTestCase
/**
* @test
*
* @throws MissingConfigurationException
*/
public function fromConfigurationReadsConfigurationFromEnvironmentVariables(): void
{
......
......@@ -33,6 +33,15 @@ use EliasHaeussler\ComposerUpdateReporter\Util;
*/
class UtilTest extends AbstractTestCase
{
/**
* @test
* @dataProvider uppercaseToUnderscoredReturnsUnderscoredStringDataProvider
*/
public function uppercaseToUnderscoredReturnsUnderscoredString(string $string, string $expected): void
{
static::assertSame($expected, Util::camelCaseToUnderscored($string));
}
/**
* @test
* @dataProvider arrayDiffRecursiveReturnsDiffBetweenArraysDataProvider
......@@ -46,6 +55,27 @@ class UtilTest extends AbstractTestCase
static::assertSame($expected, Util::arrayDiffRecursive($array1, $array2));
}
/**
* @return array<string, array>
*/
public function uppercaseToUnderscoredReturnsUnderscoredStringDataProvider(): array
{
return [
'only lowercase' => [
'foo',
'foo',
],
'only uppercase' => [
'FOO',
'F_O_O',
],
'camel case' => [
'FooBaz',
'Foo_Baz',
],
];
}
/**
* @return array<string, array>
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment