Unverified Commit 5d4c083e authored by alexpott's avatar alexpott
Browse files

Issue #3098475 by Berdir, catch, TravisCarden, xjm, benjifisher, alexpott,...

Issue #3098475 by Berdir, catch, TravisCarden, xjm, benjifisher, alexpott, larowlan, dww: Add more strict checking of hook_update_last_removed() and better explanation
parent f88a6638
......@@ -320,14 +320,6 @@ function update_get_update_list() {
// Otherwise, get the list of updates defined by this module.
$updates = drupal_get_schema_versions($module);
if ($updates !== FALSE) {
// \Drupal::moduleHandler()->invoke() returns NULL for non-existing hooks,
// so if no updates are removed, it will == 0.
$last_removed = \Drupal::moduleHandler()->invoke($module, 'update_last_removed');
if ($schema_version < $last_removed) {
$ret[$module]['warning'] = '<em>' . $module . '</em> module cannot be updated. Its schema version is ' . $schema_version . '. Updates up to and including ' . $last_removed . ' have been removed in this release. In order to update <em>' . $module . '</em> module, you will first <a href="https://www.drupal.org/upgrade">need to upgrade</a> to the last version in which these updates were available.';
continue;
}
foreach ($updates as $update) {
if ($update == \Drupal::CORE_MINIMUM_SCHEMA_VERSION) {
$ret[$module]['warning'] = '<em>' . $module . '</em> module cannot be updated. It contains an update numbered as ' . \Drupal::CORE_MINIMUM_SCHEMA_VERSION . ' which is reserved for the earliest installation of a module in Drupal ' . \Drupal::CORE_COMPATIBILITY . ', before any updates. In order to update <em>' . $module . '</em> module, you will need to install a version of the module with valid updates.';
......
......@@ -17,6 +17,13 @@
'value' => 'i:8401;',
])
->execute();
$connection->insert('key_value')
->fields([
'collection' => 'system.schema',
'name' => 'serialization',
'value' => 'i:8401;',
])
->execute();
// Update core.extension.
$extensions = $connection->select('config')
......
......@@ -1046,6 +1046,54 @@ function system_requirements($phase) {
}
}
// Ensure that no module has a current schema version that is lower than the
// one that was last removed.
if ($phase == 'update') {
$module_handler = \Drupal::moduleHandler();
$module_list = [];
foreach ($module_handler->getImplementations('update_last_removed') as $module) {
$last_removed = $module_handler->invoke($module, 'update_last_removed');
if ($last_removed && $last_removed > drupal_get_installed_schema_version($module)) {
/** @var \Drupal\Core\Extension\Extension $module_info */
$module_info = \Drupal::service('extension.list.module')->get($module);
$module_list[$module] = [
'name' => $module_info->info['name'],
'last_removed' => $last_removed,
'installed_version' => drupal_get_installed_schema_version($module),
];
}
}
// If system.module is in the list then only show a specific message for
// Drupal core, otherwise show a more generic message for each module.
if (isset($module_list['system'])) {
$requirements['system_update_last_removed'] = [
'title' => t('The version of Drupal you are trying to update from is too old'),
'description' => t('Updating to Drupal @current_major is only supported from Drupal version @required_min_version or higher. If you are trying to update from an older version, first update to the latest version of Drupal @previous_major. (<a href=":url">Drupal 9 upgrade guide</a>)', [
'@current_major' => 9,
'@required_min_version' => '8.8.0',
'@previous_major' => 8,
':url' => 'https://www.drupal.org/docs/9/how-to-prepare-your-drupal-7-or-8-site-for-drupal-9/upgrading-a-drupal-8-site-to-drupal-9',
]),
'severity' => REQUIREMENT_ERROR,
];
}
else {
foreach ($module_list as $module => $data) {
$requirements[$module . '_update_last_removed'] = [
'title' => t('Unsupported schema version: @module', ['@module' => $data['name']]),
'description' => t('The installed version of the %module module is too old to update. Update to an intermediate version first (last removed version: @last_removed_version, installed version: @installed_version).', [
'%module' => $data['name'],
'@last_removed_version' => $data['last_removed'],
'@installed_version' => $data['installed_version'],
]),
'severity' => REQUIREMENT_ERROR,
];
}
}
}
return $requirements;
}
......@@ -1263,11 +1311,3 @@ function system_update_8901() {
}
}
}
/**
* Ensures that Drupal is updated from a supported version.
*/
function system_update_9000() {
// See update_get_update_list(), there needs to be at least one update
// function to check for the last removed schema version.
}
name: 'Update test with update_last_removed implementation'
type: module
description: 'Support module for update testing.'
package: Testing
version: VERSION
<?php
/**
* @file
* Install, update and uninstall functions for the update_test_invalid_hook module.
*/
/**
* Implements hook_update_last_removed()
*/
function update_test_last_removed_update_last_removed() {
return 8002;
}
/**
* Dummy update function to run during the tests.
*/
function update_test_last_removed_update_8003() {
return 'The update_test_last_removed_update_8003() update was executed successfully.';
}
<?php
namespace Drupal\Tests\system\Functional\UpdateSystem;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\UpdatePathTestTrait;
/**
* Modules can define their last removed update function.
*
* @group system
*/
class UpdatePathLastRemovedTest extends BrowserTestBase {
use UpdatePathTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['update_test_last_removed'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* URL for the upgrade script.
*
* @var string
*/
protected $updateUrl;
/**
* A user account with upgrade permission.
*
* @var \Drupal\user\UserInterface
*/
protected $updateUser;
protected function setUp() {
parent::setUp();
require_once $this->root . '/core/includes/update.inc';
$this->updateUrl = Url::fromRoute('system.db_update');
$this->updateUser = $this->drupalCreateUser(['administer software updates']);
}
/**
* Test that a module with a too old schema version can not be updated.
*/
public function testLastRemovedVersion() {
drupal_set_installed_schema_version('update_test_last_removed', 8000);
drupal_set_installed_schema_version('system', 8804);
// Access the update page with too old versions for system and the test
// module, only the generic core message should be shown.
$this->drupalLogin($this->updateUser);
$this->drupalGet($this->updateUrl);
$assert_session = $this->assertSession();
$assert_session->pageTextContains('Requirements problem');
$assert_session->pageTextContains('The version of Drupal you are trying to update from is too old');
$assert_session->pageTextContains('Updating to Drupal 9 is only supported from Drupal version 8.8.0 or higher. If you are trying to update from an older version, first update to the latest version of Drupal 8');
$assert_session->pageTextNotContains('Unsupported schema version: Update test with update_last_removed implementation');
$assert_session->linkNotExists('Continue');
// Update the installed version of system and then assert that now,
// the test module is shown instead.
drupal_set_installed_schema_version('system', 8805);
$this->drupalGet($this->updateUrl);
$assert_session->pageTextNotContains('The version of Drupal you are trying to update from is too old');
$assert_session->pageTextContains('Unsupported schema version: Update test with update_last_removed implementation');
$assert_session->pageTextContains('The installed version of the Update test with update_last_removed implementation module is too old to update. Update to an intermediate version first (last removed version: 8002, installed version: 8000).');
$assert_session->linkNotExists('Continue');
// Set the expected schema version for the node and test module, updates are
// successful now.
drupal_set_installed_schema_version('update_test_last_removed', 8002);
$this->runUpdates();
$this->assertEquals(8003, drupal_get_installed_schema_version('update_test_last_removed'));
}
}
......@@ -59,6 +59,7 @@ protected function runUpdates($update_url = NULL) {
}
// Ensure that there are no pending updates.
drupal_get_installed_schema_version(NULL, TRUE);
foreach (['update', 'post_update'] as $update_type) {
switch ($update_type) {
case 'update':
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment