Skip to content
Snippets Groups Projects
Commit 5d1aa914 authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3247478 by tedbow, phenaproxima: Only pre-operation events should be...

Issue #3247478 by tedbow, phenaproxima: Only pre-operation events should be able to flag errors that stop an update
parent 0361e19b
No related branches found
No related tags found
1 merge request!114Issue #3247478: Determine how to handle validation error in Post events
Showing
with 158 additions and 76 deletions
<?php
namespace Drupal\package_manager\Event;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Defines an interface for events which can collect validation errors.
*/
interface ErrorEventInterface {
/**
* Adds a validation error.
*
* @param \Drupal\Core\StringTranslation\TranslatableMarkup[] $messages
* The error messages.
* @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $summary
* (optional) The summary.
*/
public function addError(array $messages, TranslatableMarkup $summary = NULL);
}
...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event; ...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired after staged changes are synced to the active directory. * Event fired after staged changes are synced to the active directory.
*/ */
class PostApplyEvent extends StageEvent { class PostApplyEvent extends PostOperationStageEvent {
} }
...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event; ...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired after a staging area has been created. * Event fired after a staging area has been created.
*/ */
class PostCreateEvent extends StageEvent { class PostCreateEvent extends PostOperationStageEvent {
} }
...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event; ...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired after the staging area is destroyed. * Event fired after the staging area is destroyed.
*/ */
class PostDestroyEvent extends StageEvent { class PostDestroyEvent extends PostOperationStageEvent {
} }
<?php
namespace Drupal\package_manager\Event;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\package_manager\ValidationResult;
/**
* Base class for events dispatched after a stage life cycle operation.
*/
abstract class PostOperationStageEvent extends StageEvent implements WarningEventInterface {
/**
* {@inheritdoc}
*/
public function addWarning(array $messages, ?TranslatableMarkup $summary = NULL) {
$this->results[] = ValidationResult::createWarning($messages, $summary);
}
}
...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event; ...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired after packages are added to the staging area. * Event fired after packages are added to the staging area.
*/ */
class PostRequireEvent extends StageEvent { class PostRequireEvent extends PostOperationStageEvent {
} }
...@@ -5,7 +5,7 @@ namespace Drupal\package_manager\Event; ...@@ -5,7 +5,7 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired before staged changes are synced to the active directory. * Event fired before staged changes are synced to the active directory.
*/ */
class PreApplyEvent extends StageEvent { class PreApplyEvent extends PreOperationStageEvent {
use ExcludedPathsTrait; use ExcludedPathsTrait;
......
...@@ -5,7 +5,7 @@ namespace Drupal\package_manager\Event; ...@@ -5,7 +5,7 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired before a staging area is created. * Event fired before a staging area is created.
*/ */
class PreCreateEvent extends StageEvent { class PreCreateEvent extends PreOperationStageEvent {
use ExcludedPathsTrait; use ExcludedPathsTrait;
......
...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event; ...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired before the staging area is destroyed. * Event fired before the staging area is destroyed.
*/ */
class PreDestroyEvent extends StageEvent { class PreDestroyEvent extends PreOperationStageEvent {
} }
<?php
namespace Drupal\package_manager\Event;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\package_manager\ValidationResult;
/**
* Base class for events dispatched before a stage life cycle operation.
*/
abstract class PreOperationStageEvent extends StageEvent implements ErrorEventInterface {
/**
* {@inheritdoc}
*/
public function addError(array $messages, ?TranslatableMarkup $summary = NULL) {
$this->results[] = ValidationResult::createError($messages, $summary);
}
}
...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event; ...@@ -5,5 +5,5 @@ namespace Drupal\package_manager\Event;
/** /**
* Event fired before packages are added to the staging area. * Event fired before packages are added to the staging area.
*/ */
class PreRequireEvent extends StageEvent { class PreRequireEvent extends PreOperationStageEvent {
} }
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
namespace Drupal\package_manager\Event; namespace Drupal\package_manager\Event;
use Drupal\package_manager\Stage; use Drupal\package_manager\Stage;
use Drupal\package_manager\ValidationResult;
use Symfony\Contracts\EventDispatcher\Event; use Symfony\Contracts\EventDispatcher\Event;
/** /**
...@@ -64,14 +63,4 @@ abstract class StageEvent extends Event { ...@@ -64,14 +63,4 @@ abstract class StageEvent extends Event {
return $this->results; return $this->results;
} }
/**
* Adds a validation result.
*
* @param \Drupal\package_manager\ValidationResult $validation_result
* The validation result.
*/
public function addValidationResult(ValidationResult $validation_result): void {
$this->results[] = $validation_result;
}
} }
<?php
namespace Drupal\package_manager\Event;
use Drupal\Core\StringTranslation\TranslatableMarkup;
/**
* Defines an interface for events which can collect validation warnings.
*/
interface WarningEventInterface {
/**
* Adds a warning.
*
* @param array $messages
* The warning messages.
* @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $summary
* (optional) The summary.
*/
public function addWarning(array $messages, TranslatableMarkup $summary = NULL);
}
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
namespace Drupal\package_manager\EventSubscriber; namespace Drupal\package_manager\EventSubscriber;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\StageEvent; use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\Core\Extension\ExtensionVersion; use Drupal\Core\Extension\ExtensionVersion;
use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\StringTranslation\TranslationInterface;
...@@ -15,7 +14,7 @@ use PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface; ...@@ -15,7 +14,7 @@ use PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface;
/** /**
* Validates that the Composer executable can be found in the correct version. * Validates that the Composer executable can be found in the correct version.
*/ */
class ComposerExecutableValidator implements StageValidatorInterface, ProcessOutputCallbackInterface { class ComposerExecutableValidator implements PreOperationStageValidatorInterface, ProcessOutputCallbackInterface {
use StringTranslationTrait; use StringTranslationTrait;
...@@ -49,15 +48,14 @@ class ComposerExecutableValidator implements StageValidatorInterface, ProcessOut ...@@ -49,15 +48,14 @@ class ComposerExecutableValidator implements StageValidatorInterface, ProcessOut
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validateStage(StageEvent $event): void { public function validateStagePreOperation(PreOperationStageEvent $event): void {
try { try {
$this->composer->run(['--version'], $this); $this->composer->run(['--version'], $this);
} }
catch (ExceptionInterface $e) { catch (ExceptionInterface $e) {
$error = ValidationResult::createError([ $event->addError([
$e->getMessage(), $e->getMessage(),
]); ]);
$event->addValidationResult($error);
return; return;
} }
...@@ -66,19 +64,17 @@ class ComposerExecutableValidator implements StageValidatorInterface, ProcessOut ...@@ -66,19 +64,17 @@ class ComposerExecutableValidator implements StageValidatorInterface, ProcessOut
->getMajorVersion(); ->getMajorVersion();
if ($major_version < 2) { if ($major_version < 2) {
$error = ValidationResult::createError([ $event->addError([
$this->t('Composer 2 or later is required, but version @version was detected.', [ $this->t('Composer 2 or later is required, but version @version was detected.', [
'@version' => $this->version, '@version' => $this->version,
]), ]),
]); ]);
$event->addValidationResult($error);
} }
} }
else { else {
$error = ValidationResult::createError([ $event->addError([
$this->t('The Composer version could not be detected.'), $this->t('The Composer version could not be detected.'),
]); ]);
$event->addValidationResult($error);
} }
} }
...@@ -87,7 +83,7 @@ class ComposerExecutableValidator implements StageValidatorInterface, ProcessOut ...@@ -87,7 +83,7 @@ class ComposerExecutableValidator implements StageValidatorInterface, ProcessOut
*/ */
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [ return [
PreCreateEvent::class => 'validateStage', PreCreateEvent::class => 'validateStagePreOperation',
]; ];
} }
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
namespace Drupal\package_manager\EventSubscriber; namespace Drupal\package_manager\EventSubscriber;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\StageEvent; use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\Component\FileSystem\FileSystem; use Drupal\Component\FileSystem\FileSystem;
use Drupal\Component\Utility\Bytes; use Drupal\Component\Utility\Bytes;
use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\StringTranslationTrait;
...@@ -14,7 +13,7 @@ use Drupal\package_manager\PathLocator; ...@@ -14,7 +13,7 @@ use Drupal\package_manager\PathLocator;
/** /**
* Validates that there is enough free disk space to do automatic updates. * Validates that there is enough free disk space to do automatic updates.
*/ */
class DiskSpaceValidator implements StageValidatorInterface { class DiskSpaceValidator implements PreOperationStageValidatorInterface {
use StringTranslationTrait; use StringTranslationTrait;
...@@ -99,7 +98,7 @@ class DiskSpaceValidator implements StageValidatorInterface { ...@@ -99,7 +98,7 @@ class DiskSpaceValidator implements StageValidatorInterface {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validateStage(StageEvent $event): void { public function validateStagePreOperation(PreOperationStageEvent $event): void {
$root_path = $this->pathLocator->getProjectRoot(); $root_path = $this->pathLocator->getProjectRoot();
$vendor_path = $this->pathLocator->getVendorDirectory(); $vendor_path = $this->pathLocator->getVendorDirectory();
$messages = []; $messages = [];
...@@ -140,9 +139,7 @@ class DiskSpaceValidator implements StageValidatorInterface { ...@@ -140,9 +139,7 @@ class DiskSpaceValidator implements StageValidatorInterface {
$summary = count($messages) > 1 $summary = count($messages) > 1
? $this->t("There is not enough disk space to create a staging area.") ? $this->t("There is not enough disk space to create a staging area.")
: NULL; : NULL;
$event->addError($messages, $summary);
$error = ValidationResult::createError($messages, $summary);
$event->addValidationResult($error);
} }
} }
...@@ -161,7 +158,7 @@ class DiskSpaceValidator implements StageValidatorInterface { ...@@ -161,7 +158,7 @@ class DiskSpaceValidator implements StageValidatorInterface {
*/ */
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [ return [
PreCreateEvent::class => 'validateStage', PreCreateEvent::class => 'validateStagePreOperation',
]; ];
} }
......
...@@ -8,15 +8,14 @@ use Drupal\Core\StringTranslation\TranslationInterface; ...@@ -8,15 +8,14 @@ use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\package_manager\Event\PostDestroyEvent; use Drupal\package_manager\Event\PostDestroyEvent;
use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\PreApplyEvent;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\Event\PreRequireEvent; use Drupal\package_manager\Event\PreRequireEvent;
use Drupal\package_manager\Event\StageEvent;
use Drupal\package_manager\PathLocator; use Drupal\package_manager\PathLocator;
use Drupal\package_manager\ValidationResult;
/** /**
* Checks that the active lock file is unchanged during stage operations. * Checks that the active lock file is unchanged during stage operations.
*/ */
class LockFileValidator implements StageValidatorInterface { class LockFileValidator implements PreOperationStageValidatorInterface {
use StringTranslationTrait; use StringTranslationTrait;
...@@ -87,17 +86,16 @@ class LockFileValidator implements StageValidatorInterface { ...@@ -87,17 +86,16 @@ class LockFileValidator implements StageValidatorInterface {
$this->state->set(static::STATE_KEY, $hash); $this->state->set(static::STATE_KEY, $hash);
} }
else { else {
$result = ValidationResult::createError([ $event->addError([
$this->t('Could not hash the active lock file.'), $this->t('Could not hash the active lock file.'),
]); ]);
$event->addValidationResult($result);
} }
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validateStage(StageEvent $event): void { public function validateStagePreOperation(PreOperationStageEvent $event): void {
// Ensure we can get a current hash of the lock file. // Ensure we can get a current hash of the lock file.
$hash = $this->getHash(); $hash = $this->getHash();
if (empty($hash)) { if (empty($hash)) {
...@@ -118,8 +116,7 @@ class LockFileValidator implements StageValidatorInterface { ...@@ -118,8 +116,7 @@ class LockFileValidator implements StageValidatorInterface {
// @todo Let the validation result carry all the relevant messages in // @todo Let the validation result carry all the relevant messages in
// https://www.drupal.org/i/3247479. // https://www.drupal.org/i/3247479.
if (isset($error)) { if (isset($error)) {
$result = ValidationResult::createError([$error]); $event->addError([$error]);
$event->addValidationResult($result);
} }
} }
...@@ -136,8 +133,8 @@ class LockFileValidator implements StageValidatorInterface { ...@@ -136,8 +133,8 @@ class LockFileValidator implements StageValidatorInterface {
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [ return [
PreCreateEvent::class => 'storeHash', PreCreateEvent::class => 'storeHash',
PreRequireEvent::class => 'validateStage', PreRequireEvent::class => 'validateStagePreOperation',
PreApplyEvent::class => 'validateStage', PreApplyEvent::class => 'validateStagePreOperation',
PostDestroyEvent::class => 'deleteHash', PostDestroyEvent::class => 'deleteHash',
]; ];
} }
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
namespace Drupal\package_manager\EventSubscriber; namespace Drupal\package_manager\EventSubscriber;
use Drupal\package_manager\Event\PreCreateEvent; use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\StageEvent; use Drupal\package_manager\Event\PreOperationStageEvent;
use Drupal\package_manager\ValidationResult;
use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Update\UpdateRegistry; use Drupal\Core\Update\UpdateRegistry;
...@@ -13,7 +12,7 @@ use Drupal\Core\Url; ...@@ -13,7 +12,7 @@ use Drupal\Core\Url;
/** /**
* Validates that there are no pending database updates. * Validates that there are no pending database updates.
*/ */
class PendingUpdatesValidator implements StageValidatorInterface { class PendingUpdatesValidator implements PreOperationStageValidatorInterface {
use StringTranslationTrait; use StringTranslationTrait;
...@@ -50,7 +49,7 @@ class PendingUpdatesValidator implements StageValidatorInterface { ...@@ -50,7 +49,7 @@ class PendingUpdatesValidator implements StageValidatorInterface {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function validateStage(StageEvent $event): void { public function validateStagePreOperation(PreOperationStageEvent $event): void {
require_once $this->appRoot . '/core/includes/install.inc'; require_once $this->appRoot . '/core/includes/install.inc';
require_once $this->appRoot . '/core/includes/update.inc'; require_once $this->appRoot . '/core/includes/update.inc';
...@@ -62,8 +61,7 @@ class PendingUpdatesValidator implements StageValidatorInterface { ...@@ -62,8 +61,7 @@ class PendingUpdatesValidator implements StageValidatorInterface {
$message = $this->t('Some modules have database schema updates to install. You should run the <a href=":update">database update script</a> immediately.', [ $message = $this->t('Some modules have database schema updates to install. You should run the <a href=":update">database update script</a> immediately.', [
':update' => Url::fromRoute('system.db_update')->toString(), ':update' => Url::fromRoute('system.db_update')->toString(),
]); ]);
$error = ValidationResult::createError([$message]); $event->addError([$message]);
$event->addValidationResult($error);
} }
} }
...@@ -72,7 +70,7 @@ class PendingUpdatesValidator implements StageValidatorInterface { ...@@ -72,7 +70,7 @@ class PendingUpdatesValidator implements StageValidatorInterface {
*/ */
public static function getSubscribedEvents() { public static function getSubscribedEvents() {
return [ return [
PreCreateEvent::class => 'validateStage', PreCreateEvent::class => 'validateStagePreOperation',
]; ];
} }
......
<?php
namespace Drupal\package_manager\EventSubscriber;
use Drupal\package_manager\Event\PostOperationStageEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Defines an interface for classes that validate a stage after an operation.
*/
interface PostOperationStageValidatorInterface extends EventSubscriberInterface {
/**
* Validates a stage after an operation.
*
* @param \Drupal\package_manager\Event\PostOperationStageEvent $event
* The stage event.
*/
public function validateStagePostOperation(PostOperationStageEvent $event): void;
}
<?php
namespace Drupal\package_manager\EventSubscriber;
use Drupal\package_manager\Event\PreOperationStageEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Defines an interface for classes that validate a stage before an operation.
*/
interface PreOperationStageValidatorInterface extends EventSubscriberInterface {
/**
* Validates a stage before an operation.
*
* @param \Drupal\package_manager\Event\PreOperationStageEvent $event
* The stage event.
*/
public function validateStagePreOperation(PreOperationStageEvent $event): void;
}
<?php
namespace Drupal\package_manager\EventSubscriber;
use Drupal\package_manager\Event\StageEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Defines an interface for services that validate a stage over its life cycle.
*/
interface StageValidatorInterface extends EventSubscriberInterface {
/**
* Validates a stage at various points during its life cycle.
*
* @param \Drupal\package_manager\Event\StageEvent $event
* The event object.
*/
public function validateStage(StageEvent $event): void;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment