Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ services:
EliasHaeussler\ComposerUpdateCheck\:
resource: '../src/*'
exclude:
- '../src/Configuration/*'
- '../src/Config/*'
- '../src/DependencyInjection/*'
- '../src/Entity/*'
- '../src/Event/*'
- '../src/Exception/*'
- '../src/Helper/*'
- '../src/Plugin.php'

# Synthetic services (set when the container is built on runtime)
Expand Down
4 changes: 2 additions & 2 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ parameters:
path: src/Composer/Installer.php

-
message: "#^Parameter \\#1 \\.\\.\\.\\$constructors of method CuyZ\\\\Valinor\\\\MapperBuilder\\:\\:registerConstructor\\(\\) expects \\(pure\\-callable\\(\\)\\: mixed\\)\\|class\\-string, Closure\\(string\\)\\: EliasHaeussler\\\\ComposerUpdateCheck\\\\Configuration\\\\Options\\\\PackageExcludePattern given\\.$#"
message: "#^Variable property access on \\$this\\(EliasHaeussler\\\\ComposerUpdateCheck\\\\Config\\\\ComposerUpdateCheckConfig\\)\\.$#"
count: 1
path: src/Configuration/Adapter/FileBasedConfigAdapter.php
path: src/Config/ComposerUpdateCheckConfig.php
56 changes: 40 additions & 16 deletions src/Command/UpdateCheckCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@

use Composer\Command;
use CuyZ\Valinor;
use EliasHaeussler\ComposerUpdateCheck\Configuration;
use EliasHaeussler\ComposerUpdateCheck\Config;
use EliasHaeussler\ComposerUpdateCheck\Exception;
use EliasHaeussler\ComposerUpdateCheck\Helper;
use EliasHaeussler\ComposerUpdateCheck\IO;
use EliasHaeussler\ComposerUpdateCheck\UpdateChecker;
use Symfony\Component\Console;
use Symfony\Component\DependencyInjection;
use Symfony\Component\Filesystem;

