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

Issue #3227575 by tedbow, phenaproxima: Run updates on cron

parent 0929d32a
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,7 @@
* Contains hook implementations for Automatic Updates.
*/
use Drupal\automatic_updates\CronUpdater;
use Drupal\automatic_updates\Validation\AdminReadinessMessages;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
......@@ -22,6 +23,10 @@ function automatic_updates_page_top() {
* Implements hook_cron().
*/
function automatic_updates_cron() {
/** @var \Drupal\automatic_updates\CronUpdater $cron_updater */
$cron_updater = \Drupal::classResolver(CronUpdater::class);
$cron_updater->handleCron();
/** @var \Drupal\automatic_updates\Validation\ReadinessValidationManager $checker_manager */
$checker_manager = \Drupal::service('automatic_updates.readiness_validation_manager');
$last_results = $checker_manager->getResults();
......
......@@ -4,7 +4,7 @@ services:
arguments: ['@keyvalue.expirable', '@datetime.time', 24]
automatic_updates.updater:
class: Drupal\automatic_updates\Updater
arguments: ['@state', '@string_translation','@package_manager.beginner', '@package_manager.stager', '@automatic_updates.cleaner', '@package_manager.committer', '@event_dispatcher', '@automatic_updates.path_locator']
arguments: ['@state', '@string_translation','@package_manager.beginner', '@package_manager.stager', '@package_manager.cleaner', '@package_manager.committer', '@event_dispatcher', '@automatic_updates.path_locator']
automatic_updates.cleaner:
class: Drupal\automatic_updates\ComposerStager\Cleaner
decorates: package_manager.cleaner
......
<?php
namespace Drupal\automatic_updates;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a service that updates via cron.
*
* @internal
* This class implements logic specific to Automatic Updates' cron hook
* implementation. It should not be called directly.
*/
class CronUpdater implements ContainerInjectionInterface {
/**
* The updater service.
*
* @var \Drupal\automatic_updates\Updater
*/
protected $updater;
/**
* The logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* Constructs a CronUpdater object.
*
* @param \Drupal\automatic_updates\Updater $updater
* The updater service.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
* The logger channel factory.
*/
public function __construct(Updater $updater, LoggerChannelFactoryInterface $logger_factory) {
$this->updater = $updater;
$this->logger = $logger_factory->get('automatic_updates');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('automatic_updates.updater'),
$container->get('logger.factory')
);
}
/**
* Handles updates during cron.
*/
public function handleCron(): void {
$recommender = new UpdateRecommender();
try {
$recommended_release = $recommender->getRecommendedRelease(TRUE);
}
catch (\Throwable $e) {
$this->logger->error($e->getMessage());
return;
}
// If we're already up-to-date, there's nothing else we need to do.
if ($recommended_release === NULL) {
return;
}
$project = $recommender->getProjectInfo();
if (empty($project['existing_version'])) {
$this->logger->error('Unable to determine the current version of Drupal core.');
return;
}
// @todo Use the queue to add update jobs allowing jobs to span multiple
// cron runs.
$recommended_version = $recommended_release->getVersion();
try {
$this->updater->begin([
'drupal' => $recommended_version,
]);
$this->updater->stage();
$this->updater->commit();
$this->updater->clean();
}
catch (\Throwable $e) {
$this->logger->error($e->getMessage());
return;
}
$this->logger->info(
'Drupal core has been updated from %previous_version to %update_version',
[
'%previous_version' => $project['existing_version'],
'%update_version' => $recommended_version,
]
);
}
}
......@@ -7,7 +7,7 @@ namespace Drupal\Tests\automatic_updates\Build;
*
* @group automatic_updates
*/
class AttendedCoreRecommendedUpdateTest extends AttendedCoreUpdateTest {
class CoreRecommendedUpdateTest extends CoreUpdateTest {
/**
* {@inheritdoc}
......
......@@ -3,11 +3,47 @@
namespace Drupal\Tests\automatic_updates\Build;
/**
* Tests an end-to-end update of Drupal core within the UI.
* Tests an end-to-end update of Drupal core.
*
* @group automatic_updates
*/
class AttendedCoreUpdateTest extends AttendedUpdateTestBase {
class CoreUpdateTest extends UpdateTestBase {
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
// Build the test site and alter its copy of core so that it thinks it's
// running Drupal 9.8.0, which will never actually exist in the real world.
// Then, prepare a secondary copy of the core code base, masquerading as
// Drupal 9.8.1, which will be the version of core we update to. These two
// versions are referenced in the fake release metadata in our fake release
// metadata (see fixtures/release-history/drupal.0.0.xml).
$this->createTestSite();
$this->setCoreVersion($this->getWebRoot() . '/core', '9.8.0');
$this->alterPackage($this->getWorkspaceDirectory(), $this->getConfigurationForUpdate('9.8.1'));
// Install Drupal and ensure it's using the fake release metadata to fetch
// information about available updates.
$this->installQuickStart('minimal');
$this->setReleaseMetadata(['drupal' => '0.0']);
$this->formLogin($this->adminUsername, $this->adminPassword);
$this->installModules([
'automatic_updates',
'automatic_updates_test',
'update_test',
]);
// Ensure that Drupal thinks we are running 9.8.0, then refresh information
// about available updates.
$this->assertCoreVersion('9.8.0');
$this->checkForUpdates();
// Ensure that an update to 9.8.1 is available.
$this->visit('/admin/automatic-update');
$this->getMink()->assertSession()->pageTextContains('9.8.1');
}
/**
* {@inheritdoc}
......@@ -37,14 +73,6 @@ class AttendedCoreUpdateTest extends AttendedUpdateTestBase {
file_put_contents($drupal_php, $code);
}
/**
* {@inheritdoc}
*/
protected function createTestSite(): void {
parent::createTestSite();
$this->setCoreVersion($this->getWebRoot() . '/core', '9.8.0');
}
/**
* Returns composer.json changes that are needed to update core.
*
......@@ -76,37 +104,40 @@ class AttendedCoreUpdateTest extends AttendedUpdateTestBase {
}
/**
* Tests an end-to-end core update.
* Tests an end-to-end core update via the UI.
*/
public function test(): void {
$this->createTestSite();
$this->alterPackage($this->getWorkspaceDirectory(), $this->getConfigurationForUpdate('9.8.1'));
$this->installQuickStart('minimal');
$this->setReleaseMetadata(['drupal' => '0.0']);
$this->formLogin($this->adminUsername, $this->adminPassword);
$this->installModules([
'automatic_updates',
'automatic_updates_test',
'update_test',
]);
public function testUi(): void {
$mink = $this->getMink();
$page = $mink->getSession()->getPage();
$assert_session = $mink->assertSession();
$this->assertCoreVersion('9.8.0');
$this->checkForUpdates();
$this->visit('/admin/automatic-update');
$assert_session->pageTextContains('9.8.1');
$page->pressButton('Download these updates');
$this->waitForBatchJob();
$assert_session->pageTextContains('Ready to update');
$page->pressButton('Continue');
$this->waitForBatchJob();
$assert_session->pageTextContains('Update complete!');
$this->assertCoreVersion('9.8.1');
$this->assertUpdateSuccessful();
}
/**
* Tests an end-to-end core update via cron.
*/
public function testCron(): void {
$this->visit('/admin/reports/status');
$this->getMink()->getSession()->getPage()->clickLink('Run cron');
$this->assertUpdateSuccessful();
}
/**
* Asserts that Drupal core was successfully updated.
*/
private function assertUpdateSuccessful(): void {
// The status page should report that we're running Drupal 9.8.1.
$this->assertCoreVersion('9.8.1');
// The fake placeholder text from ::getConfigurationForUpdate() should be
// present in the README.
$placeholder = file_get_contents($this->getWebRoot() . '/core/README.txt');
$this->assertSame('Placeholder for Drupal core 9.8.1.', $placeholder);
}
......
......@@ -8,9 +8,9 @@ use Drupal\Tests\automatic_updates\Traits\LocalPackagesTrait;
use Drupal\Tests\automatic_updates\Traits\SettingsTrait;
/**
* Base class for tests that perform in-place attended updates via the UI.
* Base class for tests that perform in-place updates.
*/
abstract class AttendedUpdateTestBase extends QuickStartTestBase {
abstract class UpdateTestBase extends QuickStartTestBase {
use LocalPackagesTrait {
getPackagePath as traitGetPackagePath;
......
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