diff --git a/src/Installer.php b/src/Installer.php index 385d9ef..a42cdab 100644 --- a/src/Installer.php +++ b/src/Installer.php @@ -401,6 +401,10 @@ public function install(InstalledRepositoryInterface $repo, PackageInterface $pa if ($this->isPathRepository($package)) { $this->io->write(" - Skipping install for path repository: {$package->getPrettyName()}"); + if (! $repo->hasPackage($package)) { + $repo->addPackage(clone $package); + } + return \React\Promise\resolve(null); } @@ -480,6 +484,14 @@ public function update(InstalledRepositoryInterface $repo, PackageInterface $ini if ($this->isPathRepository($target)) { $this->io->write(" - Skipping update for path repository: {$target->getPrettyName()}"); + if ($repo->hasPackage($initial)) { + $repo->removePackage($initial); + } + + if (! $repo->hasPackage($target)) { + $repo->addPackage(clone $target); + } + return \React\Promise\resolve(null); } diff --git a/tests/ModuleInstallerTest.php b/tests/ModuleInstallerTest.php index ef4bfde..8f6723b 100644 --- a/tests/ModuleInstallerTest.php +++ b/tests/ModuleInstallerTest.php @@ -599,6 +599,38 @@ public function test_install_logs_skip_message_and_returns_promise_for_path_repo $this->assertNotNull($promise); } + public function test_install_registers_package_in_repo_when_not_already_present_for_path_repo(): void + { + $io = $this->createStub(IOInterface::class); + + $pkg = $this->createStub(PackageInterface::class); + $pkg->method('getDistType')->willReturn('path'); + $pkg->method('getPrettyName')->willReturn('saucebase/test'); + + $repo = $this->createMock(InstalledRepositoryInterface::class); + $repo->method('hasPackage')->willReturn(false); + $repo->expects($this->once())->method('addPackage'); + + $installer = new TestableInstaller($io, null); + $installer->install($repo, $pkg); + } + + public function test_install_does_not_register_package_in_repo_when_already_present_for_path_repo(): void + { + $io = $this->createStub(IOInterface::class); + + $pkg = $this->createStub(PackageInterface::class); + $pkg->method('getDistType')->willReturn('path'); + $pkg->method('getPrettyName')->willReturn('saucebase/test'); + + $repo = $this->createMock(InstalledRepositoryInterface::class); + $repo->method('hasPackage')->willReturn(true); + $repo->expects($this->never())->method('addPackage'); + + $installer = new TestableInstaller($io, null); + $installer->install($repo, $pkg); + } + // ------------------------------------------------------------------------- // update() path-repository guard // ------------------------------------------------------------------------- @@ -624,6 +656,64 @@ public function test_update_logs_skip_message_and_returns_promise_for_path_repo( $this->assertNotNull($promise); } + public function test_update_registers_package_in_repo_when_not_already_present_for_path_repo(): void + { + $io = $this->createStub(IOInterface::class); + + $initial = $this->createStub(PackageInterface::class); + + $target = $this->createStub(PackageInterface::class); + $target->method('getDistType')->willReturn('path'); + $target->method('getPrettyName')->willReturn('saucebase/test'); + + $repo = $this->createMock(InstalledRepositoryInterface::class); + $repo->method('hasPackage')->willReturn(false); + $repo->expects($this->never())->method('removePackage'); + $repo->expects($this->once())->method('addPackage'); + + $installer = new TestableInstaller($io, null); + $installer->update($repo, $initial, $target); + } + + public function test_update_replaces_initial_with_target_in_repo_for_path_repo(): void + { + $io = $this->createStub(IOInterface::class); + + $initial = $this->createStub(PackageInterface::class); + + $target = $this->createStub(PackageInterface::class); + $target->method('getDistType')->willReturn('path'); + $target->method('getPrettyName')->willReturn('saucebase/test'); + + $repo = $this->createMock(InstalledRepositoryInterface::class); + $repo->method('hasPackage') + ->willReturnCallback(fn (PackageInterface $pkg) => $pkg === $initial); + $repo->expects($this->once())->method('removePackage')->with($initial); + $repo->expects($this->once())->method('addPackage'); + + $installer = new TestableInstaller($io, null); + $installer->update($repo, $initial, $target); + } + + public function test_update_does_not_register_package_in_repo_when_already_present_for_path_repo(): void + { + $io = $this->createStub(IOInterface::class); + + $initial = $this->createStub(PackageInterface::class); + + $target = $this->createStub(PackageInterface::class); + $target->method('getDistType')->willReturn('path'); + $target->method('getPrettyName')->willReturn('saucebase/test'); + + $repo = $this->createMock(InstalledRepositoryInterface::class); + $repo->method('hasPackage')->willReturn(true); + $repo->expects($this->once())->method('removePackage')->with($initial); + $repo->expects($this->never())->method('addPackage'); + + $installer = new TestableInstaller($io, null); + $installer->update($repo, $initial, $target); + } + // ------------------------------------------------------------------------- // uninstall() path-repository guard // -------------------------------------------------------------------------