use function array_map;
use function array_unshift;
Expand Down Expand Up @@ -64,7 +66,7 @@ protected function configure(): void
'Path to configuration file, can be in JSON, PHP oder YAML format',
);
$this->addOption(
'exclude-packages',
'exclude',
'e',
Console\Input\InputOption::VALUE_REQUIRED | Console\Input\InputOption::VALUE_IS_ARRAY,
'Packages to exclude when checking for available updates',
Expand All @@ -86,6 +88,7 @@ protected function configure(): void
'f',
Console\Input\InputOption::VALUE_REQUIRED,
'Format to display update check results',
IO\Formatter\TextFormatter::FORMAT,
);
$this->addOption(
'reporter',
Expand All @@ -109,8 +112,8 @@ protected function initialize(Console\Input\InputInterface $input, Console\Outpu
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
{
try {
$config = $this->resolveConfiguration($input);
} catch (Exception\ConfigFileIsInvalid $exception) {
$config = $this->resolveConfig($input);
} catch (Exception\ConfigFileIsInvalid|Exception\ConfigFileIsMissing|Exception\ConfigFileIsNotSupported $exception) {
$this->displayConfigError($exception);

return self::FAILURE;
Expand All @@ -127,26 +130,47 @@ protected function execute(Console\Input\InputInterface $input, Console\Output\O
return self::SUCCESS;
}

private function resolveConfiguration(Console\Input\InputInterface $input): Configuration\ComposerUpdateCheckConfig
/**
* @throws Exception\ConfigFileHasErrors
* @throws Exception\ConfigFileIsInvalid
* @throws Exception\ConfigFileIsMissing
* @throws Exception\ConfigFileIsNotSupported
*/
private function resolveConfig(Console\Input\InputInterface $input): Config\ComposerUpdateCheckConfig
{
$filename = $input->getOption('config');
$adapters = [
new Configuration\Adapter\CommandInputConfigAdapter($input),
new Configuration\Adapter\EnvironmentVariablesConfigAdapter(),
$configFile = $input->getOption('config');
$configFileFromEnv = getenv('COMPOSER_UPDATE_CHECK_CONFIG');
$configAdapters = [
new Config\Adapter\ConsoleInputConfigAdapter($input),
new Config\Adapter\EnvironmentVariablesConfigAdapter(),
];

if (null !== $filename && '' !== $filename) {
$configAdapterFactory = new Configuration\Adapter\ConfigAdapterFactory();

array_unshift($adapters, $configAdapterFactory->make($filename));
if (false !== $configFileFromEnv) {
array_unshift($configAdapters, $this->loadConfigFromFile($configFileFromEnv));
}
if (null !== $configFile) {
array_unshift($configAdapters, $this->loadConfigFromFile($configFile));
}

$configAdapter = new Configuration\Adapter\ChainedConfigAdapter($adapters);
return (new Config\Adapter\CompositeConfigAdapter($configAdapters))->get();
}

return $configAdapter->resolve();
/**
* @throws Exception\ConfigFileIsNotSupported
*/
private function loadConfigFromFile(string $configFile): Config\Adapter\ConfigAdapter
{
$configFile = Helper\FilesystemHelper::resolveRelativePath($configFile);
$extension = Filesystem\Path::getExtension($configFile, true);

return match ($extension) {
'php' => new Config\Adapter\PhpConfigAdapter($configFile),
'json', 'yaml', 'yml' => new Config\Adapter\FileConfigAdapter($configFile),
default => throw new Exception\ConfigFileIsNotSupported($configFile),
};
}

private function displayConfigError(Exception\ConfigFileIsInvalid $exception): void
private function displayConfigError(Exception\Exception $exception): void
{
$this->io->error($exception->getMessage());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,40 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace EliasHaeussler\ComposerUpdateCheck\Configuration\Adapter;
namespace EliasHaeussler\ComposerUpdateCheck\Config\Adapter;

use CuyZ\Valinor;
use EliasHaeussler\ComposerUpdateCheck\Configuration;
use EliasHaeussler\ComposerUpdateCheck\Exception;
use Symfony\Component\Yaml;
use EliasHaeussler\ComposerUpdateCheck\Config;

use function is_iterable;
use function count;

/**
* YamlConfigAdapter.
* CompositeConfigAdapter.
*
* @author Elias Häußler <elias@haeussler.dev>
* @license GPL-3.0-or-later
*/
final class YamlConfigAdapter extends FileBasedConfigAdapter
final class CompositeConfigAdapter implements ConfigAdapter
{
/**
* @throws Exception\ConfigFileHasErrors
* @throws Exception\ConfigFileIsInvalid
* @param list<ConfigAdapter> $adapters
*/
public function resolve(): Configuration\ComposerUpdateCheckConfig
public function __construct(
private readonly array $adapters,
) {}

public function get(): Config\ComposerUpdateCheckConfig
{
$yaml = Yaml\Yaml::parseFile($this->filename);
$config = new Config\ComposerUpdateCheckConfig();

if (!is_iterable($yaml)) {
throw new Exception\ConfigFileIsInvalid($this->filename);
// Avoid config merge if only one adapter is configured
if (1 === count($this->adapters)) {
return $this->adapters[0]->get();
}

$source = Valinor\Mapper\Source\Source::iterable($yaml);

try {
return $this->mapper->map(Configuration\ComposerUpdateCheckConfig::class, $source);
} catch (Valinor\Mapper\MappingError $error) {
throw new Exception\ConfigFileHasErrors($this->filename, $error);
foreach ($this->adapters as $adapter) {
$config->merge($adapter->get());
}

return $config;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace EliasHaeussler\ComposerUpdateCheck\Configuration\Adapter;
namespace EliasHaeussler\ComposerUpdateCheck\Config\Adapter;

use EliasHaeussler\ComposerUpdateCheck\Configuration;
use EliasHaeussler\ComposerUpdateCheck\Config;

/**
* ConfigAdapter.
Expand All @@ -33,5 +33,5 @@
*/
interface ConfigAdapter
{
public function resolve(): Configuration\ComposerUpdateCheckConfig;
public function get(): Config\ComposerUpdateCheckConfig;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,30 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

namespace EliasHaeussler\ComposerUpdateCheck\Configuration\Adapter;
namespace EliasHaeussler\ComposerUpdateCheck\Config\Adapter;

use EliasHaeussler\ComposerUpdateCheck\Exception;
use Symfony\Component\Filesystem;
use CuyZ\Valinor;
use EliasHaeussler\ComposerUpdateCheck\Config;

/**
* ConfigAdapterFactory.
* ConfigMapperFactory.
*
* @author Elias Häußler <elias@haeussler.dev>
* @license GPL-3.0-or-later
*
* @internal
*/
final class ConfigAdapterFactory
final class ConfigMapperFactory
{
/**
* @throws Exception\ConfigFileIsNotSupported
* @throws Exception\FileDoesNotExist
*/
public function make(string $filename): ConfigAdapter
public function get(): Valinor\Mapper\TreeMapper
{
return match (Filesystem\Path::getExtension($filename, true)) {
'json' => new JsonConfigAdapter($filename),
'php' => new PhpConfigAdapter($filename),
'yaml', 'yml' => new YamlConfigAdapter($filename),
default => throw new Exception\ConfigFileIsNotSupported($filename),
};
return (new Valinor\MapperBuilder())
->registerConstructor(
Config\Option\PackageExcludePattern::create(...),
)
->allowPermissiveTypes()
->enableFlexibleCasting()
->mapper()
;
}
}
Loading
Loading