From 94803912f6691b249fb526e3a0210ae74f8200a9 Mon Sep 17 00:00:00 2001 From: tedbow <tedbow@240860.no-reply.drupal.org> Date: Wed, 13 Oct 2021 14:32:39 +0000 Subject: [PATCH] Issue #3241105 by phenaproxima, tedbow: Ensure core package is validated in readiness check and pre-start --- automatic_updates.services.yml | 4 ++ package_manager/src/ComposerUtility.php | 12 ---- src/Validator/CoreComposerValidator.php | 49 +++++++++++++++ .../no_core_requirements/composer.json | 15 +++++ .../CoreComposerValidatorTest.php | 60 +++++++++++++++++++ 5 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 src/Validator/CoreComposerValidator.php create mode 100644 tests/fixtures/project_staged_validation/no_core_requirements/composer.json create mode 100644 tests/src/Kernel/ReadinessValidation/CoreComposerValidatorTest.php diff --git a/automatic_updates.services.yml b/automatic_updates.services.yml index 51d5714ee9..d908294df4 100644 --- a/automatic_updates.services.yml +++ b/automatic_updates.services.yml @@ -74,6 +74,10 @@ services: - '%app.root%' tags: - { name: event_subscriber } + automatic_updates.validator.core_composer: + class: Drupal\automatic_updates\Validator\CoreComposerValidator + tags: + - { name: event_subscriber } automatic_updates.path_locator: class: Drupal\automatic_updates\PathLocator arguments: diff --git a/package_manager/src/ComposerUtility.php b/package_manager/src/ComposerUtility.php index 9404cbc11f..121d067647 100644 --- a/package_manager/src/ComposerUtility.php +++ b/package_manager/src/ComposerUtility.php @@ -99,18 +99,6 @@ class ComposerUtility { */ public function getCorePackageNames(): array { $requirements = array_keys($this->composer->getPackage()->getRequires()); - - // Ensure that either drupal/core or drupal/core-recommended are required. - // If neither is, then core cannot be updated, which we consider an error - // condition. - // @todo Move this check to an update validator as part of - // https://www.drupal.org/project/automatic_updates/issues/3241105 - $core_requirements = array_intersect(['drupal/core', 'drupal/core-recommended'], $requirements); - if (empty($core_requirements)) { - $file = $this->composer->getConfig()->getConfigSource()->getName(); - throw new \LogicException("Drupal core does not appear to be required in $file."); - } - return array_intersect(static::getCorePackageList(), $requirements); } diff --git a/src/Validator/CoreComposerValidator.php b/src/Validator/CoreComposerValidator.php new file mode 100644 index 0000000000..928da62046 --- /dev/null +++ b/src/Validator/CoreComposerValidator.php @@ -0,0 +1,49 @@ +<?php + +namespace Drupal\automatic_updates\Validator; + +use Drupal\automatic_updates\AutomaticUpdatesEvents; +use Drupal\automatic_updates\Event\ReadinessCheckEvent; +use Drupal\automatic_updates\Validation\ValidationResult; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Validates the Drupal core requirements defined in composer.json. + */ +class CoreComposerValidator implements EventSubscriberInterface { + + use StringTranslationTrait; + + /** + * Validates the Drupal core requirements in composer.json. + * + * @param \Drupal\automatic_updates\Event\ReadinessCheckEvent $event + * The event object. + */ + public function checkCoreRequirements(ReadinessCheckEvent $event): void { + // Ensure that either drupal/core or drupal/core-recommended is required. + // If neither is, then core cannot be updated, which we consider an error + // condition. + $core_requirements = array_intersect( + $event->getActiveComposer()->getCorePackageNames(), + ['drupal/core', 'drupal/core-recommended'] + ); + if (empty($core_requirements)) { + $error = ValidationResult::createError([ + $this->t('Drupal core does not appear to be required in the project-level composer.json.'), + ]); + $event->addValidationResult($error); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + return [ + AutomaticUpdatesEvents::READINESS_CHECK => ['checkCoreRequirements', 1000], + ]; + } + +} diff --git a/tests/fixtures/project_staged_validation/no_core_requirements/composer.json b/tests/fixtures/project_staged_validation/no_core_requirements/composer.json new file mode 100644 index 0000000000..157b54bc9a --- /dev/null +++ b/tests/fixtures/project_staged_validation/no_core_requirements/composer.json @@ -0,0 +1,15 @@ +{ + "require": { + "drupal/core-composer-scaffold": "*", + "drupal/core-vendor-hardening": "*", + "drupal/core-project-message": "*", + "drupal/core-dev": "*", + "drupal/core-dev-pinned": "*" + }, + "extra": { + "_comment": [ + "This is an example composer.json that does not require Drupal core.", + "@see \\Drupal\\Tests\\automatic_updates\\Kernel\\ReadinessValidation\\RequirementsValidatorTest" + ] + } +} diff --git a/tests/src/Kernel/ReadinessValidation/CoreComposerValidatorTest.php b/tests/src/Kernel/ReadinessValidation/CoreComposerValidatorTest.php new file mode 100644 index 0000000000..bb1ad91372 --- /dev/null +++ b/tests/src/Kernel/ReadinessValidation/CoreComposerValidatorTest.php @@ -0,0 +1,60 @@ +<?php + +namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation; + +use Drupal\automatic_updates\PathLocator; +use Drupal\automatic_updates\Validation\ValidationResult; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Tests\automatic_updates\Kernel\AutomaticUpdatesKernelTestBase; +use Drupal\Tests\automatic_updates\Traits\ValidationTestTrait; + +/** + * @covers \Drupal\automatic_updates\Validator\CoreComposerValidator + * + * @group automatic_updates + */ +class CoreComposerValidatorTest extends AutomaticUpdatesKernelTestBase { + + use ValidationTestTrait; + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'automatic_updates', + 'package_manager', + ]; + + /** + * {@inheritdoc} + */ + public function register(ContainerBuilder $container) { + parent::register($container); + // Disable validators which interfere with the validator under test. + $container->removeDefinition('automatic_updates.disk_space_validator'); + } + + /** + * Tests that an error is raised if core is not required in composer.json. + */ + public function testCoreNotRequired(): void { + $this->installConfig('update'); + $this->setCoreVersion('9.8.0'); + $this->setReleaseMetadata(__DIR__ . '/../../../fixtures/release-history/drupal.9.8.1.xml'); + + // Point to a valid composer.json with no requirements. + $locator = $this->prophesize(PathLocator::class); + $locator->getActiveDirectory()->willReturn(__DIR__ . '/../../../fixtures/project_staged_validation/no_core_requirements'); + $this->container->set('automatic_updates.path_locator', $locator->reveal()); + + $results = $this->container->get('automatic_updates.readiness_validation_manager') + ->run() + ->getResults(); + + $error = ValidationResult::createError([ + 'Drupal core does not appear to be required in the project-level composer.json.', + ]); + $this->assertValidationResultsEqual([$error], $results); + } + +} -- GitLab