diff --git a/src/Automatic/AbstractConfigurator.php b/src/Automatic/AbstractConfigurator.php index 6a292cb9..83592f66 100644 --- a/src/Automatic/AbstractConfigurator.php +++ b/src/Automatic/AbstractConfigurator.php @@ -97,7 +97,7 @@ public function has(string $name): bool public function configure(PackageContract $package): void { foreach (\array_keys($this->configurators) as $key) { - if ($package->hasConfig($key)) { + if ($package->hasConfig(ConfiguratorContract::TYPE, $key)) { $this->get($key)->configure($package); } } @@ -113,12 +113,22 @@ public function configure(PackageContract $package): void public function unconfigure(PackageContract $package): void { foreach (\array_keys($this->configurators) as $key) { - if ($package->hasConfig($key)) { + if ($package->hasConfig(ConfiguratorContract::TYPE, $key)) { $this->get($key)->unconfigure($package); } } } + /** + * Get all registered configurators. + * + * @return array + */ + public function getConfigurators(): array + { + return $this->configurators; + } + /** * Clear all configurators. * diff --git a/src/Automatic/Automatic.php b/src/Automatic/Automatic.php index e01e7eef..049cd6b4 100644 --- a/src/Automatic/Automatic.php +++ b/src/Automatic/Automatic.php @@ -33,6 +33,7 @@ use Composer\Script\Event; use Composer\Script\ScriptEvents; use FilesystemIterator; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Contract\Exception\InvalidArgumentException; use Narrowspark\Automatic\Common\Contract\Exception\RuntimeException; use Narrowspark\Automatic\Common\Contract\Package as PackageContract; @@ -369,8 +370,8 @@ public function onPostUpdate(Event $event, array $operations = []): void '', 'Some files may have been created or updated to configure your new packages.', 'The automatic.lock file has all information about the installed packages.', - 'Please review, edit and commit them: these files are yours.', - "\nTo show the package suggests run composer suggests." + 'Please review, edit and commit them: these files are yours', + "\nTo show the package suggests run composer suggests" ); } @@ -410,7 +411,7 @@ public function executeAutoScripts(Event $event): void $scriptExecutor->execute($type, $cmd); } } else { - $this->container->get(IOInterface::class)->write('No auto-scripts section was found under scripts.', true, IOInterface::VERBOSE); + $this->container->get(IOInterface::class)->write('No auto-scripts section was found under scripts', true, IOInterface::VERBOSE); } } @@ -680,10 +681,14 @@ private function doInstall(PackageContract $package, PackageConfigurator $packag $this->writeScriptExtenderToLock($package, $lock); - $this->container->get(Configurator::class)->configure($package); + /** @var \Narrowspark\Automatic\Configurator $configurator */ + $configurator = $this->container->get(Configurator::class); + $configurator->configure($package); $packageConfigurator->configure($package); + $this->showWarningOnRemainingConfigurators($package, $packageConfigurator, $configurator); + if ($package->hasConfig('post-install-output')) { foreach ((array) $package->getConfig('post-install-output') as $line) { $this->postInstallOutput[] = self::expandTargetDir($this->container->get('composer-extra'), $line); @@ -713,10 +718,14 @@ private function doInstall(PackageContract $package, PackageConfigurator $packag */ private function doUninstall(PackageContract $package, PackageConfigurator $packageConfigurator): void { - $this->container->get(Configurator::class)->unconfigure($package); + /** @var \Narrowspark\Automatic\Configurator $configurator */ + $configurator = $this->container->get(Configurator::class); + $configurator->unconfigure($package); $packageConfigurator->unconfigure($package); + $this->showWarningOnRemainingConfigurators($package, $packageConfigurator, $configurator); + /** @var \Narrowspark\Automatic\Lock $lock */ $lock = $this->container->get(Lock::class); @@ -812,17 +821,17 @@ private function getErrorMessage(IOInterface $io): ?string { // @codeCoverageIgnoreStart if (! \extension_loaded('openssl')) { - return 'You must enable the openssl extension in your "php.ini" file.'; + return 'You must enable the openssl extension in your "php.ini" file'; } if (\version_compare(self::getComposerVersion(), '1.6.0', '<')) { - return \sprintf('Your version "%s" of Composer is too old; Please upgrade.', Composer::VERSION); + return \sprintf('Your version "%s" of Composer is too old; Please upgrade', Composer::VERSION); } // @codeCoverageIgnoreEnd // skip on no interactive mode if (! $io->isInteractive()) { - return 'Composer running in a no interaction mode.'; + return 'Composer running in a no interaction mode'; } return null; @@ -849,7 +858,7 @@ private static function getComposerVersion(): string return $matches[0]; } - throw new RuntimeException('No composer version found.'); + throw new RuntimeException('No composer version found'); } /** @@ -875,8 +884,8 @@ private function configureLegacyTagsManager(IOInterface $io, LegacyTagsManager $ } $this->addLegacyTags($io, $requires, $tagsManager); - } elseif (isset($extra['require'])) { - $this->addLegacyTags($io, $extra['require'], $tagsManager); + } elseif (isset($extra[Util::COMPOSER_EXTRA_KEY]['require'])) { + $this->addLegacyTags($io, $extra[Util::COMPOSER_EXTRA_KEY]['require'], $tagsManager); } } @@ -983,4 +992,38 @@ private function extendRepositoryManager(Composer $composer, IOInterface $io, Le return $manager; } + + /** + * Show a waring if remaining configurators are found in package config. + * + * @param \Narrowspark\Automatic\Common\Contract\Package $package + * @param \Narrowspark\Automatic\PackageConfigurator $packageConfigurator + * @param \Narrowspark\Automatic\Configurator $configurator + * + * @return void + */ + private function showWarningOnRemainingConfigurators(PackageContract $package, PackageConfigurator $packageConfigurator, Configurator $configurator): void + { + $packageConfigurators = \array_keys((array) $package->getConfig(ConfiguratorContract::TYPE)); + + foreach (\array_keys($configurator->getConfigurators()) as $key) { + if (isset($packageConfigurators[$key])) { + unset($packageConfigurators[$key]); + } + } + + foreach (\array_keys($packageConfigurator->getConfigurators()) as $key) { + if (isset($packageConfigurators[$key])) { + unset($packageConfigurators[$key]); + } + } + + if (\count($packageConfigurators) !== 0) { + $this->container->get(IOInterface::class)->writeError(\sprintf( + 'No configurators were run for [%s] in [%s]', + \implode(', ', $packageConfigurators), + $package->getPrettyName() + )); + } + } } diff --git a/src/Automatic/Configurator/CopyFromPackageConfigurator.php b/src/Automatic/Configurator/CopyFromPackageConfigurator.php index edaa4770..12825840 100644 --- a/src/Automatic/Configurator/CopyFromPackageConfigurator.php +++ b/src/Automatic/Configurator/CopyFromPackageConfigurator.php @@ -3,6 +3,7 @@ namespace Narrowspark\Automatic\Configurator; use Narrowspark\Automatic\Common\Configurator\AbstractConfigurator; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Contract\Package as PackageContract; use Symfony\Component\Filesystem\Exception\IOException; @@ -23,7 +24,7 @@ public function configure(PackageContract $package): void { $this->write('Copying files'); - foreach ((array) $package->getConfig(self::getName()) as $from => $to) { + foreach ((array) $package->getConfig(ConfiguratorContract::TYPE, self::getName()) as $from => $to) { $target = self::expandTargetDir($this->options, $to); try { @@ -50,7 +51,7 @@ public function unconfigure(PackageContract $package): void { $this->write('Removing files'); - foreach ((array) $package->getConfig(self::getName()) as $source) { + foreach ((array) $package->getConfig(ConfiguratorContract::TYPE, self::getName()) as $source) { $source = self::expandTargetDir($this->options, $source); try { diff --git a/src/Automatic/Configurator/EnvConfigurator.php b/src/Automatic/Configurator/EnvConfigurator.php index 8edc6e72..32526080 100644 --- a/src/Automatic/Configurator/EnvConfigurator.php +++ b/src/Automatic/Configurator/EnvConfigurator.php @@ -3,6 +3,7 @@ namespace Narrowspark\Automatic\Configurator; use Narrowspark\Automatic\Common\Configurator\AbstractConfigurator; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Contract\Package as PackageContract; final class EnvConfigurator extends AbstractConfigurator @@ -30,7 +31,7 @@ public function configure(PackageContract $package): void $data = ''; - foreach ((array) $package->getConfig(self::getName()) as $key => $value) { + foreach ((array) $package->getConfig(ConfiguratorContract::TYPE, self::getName()) as $key => $value) { if ($key[0] === '#' && \is_numeric(\mb_substr($key, 1))) { $data .= '# ' . $value . "\n"; diff --git a/src/Automatic/Configurator/GitIgnoreConfigurator.php b/src/Automatic/Configurator/GitIgnoreConfigurator.php index 92a30b83..bb90b436 100644 --- a/src/Automatic/Configurator/GitIgnoreConfigurator.php +++ b/src/Automatic/Configurator/GitIgnoreConfigurator.php @@ -3,6 +3,7 @@ namespace Narrowspark\Automatic\Configurator; use Narrowspark\Automatic\Common\Configurator\AbstractConfigurator; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Contract\Package as PackageContract; final class GitIgnoreConfigurator extends AbstractConfigurator @@ -20,7 +21,7 @@ public static function getName(): string */ public function configure(PackageContract $package): void { - $this->write('Added entries to .gitignore.'); + $this->write('Added entries to .gitignore'); $gitignore = $this->path->getWorkingDir() . \DIRECTORY_SEPARATOR . '.gitignore'; @@ -30,7 +31,7 @@ public function configure(PackageContract $package): void $data = ''; - foreach ((array) $package->getConfig(self::getName()) as $value) { + foreach ((array) $package->getConfig(ConfiguratorContract::TYPE, self::getName()) as $value) { $value = self::expandTargetDir($this->options, $value); $data .= "${value}\n"; } @@ -63,7 +64,7 @@ public function unconfigure(PackageContract $package): void return; } - $this->write('Removed entries in .gitignore.'); + $this->write('Removed entries in .gitignore'); \file_put_contents($file, \ltrim($contents, "\r\n")); } diff --git a/src/Common/Contract/Configurator.php b/src/Common/Contract/Configurator.php index c4f91786..289dd8ec 100644 --- a/src/Common/Contract/Configurator.php +++ b/src/Common/Contract/Configurator.php @@ -4,6 +4,11 @@ interface Configurator { + /** + * @var string + */ + public const TYPE = 'configurators'; + /** * Return the configurator key name. * diff --git a/src/Common/Contract/Package.php b/src/Common/Contract/Package.php index 7dd565ce..0b7f6d1a 100644 --- a/src/Common/Contract/Package.php +++ b/src/Common/Contract/Package.php @@ -132,20 +132,22 @@ public function setConfig(array $configs): self; /** * Checks if key exits in extra automatic config. * - * @param string $key + * @param string $mainKey + * @param null|string $name * * @return bool */ - public function hasConfig(string $key): bool; + public function hasConfig(string $mainKey, ?string $name = null): bool; /** * Get a automatic config value. * - * @param string $key + * @param string $mainKey + * @param null|string $name * * @return null|array|string */ - public function getConfig(string $key); + public function getConfig(string $mainKey, ?string $name = null); /** * Returns the automatic package configs. diff --git a/src/Common/Package.php b/src/Common/Package.php index 81b3fc7e..b2669e33 100644 --- a/src/Common/Package.php +++ b/src/Common/Package.php @@ -286,17 +286,37 @@ public function setConfig(array $configs): PackageContract /** * {@inheritdoc} */ - public function hasConfig(string $key): bool + public function hasConfig(string $mainKey, ?string $name = null): bool { - return \array_key_exists($key, $this->configs); + $mainCheck = \array_key_exists($mainKey, $this->configs); + + if ($name === null) { + return $mainCheck; + } + + if ($mainCheck === true && \is_array($this->configs[$mainKey])) { + return \array_key_exists($name, $this->configs[$mainKey]); + } + + return false; } /** * {@inheritdoc} */ - public function getConfig(string $key) + public function getConfig(string $mainKey, ?string $name = null) { - return $this->configs[$key] ?? null; + if (\array_key_exists($mainKey, $this->configs)) { + if ($name === null) { + return $this->configs[$mainKey]; + } + + if (\is_array($this->configs[$mainKey]) && \array_key_exists($name, $this->configs[$mainKey])) { + return $this->configs[$mainKey][$name]; + } + } + + return null; } /** diff --git a/src/Common/Path.php b/src/Common/Path.php index 431b6007..63ab6988 100644 --- a/src/Common/Path.php +++ b/src/Common/Path.php @@ -2,9 +2,6 @@ declare(strict_types=1); namespace Narrowspark\Automatic\Common; -/** - * @internal - */ final class Path { /** diff --git a/tests/Automatic/AutomaticTest.php b/tests/Automatic/AutomaticTest.php index 79b4baa2..5d4ec6cd 100644 --- a/tests/Automatic/AutomaticTest.php +++ b/tests/Automatic/AutomaticTest.php @@ -154,7 +154,7 @@ public function testActivateWithNoInteractive(): void ->andReturn(false); $this->ioMock->shouldReceive('writeError') ->once() - ->with('Narrowspark Automatic has been disabled. Composer running in a no interaction mode.'); + ->with('Narrowspark Automatic has been disabled. Composer running in a no interaction mode'); $this->automatic->activate($this->composerMock, $this->ioMock); } @@ -393,7 +393,7 @@ public function testExecuteAutoScriptsWithoutScripts(): void $this->ioMock->shouldReceive('write') ->once() - ->with('No auto-scripts section was found under scripts.', true, IOInterface::VERBOSE); + ->with('No auto-scripts section was found under scripts', true, IOInterface::VERBOSE); $containerMock = $this->mock(ContainerContract::class); $containerMock->shouldReceive('get') diff --git a/tests/Automatic/Configurator/CopyFromPackageConfiguratorTest.php b/tests/Automatic/Configurator/CopyFromPackageConfiguratorTest.php index bd3a2255..965206ac 100644 --- a/tests/Automatic/Configurator/CopyFromPackageConfiguratorTest.php +++ b/tests/Automatic/Configurator/CopyFromPackageConfiguratorTest.php @@ -4,6 +4,7 @@ use Composer\Composer; use Composer\IO\IOInterface; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Package; use Narrowspark\Automatic\Configurator\CopyFromPackageConfigurator; use Narrowspark\TestingHelper\Phpunit\MockeryTestCase; @@ -261,7 +262,7 @@ private function arrangePackageWithConfig(string $from, string $to): Package ->andReturn(__DIR__); $package = new Package('Stub/stub', '1.0.0'); - $package->setConfig(['copy' => [$from => $to]]); + $package->setConfig([ConfiguratorContract::TYPE => ['copy' => [$from => $to]]]); return $package; } diff --git a/tests/Automatic/Configurator/EnvConfiguratorTest.php b/tests/Automatic/Configurator/EnvConfiguratorTest.php index 5ad374c6..7bb5def2 100644 --- a/tests/Automatic/Configurator/EnvConfiguratorTest.php +++ b/tests/Automatic/Configurator/EnvConfiguratorTest.php @@ -4,6 +4,7 @@ use Composer\Composer; use Composer\IO\NullIO; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Package; use Narrowspark\Automatic\Configurator\EnvConfigurator; use Narrowspark\TestingHelper\Phpunit\MockeryTestCase; @@ -76,17 +77,19 @@ public function testConfigure(): void { $package = new Package('fixtures/test', '1.0.0'); $package->setConfig([ - 'env' => [ - 'APP_ENV' => 'test bar', - 'APP_DEBUG' => '0', - 'APP_PARAGRAPH' => "foo\n\"bar\"\\t", - 'DATABASE_URL' => 'mysql://root@127.0.0.1:3306/narrowspark?charset=utf8mb4&serverVersion=5.7', - 'MAILER_URL' => 'null://localhost', - 'MAILER_USER' => 'narrow', - '#1' => 'Comment 1', - '#2' => 'Comment 3', - '#TRUSTED_SECRET' => 's3cretf0rt3st"<>', - 'APP_SECRET' => 's3cretf0rt3st"<>', + ConfiguratorContract::TYPE => [ + 'env' => [ + 'APP_ENV' => 'test bar', + 'APP_DEBUG' => '0', + 'APP_PARAGRAPH' => "foo\n\"bar\"\\t", + 'DATABASE_URL' => 'mysql://root@127.0.0.1:3306/narrowspark?charset=utf8mb4&serverVersion=5.7', + 'MAILER_URL' => 'null://localhost', + 'MAILER_USER' => 'narrow', + '#1' => 'Comment 1', + '#2' => 'Comment 3', + '#TRUSTED_SECRET' => 's3cretf0rt3st"<>', + 'APP_SECRET' => 's3cretf0rt3st"<>', + ], ], ]); @@ -127,7 +130,7 @@ public function testUnconfigure(): void ]; $package = new Package('fixtures/env2', '1.0.0'); - $package->setConfig(['env' => $envConfig]); + $package->setConfig([ConfiguratorContract::TYPE => ['env' => $envConfig]]); $this->configurator->configure($package); @@ -146,7 +149,7 @@ public function testUnconfigure(): void static::assertStringEqualsFile($this->envPath, $envContents); $package = new Package('fixtures/env2', '1.1.0'); - $package->setConfig(['env' => $envConfig]); + $package->setConfig([ConfiguratorContract::TYPE => ['env' => $envConfig]]); $this->configurator->unconfigure($package); diff --git a/tests/Automatic/Configurator/GitignoreConfiguratorTest.php b/tests/Automatic/Configurator/GitignoreConfiguratorTest.php index 8ccb7c1f..3878d312 100644 --- a/tests/Automatic/Configurator/GitignoreConfiguratorTest.php +++ b/tests/Automatic/Configurator/GitignoreConfiguratorTest.php @@ -4,6 +4,7 @@ use Composer\Composer; use Composer\IO\NullIO; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Package; use Narrowspark\Automatic\Configurator\GitIgnoreConfigurator; use PHPUnit\Framework\TestCase; @@ -149,7 +150,7 @@ public function testUnconfigureWithNotFoundPackage(): void private function arrangePackageWithConfig(string $name, array $config): Package { $package = new Package($name, '1.0.0'); - $package->setConfig(['gitignore' => $config]); + $package->setConfig([ConfiguratorContract::TYPE => ['gitignore' => $config]]); return $package; } diff --git a/tests/Automatic/ConfiguratorTest.php b/tests/Automatic/ConfiguratorTest.php index a69e9b0c..4d8379c5 100644 --- a/tests/Automatic/ConfiguratorTest.php +++ b/tests/Automatic/ConfiguratorTest.php @@ -3,6 +3,7 @@ namespace Narrowspark\Automatic\Test; use Composer\IO\IOInterface; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Package; use Narrowspark\Automatic\Configurator; @@ -53,6 +54,11 @@ public function testConfigureWithCopy(): void \unlink($this->copyPath); } + public function testGetConfigurators(): void + { + static::assertCount(4, $this->configurator->getConfigurators()); + } + public function testUnconfigureWithCopy(): void { $this->arrangeVendorDir(); @@ -99,8 +105,10 @@ protected function arrangeCopyPackage(): Package { $package = new Package('Fixture/copy', '1.0'); $package->setConfig([ - 'copy' => [ - 'copy.txt' => $this->copyFileName, + ConfiguratorContract::TYPE => [ + 'copy' => [ + 'copy.txt' => $this->copyFileName, + ], ], ]); diff --git a/tests/Automatic/Fixture/MockConfigurator.php b/tests/Automatic/Fixture/MockConfigurator.php index ba38def6..b34c0df4 100644 --- a/tests/Automatic/Fixture/MockConfigurator.php +++ b/tests/Automatic/Fixture/MockConfigurator.php @@ -3,6 +3,7 @@ namespace Narrowspark\Automatic\Test\Fixture; use Narrowspark\Automatic\Common\Configurator\AbstractConfigurator; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Contract\Package as PackageContract; class MockConfigurator extends AbstractConfigurator @@ -14,14 +15,14 @@ public static function getName(): string public function configure(PackageContract $package): void { - foreach ($package->getConfig('mock') as $message) { + foreach ($package->getConfig(ConfiguratorContract::TYPE, 'mock') as $message) { $this->write($message); } } public function unconfigure(PackageContract $package): void { - foreach ($package->getConfig('mock') as $message) { + foreach ($package->getConfig(ConfiguratorContract::TYPE, 'mock') as $message) { $this->write($message); } } diff --git a/tests/Automatic/PackageConfiguratorTest.php b/tests/Automatic/PackageConfiguratorTest.php index 22f3172f..32615f61 100644 --- a/tests/Automatic/PackageConfiguratorTest.php +++ b/tests/Automatic/PackageConfiguratorTest.php @@ -3,6 +3,7 @@ namespace Narrowspark\Automatic\Test; use Composer\IO\IOInterface; +use Narrowspark\Automatic\Common\Contract\Configurator as ConfiguratorContract; use Narrowspark\Automatic\Common\Package; use Narrowspark\Automatic\PackageConfigurator; use Narrowspark\Automatic\Test\Fixture\MockConfigurator; @@ -17,8 +18,10 @@ public function testConfiguratorWithPackageConfigurator(): void $package = $this->arrangePackageWithConfig( 'test/test', [ - 'mock' => [ - 'test', + ConfiguratorContract::TYPE => [ + 'mock' => [ + 'test', + ], ], ] ); @@ -38,8 +41,10 @@ public function testConfiguratorOutWithPackageConfigurator(): void $package = $this->arrangePackageWithConfig( 'test/test', [ - 'mock' => [ - 'test', + ConfiguratorContract::TYPE => [ + 'mock' => [ + 'test', + ], ], ] ); diff --git a/tests/Common/PackageTest.php b/tests/Common/PackageTest.php index 6471df04..091d6382 100644 --- a/tests/Common/PackageTest.php +++ b/tests/Common/PackageTest.php @@ -98,6 +98,29 @@ public function testSetAndGetConfigs(): void static::assertEquals($config, $this->package->getConfigs()); } + public function testGetConfigWithMainKeyAndName(): void + { + $config = ['test' => ['cut' => true]]; + + $this->package->setConfig($config); + + static::assertTrue($this->package->getConfig('test', 'cut')); + static::assertNull($this->package->getConfig('test', 'noop')); + } + + public function testHasConfigWithMainKeyAndName(): void + { + $config = ['test' => ['cut' => true]]; + + $this->package->setConfig($config); + + static::assertFalse($this->package->hasConfig('noop')); + static::assertFalse($this->package->hasConfig('test', 'noop')); + static::assertFalse($this->package->hasConfig('noop', 'noop')); + static::assertTrue($this->package->hasConfig('test')); + static::assertTrue($this->package->hasConfig('test', 'cut')); + } + public function testSetAndGetParentName(): void { $name = 'foo/bar';