diff --git a/package_manager/src/Stage.php b/package_manager/src/Stage.php index f1357ff3f9544a1d002ddaafa520fbe98eb7e491..6a3c1feabc398047427f638a0aa56d7509c9167b 100644 --- a/package_manager/src/Stage.php +++ b/package_manager/src/Stage.php @@ -370,7 +370,13 @@ class Stage implements LoggerAwareInterface { $active_dir = $this->pathFactory->create($this->pathLocator->getProjectRoot()); $stage_dir = $this->pathFactory->create($this->getStageDirectory()); - $event = new PreCreateEvent($this, $this->getIgnoredPaths()); + try { + $ignored_paths = $this->getIgnoredPaths(); + } + catch (\Exception $e) { + throw new StageException($e->getMessage()); + } + $event = new PreCreateEvent($this, $ignored_paths); // If an error occurs and we won't be able to create the stage, mark it as // available. $this->dispatch($event, [$this, 'markAsAvailable']); @@ -449,10 +455,17 @@ class Stage implements LoggerAwareInterface { $active_dir = $this->pathFactory->create($this->pathLocator->getProjectRoot()); $stage_dir = $this->pathFactory->create($this->getStageDirectory()); + try { + $ignored_paths = $this->getIgnoredPaths(); + } + catch (\Exception $e) { + throw new StageException($e->getMessage()); + } + // If an error occurs while dispatching the events, ensure that ::destroy() // doesn't think we're in the middle of applying the staged changes to the // active directory. - $event = new PreApplyEvent($this, $this->getIgnoredPaths()); + $event = new PreApplyEvent($this, $ignored_paths); $this->tempStore->set(self::TEMPSTORE_APPLY_TIME_KEY, $this->time->getRequestTime()); $this->dispatch($event, $this->setNotApplying()); diff --git a/package_manager/tests/modules/package_manager_test_validation/package_manager_test_validation.services.yml b/package_manager/tests/modules/package_manager_test_validation/package_manager_test_validation.services.yml index f9a59946f6cafa34c8d5c1b9d2d0c480aefb9198..7ce1b0b1cabe2cd1bfe9ca5c8199204e692053ac 100644 --- a/package_manager/tests/modules/package_manager_test_validation/package_manager_test_validation.services.yml +++ b/package_manager/tests/modules/package_manager_test_validation/package_manager_test_validation.services.yml @@ -5,3 +5,7 @@ services: - '@state' tags: - { name: event_subscriber } + package_manager.validator.collect_ignored_paths_fail: + class: Drupal\package_manager_test_validation\CollectIgnoredPathsFailValidator + tags: + - { name: event_subscriber } diff --git a/package_manager/tests/modules/package_manager_test_validation/src/CollectIgnoredPathsFailValidator.php b/package_manager/tests/modules/package_manager_test_validation/src/CollectIgnoredPathsFailValidator.php new file mode 100644 index 0000000000000000000000000000000000000000..425df19ba829a9f7d8082dbc2f1b8d52f5f77ead --- /dev/null +++ b/package_manager/tests/modules/package_manager_test_validation/src/CollectIgnoredPathsFailValidator.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types = 1); + +namespace Drupal\package_manager_test_validation; + +use Drupal\package_manager\Event\CollectIgnoredPathsEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Allows to test an excluder which fails on CollectIgnoredPathsEvent. + */ +class CollectIgnoredPathsFailValidator implements EventSubscriberInterface { + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array { + return [ + CollectIgnoredPathsEvent::class => 'callToComposer', + ]; + } + + /** + * Fails when composer.json is deleted to simulate failure on excluders. + */ + public function callToComposer(CollectIgnoredPathsEvent $event) { + $event->getStage()->getActiveComposer(); + } + +} diff --git a/package_manager/tests/src/Kernel/ComposerJsonExistsValidatorTest.php b/package_manager/tests/src/Kernel/ComposerJsonExistsValidatorTest.php index e5604330df416a3a8c2e199c0a868626d70b4ee7..4a3434f13ea7b4d169d6d73b2e1bc8bb9ddd9cd9 100644 --- a/package_manager/tests/src/Kernel/ComposerJsonExistsValidatorTest.php +++ b/package_manager/tests/src/Kernel/ComposerJsonExistsValidatorTest.php @@ -6,6 +6,7 @@ namespace Drupal\Tests\package_manager\Kernel; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\PreCreateEvent; +use Drupal\package_manager\Event\StageEvent; use Drupal\package_manager\Event\StatusCheckEvent; use Drupal\package_manager\ValidationResult; @@ -15,28 +16,43 @@ use Drupal\package_manager\ValidationResult; */ class ComposerJsonExistsValidatorTest extends PackageManagerKernelTestBase { + /** + * {@inheritdoc} + */ + protected static $modules = ['package_manager_test_validation']; + /** * Tests validation when the active composer.json is not present. */ public function testComposerRequirement(): void { - unlink($this->container->get('package_manager.path_locator') - ->getProjectRoot() . '/composer.json'); - $result = ValidationResult::createError([ - 'No composer.json file can be found at <PROJECT_ROOT>', + $listener = function (StageEvent $event): void { + unlink($this->container->get('package_manager.path_locator') + ->getProjectRoot() . '/composer.json'); + }; + $this->addEventTestListener($listener, PreCreateEvent::class, 1000); + $result = ValidationResult::createError([t( + 'No composer.json file can be found at <PROJECT_ROOT>'), ]); foreach ([PreCreateEvent::class, StatusCheckEvent::class] as $event_class) { $this->assertEventPropagationStopped($event_class, [$this->container->get('package_manager.validator.composer_json_exists'), 'validateComposerJson']); } - $this->assertStatusCheckResults([$result]); $this->assertResults([$result], PreCreateEvent::class); + $result = ValidationResult::createError( + [ + t("Composer could not find the config file: <PROJECT_ROOT>/composer.json\n"), + ], + t("Unable to collect ignored paths, therefore can't perform status checks.") + ); + + $this->assertStatusCheckResults([$result]); } /** * Tests that active composer.json is not present during pre-apply. */ public function testComposerRequirementDuringPreApply(): void { - $result = ValidationResult::createError([ - 'No composer.json file can be found at <PROJECT_ROOT>', + $result = ValidationResult::createError([t( + 'No composer.json file can be found at <PROJECT_ROOT>'), ]); $this->addEventTestListener(function (): void { unlink($this->container->get('package_manager.path_locator') diff --git a/package_manager/tests/src/Kernel/StageTest.php b/package_manager/tests/src/Kernel/StageTest.php index 01e4178ebf75ad508b96272851886f85c3de4cf7..702ae743fdb6688942f2de80f81e8370836bf7b5 100644 --- a/package_manager/tests/src/Kernel/StageTest.php +++ b/package_manager/tests/src/Kernel/StageTest.php @@ -32,6 +32,11 @@ use ColinODell\PsrTestLogger\TestLogger; */ class StageTest extends PackageManagerKernelTestBase { + /** + * {@inheritdoc} + */ + protected static $modules = ['package_manager_test_validation']; + /** * {@inheritdoc} */ @@ -523,6 +528,32 @@ class StageTest extends PackageManagerKernelTestBase { $this->assertTrue($asserted); } + /** + * Tests that if a stage fails to get ignored paths, throws a stage exception. + */ + public function testFailureCollectIgnoredPaths(): void { + $project_root = $this->container->get('package_manager.path_locator') + ->getProjectRoot(); + unlink($project_root . '/composer.json'); + $this->expectException(StageException::class); + $this->expectExceptionMessage("Composer could not find the config file: $project_root/composer.json\n"); + $stage = $this->createStage(); + $stage->create(); + } + + /** + * Tests that if apply fails to get ignored paths, throws a stage exception. + */ + public function testFailureCollectIgnoredPathsOnApply(): void { + $stage = $this->createStage(); + $stage->create(); + $stage->require(['drupal/random']); + $this->expectException(StageException::class); + $this->expectExceptionMessage("Composer could not find the config file: " . $stage->getStageDirectory() . "/composer.json\n"); + unlink($stage->getStageDirectory() . '/composer.json'); + $stage->apply(); + } + } /**