diff --git a/ruleset.xml b/ruleset.xml
index a11f18f..0591ed0 100644
--- a/ruleset.xml
+++ b/ruleset.xml
@@ -9,7 +9,14 @@
-
+
+
+
+
+
+
+
+
diff --git a/src/Plugin.php b/src/Plugin.php
index cef68b5..0b202cb 100644
--- a/src/Plugin.php
+++ b/src/Plugin.php
@@ -21,12 +21,14 @@
use Composer\Plugin\Capability\CommandProvider as ComposerCommandProvider;
use Composer\Plugin\Capable;
use Composer\Plugin\PluginInterface;
+use Composer\Script\Event;
use Composer\Script\ScriptEvents;
use Composer\Util\Filesystem as ComposerFileSystem;
use ComposerLink\Actions\LinkPackages;
use ComposerLink\Repository\Repository;
use ComposerLink\Repository\RepositoryFactory;
use RuntimeException;
+use Throwable;
class Plugin implements PluginInterface, Capable, EventSubscriberInterface
{
@@ -40,6 +42,15 @@ class Plugin implements PluginInterface, Capable, EventSubscriberInterface
protected Composer $composer;
+ /**
+ * It can happen that activation doesn't work, this happens when this plugin is upgraded.
+ * Composer runs this file through an eval() with renamed class names, but all other classes
+ * in this library are still the old ones loaded in memory.
+ *
+ * We try to detect this, and skip the event callbacks if it happens
+ */
+ protected bool $couldNotActivate = false;
+
public function __construct(
?ComposerFileSystem $filesystem = null,
protected ?LinkPackages $linkPackages = null,
@@ -73,10 +84,15 @@ public function activate(Composer $composer, IOInterface $io): void
$io->debug("[ComposerLink]\tPlugin is activating");
$this->composer = $composer;
- $this->initializeRepository();
- $this->initializeLinkedPackageFactory();
- $this->initializeLinkManager();
- $this->initializeLinkPackages();
+ try {
+ $this->initializeRepository();
+ $this->initializeLinkedPackageFactory();
+ $this->initializeLinkManager();
+ $this->initializeLinkPackages();
+ } catch (Throwable $e) {
+ $io->debug("[ComposerLink]\tException: " . $e->getMessage());
+ $this->couldNotActivate = true;
+ }
}
protected function initializeRepository(): void
@@ -136,8 +152,15 @@ public function getLinkManager(): LinkManager
return $this->linkManager;
}
- public function linkLinkedPackages(): void
+ public function linkLinkedPackages(Event $event): void
{
+ // Plugin couldn't be activated probably because the plugin was updated
+ if ($this->couldNotActivate) {
+ $event->getIO()->warning('Composer link couldn\'t be activated because it was probably upgraded, run `composer install` again to link packages');
+
+ return;
+ }
+
if (is_null($this->linkPackages)) {
throw new RuntimeException('Plugin not activated');
}
diff --git a/tests/Unit/PluginTest.php b/tests/Unit/PluginTest.php
index 6732056..ddb90bc 100644
--- a/tests/Unit/PluginTest.php
+++ b/tests/Unit/PluginTest.php
@@ -23,14 +23,17 @@
use Composer\Plugin\Capability\CommandProvider as ComposerCommandProvider;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Repository\RepositoryManager;
+use Composer\Script\Event;
use Composer\Script\ScriptEvents;
use Composer\Util\Filesystem;
use Composer\Util\Loop;
use ComposerLink\Actions\LinkPackages;
use ComposerLink\CommandProvider;
use ComposerLink\Plugin;
+use ComposerLink\Repository\RepositoryFactory;
use PHPUnit\Framework\MockObject\MockObject;
use RuntimeException;
+use TypeError;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -103,6 +106,30 @@ public function test_if_plugin_can_be_utilized(): void
$plugin->uninstall($this->composer, $this->io);
}
+ public function test_unable_to_activate_plugin(): void
+ {
+ $repositoryFactory = $this->createMock(RepositoryFactory::class);
+ $linkPackages = $this->createMock(LinkPackages::class);
+ $event = $this->createMock(Event::class);
+ $event->method('getIO')->willReturn($this->io);
+
+ $repositoryFactory->method('create')
+ ->willThrowException(new TypeError('test error'));
+
+ $plugin = new Plugin(
+ $this->filesystem,
+ $linkPackages,
+ $repositoryFactory,
+ );
+
+ $plugin->activate($this->composer, $this->io);
+
+ $this->io->expects(static::once())->method('warning')->with(
+ static::stringContains('Composer link couldn\'t be activated')
+ );
+ $plugin->linkLinkedPackages($event);
+ }
+
public function test_is_global(): void
{
$this->config->method('get')
@@ -143,13 +170,14 @@ public function test_plugin_throws_exception_repository(): void
public function test_plugin_link_linked_packages(): void
{
+ $event = $this->createMock(Event::class);
$linkPackages = $this->createMock(LinkPackages::class);
$linkPackages->expects(static::once())->method('execute');
$plugin = new Plugin($this->createMock(Filesystem::class), $linkPackages);
- $plugin->linkLinkedPackages();
+ $plugin->linkLinkedPackages($event);
static::expectException(RuntimeException::class);
$plugin = new Plugin($this->createMock(Filesystem::class));
- $plugin->linkLinkedPackages();
+ $plugin->linkLinkedPackages($event);
}
}