Skip to content
Snippets Groups Projects
Commit 6a3f2d7c authored by Ted Bowman's avatar Ted Bowman Committed by Adam G-H
Browse files

Issue #3255320 by tedbow, phenaproxima: ReadinessCheckEvent should have...

Issue #3255320 by tedbow, phenaproxima: ReadinessCheckEvent should have CronUpdater instance when cron will run
parent ee34db21
No related branches found
No related tags found
1 merge request!154Issue #3255320: ReadinessCheckEvent should have CronUpdater instance if cron updates are enabled
......@@ -6,6 +6,8 @@ services:
- '@datetime.time'
- '@event_dispatcher'
- '@automatic_updates.updater'
- '@automatic_updates.cron_updater'
- '@config.factory'
- 24
automatic_updates.updater:
class: Drupal\automatic_updates\Updater
......
......@@ -33,13 +33,24 @@ class ReadinessCheckEvent extends PreOperationStageEvent {
*
* @param \Drupal\automatic_updates\Updater $updater
* The updater service.
* @param string[] $package_versions
* (optional) The desired package versions to update to, keyed by package
* @param string[] $project_versions
* (optional) The versions of the packages to update to, keyed by package
* name.
*/
public function __construct(Updater $updater, array $package_versions = []) {
public function __construct(Updater $updater, array $project_versions = []) {
parent::__construct($updater);
$this->packageVersions = $package_versions;
if ($project_versions) {
if (count($project_versions) !== 1 || !array_key_exists('drupal', $project_versions)) {
throw new \InvalidArgumentException("Currently only updates to Drupal core are supported.");
}
$core_packages = $this->getStage()->getActiveComposer()->getCorePackageNames();
// Update all core packages to the same version.
$package_versions = array_fill(0, count($core_packages), $project_versions['drupal']);
$this->packageVersions = array_combine($core_packages, $package_versions);
}
else {
$this->packageVersions = [];
}
}
/**
......
......@@ -3,8 +3,10 @@
namespace Drupal\automatic_updates\Form;
use Drupal\automatic_updates\BatchProcessor;
use Drupal\automatic_updates\Event\ReadinessCheckEvent;
use Drupal\automatic_updates\Updater;
use Drupal\automatic_updates\UpdateRecommender;
use Drupal\automatic_updates\Validation\ReadinessTrait;
use Drupal\automatic_updates\Validation\ReadinessValidationManager;
use Drupal\Core\Batch\BatchBuilder;
use Drupal\Core\Form\FormBase;
......@@ -15,6 +17,7 @@ use Drupal\Core\Url;
use Drupal\system\SystemManager;
use Drupal\update\UpdateManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Defines a form to update Drupal core.
......@@ -24,6 +27,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class UpdaterForm extends FormBase {
use ReadinessTrait;
/**
* The updater service.
*
......@@ -45,6 +50,13 @@ class UpdaterForm extends FormBase {
*/
protected $readinessValidationManager;
/**
* The event dispatcher service.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* Constructs a new UpdaterForm object.
*
......@@ -54,11 +66,14 @@ class UpdaterForm extends FormBase {
* The updater service.
* @param \Drupal\automatic_updates\Validation\ReadinessValidationManager $readiness_validation_manager
* The readiness validation manager service.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher service.
*/
public function __construct(StateInterface $state, Updater $updater, ReadinessValidationManager $readiness_validation_manager) {
public function __construct(StateInterface $state, Updater $updater, ReadinessValidationManager $readiness_validation_manager, EventDispatcherInterface $event_dispatcher) {
$this->updater = $updater;
$this->state = $state;
$this->readinessValidationManager = $readiness_validation_manager;
$this->eventDispatcher = $event_dispatcher;
}
/**
......@@ -75,7 +90,8 @@ class UpdaterForm extends FormBase {
return new static(
$container->get('state'),
$container->get('automatic_updates.updater'),
$container->get('automatic_updates.readiness_validation_manager')
$container->get('automatic_updates.readiness_validation_manager'),
$container->get('event_dispatcher')
);
}
......@@ -182,17 +198,18 @@ class UpdaterForm extends FormBase {
],
];
// @todo Add a hasErrors() or getErrors() method to
// ReadinessValidationManager to make validation more introspectable.
// Re-running the readiness checks now should mean that when we display
// cached errors in automatic_updates_page_top(), we'll see errors that
// were raised during this run, instead of any previously cached results.
$errors = $this->readinessValidationManager->run()
->getResults(SystemManager::REQUIREMENT_ERROR);
if (empty($errors)) {
$results = $this->getReadinessErrors($recommended_release->getVersion());
if (empty($results)) {
$form['actions'] = $this->actions($form_state);
}
else {
$this->messenger()->addError($this->getFailureMessageForSeverity(SystemManager::REQUIREMENT_ERROR));
foreach ($results as $result) {
$messages = $result->getMessages();
$message = count($messages) === 1 ? $messages[0] : $result->getSummary();
$this->messenger()->addError($message);
}
}
return $form;
}
......@@ -256,4 +273,19 @@ class UpdaterForm extends FormBase {
batch_set($batch);
}
/**
* Gets validation errors before an update begins.
*
* @param string $update_version
* The version of Drupal to which we will update.
*
* @return \Drupal\package_manager\ValidationResult[]
* The error validation results.
*/
private function getReadinessErrors(string $update_version): array {
$event = new ReadinessCheckEvent($this->updater, ['drupal' => $update_version]);
$this->eventDispatcher->dispatch($event);
return $event->getResults(SystemManager::REQUIREMENT_ERROR);
}
}
......@@ -140,6 +140,9 @@ final class AdminReadinessMessages implements ContainerInjectionInterface {
'update.settings',
'system.status',
'update.confirmation_page',
'automatic_updates.report_update',
'automatic_updates.module_update',
'automatic_updates.theme_update',
];
return !in_array($this->currentRouteMatch->getRouteName(), $disabled_routes, TRUE);
}
......
......@@ -2,10 +2,12 @@
namespace Drupal\automatic_updates\Validation;
use Drupal\automatic_updates\CronUpdater;
use Drupal\automatic_updates\Event\ReadinessCheckEvent;
use Drupal\automatic_updates\Updater;
use Drupal\automatic_updates\UpdateRecommender;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
......@@ -50,6 +52,20 @@ class ReadinessValidationManager {
*/
protected $updater;
/**
* The cron updater service.
*
* @var \Drupal\automatic_updates\CronUpdater
*/
protected $cronUpdater;
/**
* The config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $config;
/**
* Constructs a ReadinessValidationManager.
*
......@@ -61,14 +77,20 @@ class ReadinessValidationManager {
* The event dispatcher service.
* @param \Drupal\automatic_updates\Updater $updater
* The updater service.
* @param \Drupal\automatic_updates\CronUpdater $cron_updater
* The cron updater service.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config
* The config factory service.
* @param int $results_time_to_live
* The number of hours to store results.
*/
public function __construct(KeyValueExpirableFactoryInterface $key_value_expirable_factory, TimeInterface $time, EventDispatcherInterface $dispatcher, Updater $updater, int $results_time_to_live) {
public function __construct(KeyValueExpirableFactoryInterface $key_value_expirable_factory, TimeInterface $time, EventDispatcherInterface $dispatcher, Updater $updater, CronUpdater $cron_updater, ConfigFactoryInterface $config, int $results_time_to_live) {
$this->keyValueExpirable = $key_value_expirable_factory->get('automatic_updates');
$this->time = $time;
$this->eventDispatcher = $dispatcher;
$this->updater = $updater;
$this->cronUpdater = $cron_updater;
$this->config = $config;
$this->resultsTimeToLive = $results_time_to_live;
}
......@@ -78,20 +100,20 @@ class ReadinessValidationManager {
* @return $this
*/
public function run(): self {
$composer = $this->updater->getActiveComposer();
$recommender = new UpdateRecommender();
$release = $recommender->getRecommendedRelease(TRUE);
if ($release) {
$core_packages = $composer->getCorePackageNames();
// Update all core packages to the same version.
$package_versions = array_fill(0, count($core_packages), $release->getVersion());
$package_versions = array_combine($core_packages, $package_versions);
// If updates will run during cron, use the cron updater service provided by
// this module. This will allow subscribers to ReadinessCheckEvent to run
// specific validation for conditions that only affect cron updates.
if ($this->config->get('automatic_updates.settings')->get('cron') == CronUpdater::DISABLED) {
$stage = $this->updater;
}
else {
$package_versions = [];
$stage = $this->cronUpdater;
}
$event = new ReadinessCheckEvent($this->updater, $package_versions);
$project_versions = $release ? ['drupal' => $release->getVersion()] : [];
$event = new ReadinessCheckEvent($stage, $project_versions);
$this->eventDispatcher->dispatch($event);
$results = $event->getResults();
$this->keyValueExpirable->setWithExpire(
......@@ -116,10 +138,16 @@ class ReadinessValidationManager {
$listeners = $this->eventDispatcher->getListeners($event_name);
$string = '';
foreach ($listeners as $listener) {
/** @var object $object */
$object = $listener[0];
$method = $listener[1];
$string .= '-' . get_class($object) . '::' . $method;
if (is_array($listener)) {
$string .= is_object($listener[0]) ? get_class($listener[0]) : $listener[0];
$string .= $listener[1];
}
elseif (is_object($listener)) {
$string .= "-" . get_class($listener);
}
elseif (is_string($listener)) {
$string .= "-$listener";
}
}
return $string;
}
......
......@@ -2,7 +2,9 @@
namespace Drupal\Tests\automatic_updates\Kernel\ReadinessValidation;
use Drupal\automatic_updates\CronUpdater;
use Drupal\automatic_updates\Event\ReadinessCheckEvent;
use Drupal\automatic_updates\Updater;
use Drupal\automatic_updates_test\ReadinessChecker\TestChecker1;
use Drupal\automatic_updates_test2\ReadinessChecker\TestChecker2;
use Drupal\system\SystemManager;
......@@ -210,4 +212,25 @@ class ReadinessValidationManagerTest extends AutomaticUpdatesKernelTestBase {
$this->assertCheckerResultsFromManager($expected_results);
}
/**
* Tests the Automatic Updates cron setting changes which stage class is used.
*/
public function testCronSetting(): void {
$this->enableModules(['automatic_updates']);
$stage_class = NULL;
$listener = function (ReadinessCheckEvent $event) use (&$stage_class): void {
$stage_class = get_class($event->getStage());
};
$event_dispatcher = $this->container->get('event_dispatcher');
$event_dispatcher->addListener(ReadinessCheckEvent::class, $listener);
$this->container->get('automatic_updates.readiness_validation_manager')->run();
// By default, updates will be enabled on cron.
$this->assertSame(CronUpdater::class, $stage_class);
$this->config('automatic_updates.settings')
->set('cron', CronUpdater::DISABLED)
->save();
$this->container->get('automatic_updates.readiness_validation_manager')->run();
$this->assertSame(Updater::class, $stage_class);
}
}
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