From dcdd07650ea693f8ff4055bfad39b4478fe3012c Mon Sep 17 00:00:00 2001 From: James Titcumb Date: Thu, 23 Jan 2025 11:08:58 +0000 Subject: [PATCH] Allow adding/removing Packagist.org repo --- docs/usage.md | 2 ++ src/Command/RepositoryAddCommand.php | 12 ++++++++--- src/Command/RepositoryRemoveCommand.php | 11 ++++++++-- src/ComposerIntegration/PieJsonEditor.php | 16 +++++++++++++++ .../RepositoryManagementCommandsTest.php | 20 +++++++++++++++++++ .../ComposerIntegration/PieJsonEditorTest.php | 19 ++++++++++++++++++ 6 files changed, 75 insertions(+), 5 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 209411f..dd10cdb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -239,6 +239,7 @@ to use some other repository types: * `pie repository:add [--with-php-config=...] path /path/to/your/local/extension` * `pie repository:add [--with-php-config=...] vcs https://github.com/youruser/yourextension` * `pie repository:add [--with-php-config=...] composer https://repo.packagist.com/your-private-packagist/` +* `pie repository:add [--with-php-config=...] composer packagist.org` The `repository:*` commands all support the optional `--with-php-config` flag to allow you to specify which PHP installation to use (for example, if you have @@ -248,6 +249,7 @@ removed too, using the inverse `repository:remove` commands: * `pie repository:remove [--with-php-config=...] /path/to/your/local/extension` * `pie repository:remove [--with-php-config=...] https://github.com/youruser/yourextension` * `pie repository:remove [--with-php-config=...] https://repo.packagist.com/your-private-packagist/` +* `pie repository:remove [--with-php-config=...] packagist.org` Note you do not need to specify the repository type in `repository:remove`, just the URL. diff --git a/src/Command/RepositoryAddCommand.php b/src/Command/RepositoryAddCommand.php index 09852a3..fedcb6a 100644 --- a/src/Command/RepositoryAddCommand.php +++ b/src/Command/RepositoryAddCommand.php @@ -17,6 +17,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Webmozart\Assert\Assert; use function realpath; +use function str_contains; #[AsCommand( name: 'repository:add', @@ -69,16 +70,21 @@ final class RepositoryAddCommand extends Command $url = realpath($originalUrl); } - Assert::stringNotEmpty($url, 'Could not resolve ' . $originalUrl . ' to a real path'); + if ($type === 'composer' && str_contains($url, 'packagist.org')) { + // "adding packagist" is really just removing an exclusion + (new PieJsonEditor($pieJsonFilename))->removeRepository('packagist.org'); + } else { + Assert::stringNotEmpty($url, 'Could not resolve ' . $originalUrl . ' to a real path'); - (new PieJsonEditor($pieJsonFilename))->addRepository($type, $url); + (new PieJsonEditor($pieJsonFilename))->addRepository($type, $url); + } CommandHelper::listRepositories( PieComposerFactory::createPieComposer( $this->container, PieComposerRequest::noOperation( $output, - CommandHelper::determineTargetPlatformFromInputs($input, $output), + $targetPlatform, ), ), $output, diff --git a/src/Command/RepositoryRemoveCommand.php b/src/Command/RepositoryRemoveCommand.php index bd9966f..1742a71 100644 --- a/src/Command/RepositoryRemoveCommand.php +++ b/src/Command/RepositoryRemoveCommand.php @@ -16,6 +16,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Webmozart\Assert\Assert; +use function str_contains; + #[AsCommand( name: 'repository:remove', description: 'Remove a repository for packages that PIE can use.', @@ -52,14 +54,19 @@ final class RepositoryRemoveCommand extends Command $url = (string) $input->getArgument(self::ARG_URL); Assert::stringNotEmpty($url); - (new PieJsonEditor($pieJsonFilename))->removeRepository($url); + if (str_contains($url, 'packagist.org')) { + // "removing packagist" is really just adding an exclusion + (new PieJsonEditor($pieJsonFilename))->excludePackagistOrg(); + } else { + (new PieJsonEditor($pieJsonFilename))->removeRepository($url); + } CommandHelper::listRepositories( PieComposerFactory::createPieComposer( $this->container, PieComposerRequest::noOperation( $output, - CommandHelper::determineTargetPlatformFromInputs($input, $output), + $targetPlatform, ), ), $output, diff --git a/src/ComposerIntegration/PieJsonEditor.php b/src/ComposerIntegration/PieJsonEditor.php index a567b20..47b8308 100644 --- a/src/ComposerIntegration/PieJsonEditor.php +++ b/src/ComposerIntegration/PieJsonEditor.php @@ -15,6 +15,8 @@ use function str_replace; /** @internal This is not public API for PIE, so should not be depended upon unless you accept the risk of BC breaks */ class PieJsonEditor { + public const PACKAGIST_ORG_KEY = 'packagist.org'; + public function __construct(private readonly string $pieJsonFilename) { } @@ -60,6 +62,20 @@ class PieJsonEditor file_put_contents($this->pieJsonFilename, $originalPieJsonContent); } + public function excludePackagistOrg(): string + { + $originalPieJsonContent = file_get_contents($this->pieJsonFilename); + + (new JsonConfigSource( + new JsonFile( + $this->pieJsonFilename, + ), + )) + ->addRepository(self::PACKAGIST_ORG_KEY, false); + + return $originalPieJsonContent; + } + /** * Add a repository to the given `pie.json`. Returns the original * `pie.json` content, in case it needs to be restored later. diff --git a/test/integration/Command/RepositoryManagementCommandsTest.php b/test/integration/Command/RepositoryManagementCommandsTest.php index de9de3e..ffbf21a 100644 --- a/test/integration/Command/RepositoryManagementCommandsTest.php +++ b/test/integration/Command/RepositoryManagementCommandsTest.php @@ -28,6 +28,7 @@ final class RepositoryManagementCommandsTest extends TestCase { private const EXAMPLE_PATH_REPOSITORY_URL = __DIR__; private const EXAMPLE_VCS_REPOSITORY_URL = 'https://github.com/asgrim/example-pie-extension'; + private const PACKAGIST_ORG_URL = 'packagist.org'; private CommandTester $listCommand; private CommandTester $addCommand; @@ -39,6 +40,10 @@ final class RepositoryManagementCommandsTest extends TestCase $this->addCommand = new CommandTester(Container::factory()->get(RepositoryAddCommand::class)); $this->removeCommand = new CommandTester(Container::factory()->get(RepositoryRemoveCommand::class)); + $this->addCommand->execute([ + 'type' => 'composer', + 'url' => self::PACKAGIST_ORG_URL, + ]); $this->removeCommand->execute(['url' => self::EXAMPLE_PATH_REPOSITORY_URL]); $this->removeCommand->execute(['url' => self::EXAMPLE_VCS_REPOSITORY_URL]); $this->removeCommand->execute(['url' => self::EXAMPLE_VCS_REPOSITORY_URL . '.git']); @@ -84,6 +89,21 @@ final class RepositoryManagementCommandsTest extends TestCase $this->assertRepositoryListDisplayed(['Packagist']); } + public function testPackagistOrgCanBeManaged(): void + { + $this->assertRepositoryListDisplayed(['Packagist']); + + $this->removeCommand->execute(['url' => self::PACKAGIST_ORG_URL]); + + $this->assertRepositoryListDisplayed([]); + + $this->addCommand->execute([ + 'type' => 'composer', + 'url' => self::PACKAGIST_ORG_URL, + ]); + $this->assertRepositoryListDisplayed(['Packagist']); + } + /** @param list $expectedRepositories */ private function assertRepositoryListDisplayed(array $expectedRepositories): void { diff --git a/test/unit/ComposerIntegration/PieJsonEditorTest.php b/test/unit/ComposerIntegration/PieJsonEditorTest.php index 9ceb3f6..1ab4641 100644 --- a/test/unit/ComposerIntegration/PieJsonEditorTest.php +++ b/test/unit/ComposerIntegration/PieJsonEditorTest.php @@ -107,10 +107,29 @@ final class PieJsonEditorTest extends TestCase $this->normaliseJson($originalContent2), ); + $noRepositoriesContent = $this->normaliseJson(<<<'EOF' + { + "repositories": { + } + } + EOF); + + self::assertSame( + $noRepositoriesContent, + $this->normaliseJson(file_get_contents($testPieJson)), + ); + + $originalContent3 = $editor->excludePackagistOrg(); + self::assertSame( + $noRepositoriesContent, + $this->normaliseJson($originalContent3), + ); + self::assertSame( $this->normaliseJson(<<<'EOF' { "repositories": { + "packagist.org": false } } EOF),