From 7a43045178fe469b826914f5f07d5b2661e76e12 Mon Sep 17 00:00:00 2001 From: Waleed Qadi Date: Sat, 11 Feb 2023 22:39:03 -0700 Subject: [PATCH 1/8] Add composer and io to all events --- src/Event/PatchEvent.php | 37 ++++++++++++++++++++++++++++++++-- src/Event/PluginEvent.php | 36 ++++++++++++++++++++++++++++++++- src/Plugin/Patches.php | 10 ++++----- tests/unit/PatchEventTest.php | 7 ++++++- tests/unit/PluginEventTest.php | 7 ++++++- 5 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/Event/PatchEvent.php b/src/Event/PatchEvent.php index 4ada8551..9d4005e1 100644 --- a/src/Event/PatchEvent.php +++ b/src/Event/PatchEvent.php @@ -7,8 +7,9 @@ namespace cweagans\Composer\Event; +use Composer\Composer; use Composer\EventDispatcher\Event; -use Composer\Package\PackageInterface; +use Composer\IO\IOInterface; use cweagans\Composer\Patch; class PatchEvent extends Event @@ -18,16 +19,28 @@ class PatchEvent extends Event */ protected Patch $patch; + /** + * @var Composer $composer + */ + protected Composer $composer; + + /** + * @var IOInterface $io + */ + protected IOInterface $io; + /** * Constructs a PatchEvent object. * * @param string $eventName * @param Patch $patch */ - public function __construct(string $eventName, Patch $patch) + public function __construct(string $eventName, Patch $patch, Composer $composer, IOInterface $io) { parent::__construct($eventName); $this->patch = $patch; + $this->composer = $composer; + $this->io = $io; } /** @@ -39,4 +52,24 @@ public function getPatch(): Patch { return $this->patch; } + + /** + * Returns the Composer object. + * + * @return Composer + */ + public function getComposer(): Composer + { + return $this->composer; + } + + /** + * Returns the IOInterface. + * + * @return IOInterface + */ + public function getIO(): IOInterface + { + return $this->io; + } } diff --git a/src/Event/PluginEvent.php b/src/Event/PluginEvent.php index 5f428cc6..9fa1b3d7 100644 --- a/src/Event/PluginEvent.php +++ b/src/Event/PluginEvent.php @@ -2,7 +2,9 @@ namespace cweagans\Composer\Event; +use Composer\Composer; use Composer\EventDispatcher\Event; +use Composer\IO\IOInterface; class PluginEvent extends Event { @@ -11,16 +13,28 @@ class PluginEvent extends Event */ protected array $capabilities; + /** + * @var Composer $composer + */ + protected Composer $composer; + + /** + * @var IOInterface $io + */ + protected IOInterface $io; + /** * Constructs a PluginEvent object. * * @param string $eventName * @param array $capabilities */ - public function __construct(string $eventName, array $capabilities) + public function __construct(string $eventName, array $capabilities, Composer $composer, IOInterface $io) { parent::__construct($eventName); $this->capabilities = $capabilities; + $this->composer = $composer; + $this->io = $io; } /** @@ -46,4 +60,24 @@ public function setCapabilities(array $capabilities): void { $this->capabilities = $capabilities; } + + /** + * Returns the Composer object. + * + * @return Composer + */ + public function getComposer(): Composer + { + return $this->composer; + } + + /** + * Returns the IOInterface. + * + * @return IOInterface + */ + public function getIO(): IOInterface + { + return $this->io; + } } diff --git a/src/Plugin/Patches.php b/src/Plugin/Patches.php index 1f9e46bf..9435e3ed 100644 --- a/src/Plugin/Patches.php +++ b/src/Plugin/Patches.php @@ -224,18 +224,18 @@ public function download(Patch $patch) $this->composer->getEventDispatcher()->dispatch( PatchEvents::PRE_PATCH_DOWNLOAD, - new PatchEvent(PatchEvents::PRE_PATCH_DOWNLOAD, $patch) + new PatchEvent(PatchEvents::PRE_PATCH_DOWNLOAD, $patch, $this->composer, $this->io) ); $downloader->downloadPatch($patch); $this->composer->getEventDispatcher()->dispatch( PatchEvents::POST_PATCH_DOWNLOAD, - new PatchEvent(PatchEvents::POST_PATCH_DOWNLOAD, $patch) + new PatchEvent(PatchEvents::POST_PATCH_DOWNLOAD, $patch, $this->composer, $this->io) ); } public function guessDepth(Patch $patch) { - $event = new PatchEvent(PatchEvents::PRE_PATCH_GUESS_DEPTH, $patch); + $event = new PatchEvent(PatchEvents::PRE_PATCH_GUESS_DEPTH, $patch, $this->composer, $this->io); $this->composer->getEventDispatcher()->dispatch(PatchEvents::PRE_PATCH_GUESS_DEPTH, $event); $patch = $event->getPatch(); @@ -255,7 +255,7 @@ public function apply(Patch $patch, string $install_path) $this->guessDepth($patch); - $event = new PatchEvent(PatchEvents::PRE_PATCH_APPLY, $patch); + $event = new PatchEvent(PatchEvents::PRE_PATCH_APPLY, $patch, $this->composer, $this->io); $this->composer->getEventDispatcher()->dispatch(PatchEvents::PRE_PATCH_APPLY, $event); $patch = $event->getPatch(); @@ -272,7 +272,7 @@ public function apply(Patch $patch, string $install_path) $this->composer->getEventDispatcher()->dispatch( PatchEvents::POST_PATCH_APPLY, - new PatchEvent(PatchEvents::POST_PATCH_APPLY, $patch) + new PatchEvent(PatchEvents::POST_PATCH_APPLY, $patch, $this->composer, $this->io) ); } diff --git a/tests/unit/PatchEventTest.php b/tests/unit/PatchEventTest.php index 46f5db31..e39ec093 100644 --- a/tests/unit/PatchEventTest.php +++ b/tests/unit/PatchEventTest.php @@ -8,6 +8,8 @@ namespace cweagans\Composer\Tests\Unit; use Codeception\Test\Unit; +use Composer\Composer; +use Composer\IO\NullIO; use Composer\Package\Package; use Composer\Package\PackageInterface; use cweagans\Composer\Event\PatchEvent; @@ -23,7 +25,10 @@ class PatchEventTest extends Unit */ public function testGetters($event_name, $patch) { - $patch_event = new PatchEvent($event_name, $patch); + $composer = new Composer(); + $io = new NullIO(); + + $patch_event = new PatchEvent($event_name, $patch, $composer, $io); $this->assertEquals($event_name, $patch_event->getName()); $this->assertEquals($patch, $patch_event->getPatch()); } diff --git a/tests/unit/PluginEventTest.php b/tests/unit/PluginEventTest.php index 8fb2ad42..c37c1e6f 100644 --- a/tests/unit/PluginEventTest.php +++ b/tests/unit/PluginEventTest.php @@ -8,6 +8,8 @@ namespace cweagans\Composer\Tests\Unit; use Codeception\Test\Unit; +use Composer\Composer; +use Composer\IO\NullIO; use cweagans\Composer\Event\PluginEvent; use cweagans\Composer\Event\PluginEvents; @@ -20,7 +22,10 @@ class PluginEventTest extends Unit */ public function testGetters($event_name, array $capabilities) { - $plugin_event = new PluginEvent($event_name, $capabilities); + $composer = new Composer(); + $io = new NullIO(); + + $plugin_event = new PluginEvent($event_name, $capabilities, $composer, $io); $this->assertEquals($event_name, $plugin_event->getName()); $this->assertEquals($capabilities, $plugin_event->getCapabilities()); From 12d83f6480c559050c9285ffd508adcc9db3b1d4 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sat, 11 Feb 2023 22:42:07 -0700 Subject: [PATCH 2/8] Add params to a few more event constructors --- src/Downloader.php | 2 +- src/Patcher.php | 2 +- src/Resolver.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Downloader.php b/src/Downloader.php index aa29382f..b1c84843 100644 --- a/src/Downloader.php +++ b/src/Downloader.php @@ -104,7 +104,7 @@ protected function getDownloaders(): array } - $event = new PluginEvent(PluginEvents::POST_DISCOVER_DOWNLOADERS, $downloaders); + $event = new PluginEvent(PluginEvents::POST_DISCOVER_DOWNLOADERS, $downloaders, $this->composer, $this->io); $this->composer->getEventDispatcher()->dispatch(PluginEvents::POST_DISCOVER_DOWNLOADERS, $event); $downloaders = $event->getCapabilities(); diff --git a/src/Patcher.php b/src/Patcher.php index d56eb09f..87c47e70 100644 --- a/src/Patcher.php +++ b/src/Patcher.php @@ -103,7 +103,7 @@ protected function getPatchers(): array $patchers = array_merge($patchers, $newPatchers); } - $event = new PluginEvent(PluginEvents::POST_DISCOVER_PATCHERS, $patchers); + $event = new PluginEvent(PluginEvents::POST_DISCOVER_PATCHERS, $patchers, $this->composer, $this->io); $this->composer->getEventDispatcher()->dispatch(PluginEvents::POST_DISCOVER_PATCHERS, $event); $patchers = $event->getCapabilities(); diff --git a/src/Resolver.php b/src/Resolver.php index 6beb3c94..b042939a 100644 --- a/src/Resolver.php +++ b/src/Resolver.php @@ -100,7 +100,7 @@ protected function getPatchResolvers(): array $resolvers = array_merge($resolvers, $newResolvers); } - $event = new PluginEvent(PluginEvents::POST_DISCOVER_RESOLVERS, $resolvers); + $event = new PluginEvent(PluginEvents::POST_DISCOVER_RESOLVERS, $resolvers, $this->composer, $this->io); $this->composer->getEventDispatcher()->dispatch(PluginEvents::POST_DISCOVER_RESOLVERS, $event); $resolvers = $event->getCapabilities(); From f10a18cf5a5ee96bf00c930a002c1f5c2044d923 Mon Sep 17 00:00:00 2001 From: Waleed Qadi Date: Sat, 11 Feb 2023 22:48:53 -0700 Subject: [PATCH 3/8] Emit an event before throwing exception when patch cannot be applied --- src/Event/PatchEvent.php | 26 ++++++++++++++++++++++++-- src/Event/PatchEvents.php | 10 ++++++++++ src/Plugin/Patches.php | 7 ++++++- tests/unit/PatchEventTest.php | 18 +++++++++--------- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/Event/PatchEvent.php b/src/Event/PatchEvent.php index 9d4005e1..9f767466 100644 --- a/src/Event/PatchEvent.php +++ b/src/Event/PatchEvent.php @@ -11,6 +11,7 @@ use Composer\EventDispatcher\Event; use Composer\IO\IOInterface; use cweagans\Composer\Patch; +use Exception; class PatchEvent extends Event { @@ -29,18 +30,29 @@ class PatchEvent extends Event */ protected IOInterface $io; + /** + * @var Exception $error + */ + protected ?Exception $error; + /** * Constructs a PatchEvent object. * * @param string $eventName * @param Patch $patch */ - public function __construct(string $eventName, Patch $patch, Composer $composer, IOInterface $io) - { + public function __construct( + string $eventName, + Patch $patch, + Composer $composer, + IOInterface $io, + ?Exception $error = null + ) { parent::__construct($eventName); $this->patch = $patch; $this->composer = $composer; $this->io = $io; + $this->error = $error; } /** @@ -72,4 +84,14 @@ public function getIO(): IOInterface { return $this->io; } + + /** + * Returns the exception about to be thrown when a patch cannot be applied. + * + * @return Exception + */ + public function getError(): Exception + { + return $this->error; + } } diff --git a/src/Event/PatchEvents.php b/src/Event/PatchEvents.php index 2cdb552a..20b34e53 100644 --- a/src/Event/PatchEvents.php +++ b/src/Event/PatchEvents.php @@ -53,4 +53,14 @@ class PatchEvents * @var string */ public const POST_PATCH_APPLY = 'post-patch-apply'; + + + /** + * The POST_PATCH_APPLY_ERROR event occurs when a patch could not be applied by any patcher. + * + * The event listener method receives a cweagans\Composer\Event\PatchEvent instance. + * + * @var string + */ + public const POST_PATCH_APPLY_ERROR = 'post-patch-apply-error'; } diff --git a/src/Plugin/Patches.php b/src/Plugin/Patches.php index 9435e3ed..a0fe40b9 100644 --- a/src/Plugin/Patches.php +++ b/src/Plugin/Patches.php @@ -267,7 +267,12 @@ public function apply(Patch $patch, string $install_path) $status = $patcher->applyPatch($patch, $install_path); if ($status === false) { - throw new Exception("No available patcher was able to apply patch {$patch->url} to {$patch->package}"); + $e = new Exception("No available patcher was able to apply patch {$patch->url} to {$patch->package}"); + + $this->composer->getEventDispatcher()->dispatch( + PatchEvents::POST_PATCH_APPLY_ERROR, + new PatchEvent(PatchEvents::POST_PATCH_APPLY_ERROR, $patch, $this->composer, $this->io, $e) + ); } $this->composer->getEventDispatcher()->dispatch( diff --git a/tests/unit/PatchEventTest.php b/tests/unit/PatchEventTest.php index e39ec093..73b63b30 100644 --- a/tests/unit/PatchEventTest.php +++ b/tests/unit/PatchEventTest.php @@ -23,11 +23,8 @@ class PatchEventTest extends Unit * * @dataProvider patchEventDataProvider */ - public function testGetters($event_name, $patch) + public function testGetters($event_name, $patch, $composer, $io) { - $composer = new Composer(); - $io = new NullIO(); - $patch_event = new PatchEvent($event_name, $patch, $composer, $io); $this->assertEquals($event_name, $patch_event->getName()); $this->assertEquals($patch, $patch_event->getPatch()); @@ -36,13 +33,16 @@ public function testGetters($event_name, $patch) public function patchEventDataProvider() { $patch = new Patch(); + $composer = new Composer(); + $io = new NullIO(); return array( - [PatchEvents::PRE_PATCH_GUESS_DEPTH, $patch], - [PatchEvents::PRE_PATCH_APPLY, $patch], - [PatchEvents::POST_PATCH_APPLY, $patch], - [PatchEvents::PRE_PATCH_DOWNLOAD, $patch], - [PatchEvents::POST_PATCH_DOWNLOAD, $patch], + [PatchEvents::PRE_PATCH_GUESS_DEPTH, $patch, $composer, $io], + [PatchEvents::PRE_PATCH_APPLY, $patch, $composer, $io], + [PatchEvents::POST_PATCH_APPLY, $patch, $composer, $io], + [PatchEvents::PRE_PATCH_DOWNLOAD, $patch, $composer, $io], + [PatchEvents::POST_PATCH_DOWNLOAD, $patch, $composer, $io], + [PatchEvents::POST_PATCH_APPLY_ERROR, $patch, $composer, $io], ); } } From 216e521ff57885186b44443cd0816613ae0c77ff Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sat, 11 Feb 2023 22:52:03 -0700 Subject: [PATCH 4/8] Increase test coverage --- src/Event/PatchEvent.php | 4 ++-- tests/unit/PatchEventTest.php | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Event/PatchEvent.php b/src/Event/PatchEvent.php index 9f767466..fd1f1e24 100644 --- a/src/Event/PatchEvent.php +++ b/src/Event/PatchEvent.php @@ -31,7 +31,7 @@ class PatchEvent extends Event protected IOInterface $io; /** - * @var Exception $error + * @var ?Exception $error */ protected ?Exception $error; @@ -90,7 +90,7 @@ public function getIO(): IOInterface * * @return Exception */ - public function getError(): Exception + public function getError(): ?Exception { return $this->error; } diff --git a/tests/unit/PatchEventTest.php b/tests/unit/PatchEventTest.php index 73b63b30..601b576d 100644 --- a/tests/unit/PatchEventTest.php +++ b/tests/unit/PatchEventTest.php @@ -15,6 +15,7 @@ use cweagans\Composer\Event\PatchEvent; use cweagans\Composer\Event\PatchEvents; use cweagans\Composer\Patch; +use Exception; class PatchEventTest extends Unit { @@ -23,11 +24,14 @@ class PatchEventTest extends Unit * * @dataProvider patchEventDataProvider */ - public function testGetters($event_name, $patch, $composer, $io) + public function testGetters($event_name, $patch, $composer, $io, $error = null) { - $patch_event = new PatchEvent($event_name, $patch, $composer, $io); + $patch_event = new PatchEvent($event_name, $patch, $composer, $io, $error); $this->assertEquals($event_name, $patch_event->getName()); $this->assertEquals($patch, $patch_event->getPatch()); + $this->assertEquals($composer, $patch_event->getComposer()); + $this->assertEquals($io, $patch_event->getIO()); + $this->assertEquals($error, $patch_event->getError()); } public function patchEventDataProvider() @@ -35,6 +39,7 @@ public function patchEventDataProvider() $patch = new Patch(); $composer = new Composer(); $io = new NullIO(); + $e = new Exception("test"); return array( [PatchEvents::PRE_PATCH_GUESS_DEPTH, $patch, $composer, $io], @@ -42,7 +47,7 @@ public function patchEventDataProvider() [PatchEvents::POST_PATCH_APPLY, $patch, $composer, $io], [PatchEvents::PRE_PATCH_DOWNLOAD, $patch, $composer, $io], [PatchEvents::POST_PATCH_DOWNLOAD, $patch, $composer, $io], - [PatchEvents::POST_PATCH_APPLY_ERROR, $patch, $composer, $io], + [PatchEvents::POST_PATCH_APPLY_ERROR, $patch, $composer, $io, $e], ); } } From 6ac2681a5b6e731ef9b8795f0e610f4e14556306 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sat, 11 Feb 2023 22:52:38 -0700 Subject: [PATCH 5/8] The exception needs to actually be thrown --- src/Plugin/Patches.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Plugin/Patches.php b/src/Plugin/Patches.php index a0fe40b9..443cb37f 100644 --- a/src/Plugin/Patches.php +++ b/src/Plugin/Patches.php @@ -273,6 +273,8 @@ public function apply(Patch $patch, string $install_path) PatchEvents::POST_PATCH_APPLY_ERROR, new PatchEvent(PatchEvents::POST_PATCH_APPLY_ERROR, $patch, $this->composer, $this->io, $e) ); + + throw $e; } $this->composer->getEventDispatcher()->dispatch( From 30a7405909dc9a89b73885d113836771fefcc7e2 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sat, 11 Feb 2023 22:54:52 -0700 Subject: [PATCH 6/8] Increase test coverage --- tests/unit/PluginEventTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/PluginEventTest.php b/tests/unit/PluginEventTest.php index c37c1e6f..830efa24 100644 --- a/tests/unit/PluginEventTest.php +++ b/tests/unit/PluginEventTest.php @@ -28,6 +28,8 @@ public function testGetters($event_name, array $capabilities) $plugin_event = new PluginEvent($event_name, $capabilities, $composer, $io); $this->assertEquals($event_name, $plugin_event->getName()); $this->assertEquals($capabilities, $plugin_event->getCapabilities()); + $this->assertEquals($composer, $plugin_event->getComposer()); + $this->assertEquals($io, $plugin_event->getIO()); $plugin_event->setCapabilities(['something']); $this->assertEquals(['something'], $plugin_event->getCapabilities()); From 6374544c9957f4232046981ae3244cf3ad31c429 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sat, 11 Feb 2023 23:02:02 -0700 Subject: [PATCH 7/8] Add test for patch that does not apply --- .../patch-does-not-apply/composer.json | 29 +++++++++++++++++++ tests/acceptance/PatchDoesNotApplyCept.php | 15 ++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/_data/fixtures/patch-does-not-apply/composer.json create mode 100644 tests/acceptance/PatchDoesNotApplyCept.php diff --git a/tests/_data/fixtures/patch-does-not-apply/composer.json b/tests/_data/fixtures/patch-does-not-apply/composer.json new file mode 100644 index 00000000..64420945 --- /dev/null +++ b/tests/_data/fixtures/patch-does-not-apply/composer.json @@ -0,0 +1,29 @@ +{ + "name": "cweagans/composer-patches-test-project", + "description": "Project for use in cweagans/composer-patches acceptance tests.", + "type": "project", + "license": "BSD-3-Clause", + "repositories": [ + { + "type": "path", + "url": "../../../../" + } + ], + "require": { + "cweagans/composer-patches": "*@dev", + "cweagans/composer-patches-testrepo": "~1.0" + }, + "extra": { + "patches": { + "cweagans/composer-patches-testrepo": { + "Patch from a totally different project": "https://patch-diff.githubusercontent.com/raw/cweagans/awesome-diy-software/pull/4.patch" + } + } + }, + "config": { + "preferred-install": "source", + "allow-plugins": { + "cweagans/composer-patches": true + } + } +} diff --git a/tests/acceptance/PatchDoesNotApplyCept.php b/tests/acceptance/PatchDoesNotApplyCept.php new file mode 100644 index 00000000..7f0ff438 --- /dev/null +++ b/tests/acceptance/PatchDoesNotApplyCept.php @@ -0,0 +1,15 @@ +wantTo('see an error when I try to apply a patch that does not apply'); +$I->amInPath(codecept_data_dir('fixtures/patch-does-not-apply')); +$I->runComposerCommand('install', ['-vvv'], false); +$I->seeInComposerOutput("1 out of 1 hunk FAILED"); +$I->seeInComposerOutput("No available patcher was able to apply patch"); +$I->seeInComposerOutput("Exception trace"); From e317b8c145643f374a059b76eadaf60a6bc3a659 Mon Sep 17 00:00:00 2001 From: Cameron Eagans Date: Sat, 11 Feb 2023 23:03:48 -0700 Subject: [PATCH 8/8] Patch debug output only shows up when --debug is passed to codecept, so we cannot count on that in the composer output --- tests/acceptance/PatchDoesNotApplyCept.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/acceptance/PatchDoesNotApplyCept.php b/tests/acceptance/PatchDoesNotApplyCept.php index 7f0ff438..a709a0f0 100644 --- a/tests/acceptance/PatchDoesNotApplyCept.php +++ b/tests/acceptance/PatchDoesNotApplyCept.php @@ -10,6 +10,5 @@ $I->wantTo('see an error when I try to apply a patch that does not apply'); $I->amInPath(codecept_data_dir('fixtures/patch-does-not-apply')); $I->runComposerCommand('install', ['-vvv'], false); -$I->seeInComposerOutput("1 out of 1 hunk FAILED"); $I->seeInComposerOutput("No available patcher was able to apply patch"); $I->seeInComposerOutput("Exception trace");