Update to Drupal 8.1.0. For more information, see https://www.drupal.org/drupal-8.1.0-release-notes
This commit is contained in:
parent
b11a755ba8
commit
c0a0d5a94c
6920 changed files with 64395 additions and 57312 deletions
11
core/modules/migrate_drupal_ui/migrate_drupal_ui.info.yml
Normal file
11
core/modules/migrate_drupal_ui/migrate_drupal_ui.info.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
name: 'Migrate Drupal UI'
|
||||
type: module
|
||||
description: 'Provides a user interface for migrating from older Drupal versions.'
|
||||
package: 'Core (Experimental)'
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
configure: migrate_drupal_ui.upgrade
|
||||
dependencies:
|
||||
- migrate
|
||||
- migrate_drupal
|
||||
- dblog
|
16
core/modules/migrate_drupal_ui/migrate_drupal_ui.install
Normal file
16
core/modules/migrate_drupal_ui/migrate_drupal_ui.install
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update, and uninstall functions for the migrate_drupal_ui module.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function migrate_drupal_ui_install() {
|
||||
$url = Url::fromUri('base:upgrade')->toString();
|
||||
drupal_set_message(t('The Migrate Drupal UI module has been enabled. Proceed to the <a href=":url">upgrade form</a>.', [':url' => $url]));
|
||||
}
|
19
core/modules/migrate_drupal_ui/migrate_drupal_ui.module
Normal file
19
core/modules/migrate_drupal_ui/migrate_drupal_ui.module
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Alert administrators before starting the import process.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function migrate_drupal_ui_help($route_name, RouteMatchInterface $route_match) {
|
||||
switch ($route_name) {
|
||||
case 'help.page.migrate_drupal_ui':
|
||||
$output = '<p>' . t('The Migrate Drupal UI module provides a one-click upgrade from an earlier version of Drupal. For details, see the <a href=":migrate">online documentation for the Migrate Drupal UI module</a> in the handbook on upgrading from previous versions.', [':migrate' => 'https://www.drupal.org/upgrade/migrate']) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
18
core/modules/migrate_drupal_ui/migrate_drupal_ui.routing.yml
Normal file
18
core/modules/migrate_drupal_ui/migrate_drupal_ui.routing.yml
Normal file
|
@ -0,0 +1,18 @@
|
|||
migrate_drupal_ui.upgrade:
|
||||
path: '/upgrade'
|
||||
defaults:
|
||||
_form: '\Drupal\migrate_drupal_ui\Form\MigrateUpgradeForm'
|
||||
_title: 'Upgrade'
|
||||
requirements:
|
||||
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'
|
||||
options:
|
||||
_admin_route: TRUE
|
||||
|
||||
migrate_drupal_ui.log:
|
||||
path: '/upgrade/log'
|
||||
defaults:
|
||||
_controller: '\Drupal\migrate_drupal_ui\Controller\MigrateController::showLog'
|
||||
requirements:
|
||||
_custom_access: '\Drupal\migrate_drupal_ui\MigrateAccessCheck::checkAccess'
|
||||
options:
|
||||
_admin_route: TRUE
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui\Controller;
|
||||
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
|
||||
/**
|
||||
* Provides controller methods for the migration.
|
||||
*/
|
||||
class MigrateController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* Sets a log filter and redirects to the log.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* A redirect response object that may be returned by the controller.
|
||||
*/
|
||||
public function showLog() {
|
||||
$_SESSION['dblog_overview_filter'] = [];
|
||||
$_SESSION['dblog_overview_filter']['type'] = ['migrate_drupal_ui' => 'migrate_drupal_ui'];
|
||||
return $this->redirect('dblog.overview');
|
||||
}
|
||||
|
||||
}
|
1118
core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
Normal file
1118
core/modules/migrate_drupal_ui/src/Form/MigrateUpgradeForm.php
Normal file
File diff suppressed because it is too large
Load diff
35
core/modules/migrate_drupal_ui/src/MigrateAccessCheck.php
Normal file
35
core/modules/migrate_drupal_ui/src/MigrateAccessCheck.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui;
|
||||
|
||||
use Drupal\Core\Access\AccessResultAllowed;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Checks access for migrate_drupal_ui routes.
|
||||
*
|
||||
* The Migrate Drupal UI can only be used by user 1. This is because any other
|
||||
* user might have different permissions on the source and target site.
|
||||
*
|
||||
* This class is designed to be used with '_custom_access' route requirement.
|
||||
*
|
||||
* @see \Drupal\Core\Access\CustomAccessCheck
|
||||
*/
|
||||
class MigrateAccessCheck {
|
||||
|
||||
/**
|
||||
* Checks if the user is user 1 and grants access if so.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResult
|
||||
* The access result.
|
||||
*/
|
||||
public function checkAccess(AccountInterface $account) {
|
||||
// The access result is uncacheable because it is just limiting access to
|
||||
// the migrate UI which is not worth caching.
|
||||
return AccessResultAllowed::allowedIf((int) $account->id() === 1)->mergeCacheMaxAge(0);
|
||||
}
|
||||
|
||||
}
|
43
core/modules/migrate_drupal_ui/src/MigrateMessageCapture.php
Normal file
43
core/modules/migrate_drupal_ui/src/MigrateMessageCapture.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui;
|
||||
|
||||
use Drupal\migrate\MigrateMessageInterface;
|
||||
|
||||
/**
|
||||
* Allows capturing messages rather than displaying them directly.
|
||||
*/
|
||||
class MigrateMessageCapture implements MigrateMessageInterface {
|
||||
|
||||
/**
|
||||
* Array of recorded messages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $messages = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function display($message, $type = 'status') {
|
||||
$this->messages[] = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out any captured messages.
|
||||
*/
|
||||
public function clear() {
|
||||
$this->messages = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns any captured messages.
|
||||
*
|
||||
* @return array
|
||||
* The captured messages.
|
||||
*/
|
||||
public function getMessages() {
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
}
|
350
core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php
Normal file
350
core/modules/migrate_drupal_ui/src/MigrateUpgradeRunBatch.php
Normal file
|
@ -0,0 +1,350 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui;
|
||||
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Event\MigrateEvents;
|
||||
use Drupal\migrate\Event\MigrateIdMapMessageEvent;
|
||||
use Drupal\migrate\Event\MigrateMapDeleteEvent;
|
||||
use Drupal\migrate\Event\MigrateMapSaveEvent;
|
||||
use Drupal\migrate\Event\MigratePostRowSaveEvent;
|
||||
use Drupal\migrate\Event\MigrateRowDeleteEvent;
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
|
||||
/**
|
||||
* Runs a single migration batch.
|
||||
*/
|
||||
class MigrateUpgradeRunBatch {
|
||||
|
||||
/**
|
||||
* Maximum number of previous messages to display.
|
||||
*/
|
||||
const MESSAGE_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* The processed items for one batch of a given migration.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $numProcessed = 0;
|
||||
|
||||
/**
|
||||
* Ensure we only add the listeners once per request.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $listenersAdded = FALSE;
|
||||
|
||||
/**
|
||||
* The maximum length in seconds to allow processing in a request.
|
||||
*
|
||||
* @see self::run()
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $maxExecTime;
|
||||
|
||||
/**
|
||||
* MigrateMessage instance to capture messages during the migration process.
|
||||
*
|
||||
* @var \Drupal\migrate_drupal_ui\MigrateMessageCapture
|
||||
*/
|
||||
protected static $messages;
|
||||
|
||||
/**
|
||||
* Runs a single migration batch.
|
||||
*
|
||||
* @param int[] $initial_ids
|
||||
* The full set of migration IDs to import.
|
||||
* @param string $operation
|
||||
* The operation to perform. Only 'import' is currently supported.
|
||||
* @param array $config
|
||||
* An array of additional configuration from the form.
|
||||
* @param array $context
|
||||
* The batch context.
|
||||
*
|
||||
* @todo Remove the $operation parameter and conditionals for it below, and
|
||||
* refactor this method. https://www.drupal.org/node/2687851
|
||||
*/
|
||||
public static function run($initial_ids, $operation, $config, &$context) {
|
||||
if (!static::$listenersAdded) {
|
||||
$event_dispatcher = \Drupal::service('event_dispatcher');
|
||||
if ($operation == 'import') {
|
||||
$event_dispatcher->addListener(MigrateEvents::POST_ROW_SAVE, [static::class, 'onPostRowSave']);
|
||||
$event_dispatcher->addListener(MigrateEvents::MAP_SAVE, [static::class, 'onMapSave']);
|
||||
$event_dispatcher->addListener(MigrateEvents::IDMAP_MESSAGE, [static::class, 'onIdMapMessage']);
|
||||
}
|
||||
static::$maxExecTime = ini_get('max_execution_time');
|
||||
if (static::$maxExecTime <= 0) {
|
||||
static::$maxExecTime = 60;
|
||||
}
|
||||
// Set an arbitrary threshold of 3 seconds (e.g., if max_execution_time is
|
||||
// 45 seconds, we will quit at 42 seconds so a slow item or cleanup
|
||||
// overhead don't put us over 45).
|
||||
static::$maxExecTime -= 3;
|
||||
static::$listenersAdded = TRUE;
|
||||
}
|
||||
if (!isset($context['sandbox']['migration_ids'])) {
|
||||
$context['sandbox']['max'] = count($initial_ids);
|
||||
$context['sandbox']['current'] = 1;
|
||||
// Total number processed for this migration.
|
||||
$context['sandbox']['num_processed'] = 0;
|
||||
// migration_ids will be the list of IDs remaining to run.
|
||||
$context['sandbox']['migration_ids'] = $initial_ids;
|
||||
$context['sandbox']['messages'] = [];
|
||||
$context['results']['failures'] = 0;
|
||||
$context['results']['successes'] = 0;
|
||||
$context['results']['operation'] = $operation;
|
||||
}
|
||||
|
||||
// Number processed in this batch.
|
||||
static::$numProcessed = 0;
|
||||
|
||||
$migration_id = reset($context['sandbox']['migration_ids']);
|
||||
/** @var \Drupal\migrate\Plugin\Migration $migration */
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id);
|
||||
|
||||
// @TODO, remove this in https://www.drupal.org/node/2681869.
|
||||
$destination = $migration->getDestinationConfiguration();
|
||||
if ($destination['plugin'] === 'entity:file') {
|
||||
// Make sure we have a single trailing slash.
|
||||
$source_base_path = rtrim($config['source_base_path'], '/') . '/';
|
||||
$destination['source_base_path'] = $source_base_path;
|
||||
$migration->set('destination', $destination);
|
||||
}
|
||||
|
||||
if ($migration) {
|
||||
static::$messages = new MigrateMessageCapture();
|
||||
$executable = new MigrateExecutable($migration, static::$messages);
|
||||
|
||||
$migration_name = $migration->label() ? $migration->label() : $migration_id;
|
||||
|
||||
try {
|
||||
if ($operation == 'import') {
|
||||
$migration_status = $executable->import();
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
static::logger()->error($e->getMessage());
|
||||
$migration_status = MigrationInterface::RESULT_FAILED;
|
||||
}
|
||||
|
||||
switch ($migration_status) {
|
||||
case MigrationInterface::RESULT_COMPLETED:
|
||||
// Store the number processed in the sandbox.
|
||||
$context['sandbox']['num_processed'] += static::$numProcessed;
|
||||
if ($operation == 'import') {
|
||||
$message = static::getTranslation()->formatPlural(
|
||||
$context['sandbox']['num_processed'], 'Upgraded @migration (processed 1 item total)', 'Upgraded @migration (processed @num_processed items total)',
|
||||
['@migration' => $migration_name, '@num_processed' => $context['sandbox']['num_processed']]);
|
||||
}
|
||||
$context['sandbox']['messages'][] = $message;
|
||||
static::logger()->notice($message);
|
||||
$context['sandbox']['num_processed'] = 0;
|
||||
$context['results']['successes']++;
|
||||
break;
|
||||
|
||||
case MigrationInterface::RESULT_INCOMPLETE:
|
||||
$context['sandbox']['messages'][] = static::getTranslation()->formatPlural(
|
||||
static::$numProcessed, 'Continuing with @migration (processed 1 item)', 'Continuing with @migration (processed @num_processed items)',
|
||||
['@migration' => $migration_name, '@num_processed' => static::$numProcessed]);
|
||||
$context['sandbox']['num_processed'] += static::$numProcessed;
|
||||
break;
|
||||
|
||||
case MigrationInterface::RESULT_STOPPED:
|
||||
$context['sandbox']['messages'][] = t('Operation stopped by request');
|
||||
break;
|
||||
|
||||
case MigrationInterface::RESULT_FAILED:
|
||||
$context['sandbox']['messages'][] = t('Operation on @migration failed', ['@migration' => $migration_name]);
|
||||
$context['results']['failures']++;
|
||||
static::logger()->error('Operation on @migration failed', ['@migration' => $migration_name]);
|
||||
break;
|
||||
|
||||
case MigrationInterface::RESULT_SKIPPED:
|
||||
$context['sandbox']['messages'][] = t('Operation on @migration skipped due to unfulfilled dependencies', ['@migration' => $migration_name]);
|
||||
static::logger()->error('Operation on @migration skipped due to unfulfilled dependencies', ['@migration' => $migration_name]);
|
||||
break;
|
||||
|
||||
case MigrationInterface::RESULT_DISABLED:
|
||||
// Skip silently if disabled.
|
||||
break;
|
||||
}
|
||||
|
||||
// Unless we're continuing on with this migration, take it off the list.
|
||||
if ($migration_status != MigrationInterface::RESULT_INCOMPLETE) {
|
||||
array_shift($context['sandbox']['migration_ids']);
|
||||
$context['sandbox']['current']++;
|
||||
}
|
||||
|
||||
// Add and log any captured messages.
|
||||
foreach (static::$messages->getMessages() as $message) {
|
||||
$context['sandbox']['messages'][] = $message;
|
||||
static::logger()->error($message);
|
||||
}
|
||||
|
||||
// Only display the last MESSAGE_LENGTH messages, in reverse order.
|
||||
$message_count = count($context['sandbox']['messages']);
|
||||
$context['message'] = '';
|
||||
for ($index = max(0, $message_count - self::MESSAGE_LENGTH); $index < $message_count; $index++) {
|
||||
$context['message'] = $context['sandbox']['messages'][$index] . "<br />\n" . $context['message'];
|
||||
}
|
||||
if ($message_count > self::MESSAGE_LENGTH) {
|
||||
// Indicate there are earlier messages not displayed.
|
||||
$context['message'] .= '…';
|
||||
}
|
||||
// At the top of the list, display the next one (which will be the one
|
||||
// that is running while this message is visible).
|
||||
if (!empty($context['sandbox']['migration_ids'])) {
|
||||
$migration_id = reset($context['sandbox']['migration_ids']);
|
||||
$migration = \Drupal::service('plugin.manager.migration')->createInstance($migration_id);
|
||||
$migration_name = $migration->label() ? $migration->label() : $migration_id;
|
||||
if ($operation == 'import') {
|
||||
$context['message'] = t('Currently upgrading @migration (@current of @max total tasks)', [
|
||||
'@migration' => $migration_name,
|
||||
'@current' => $context['sandbox']['current'],
|
||||
'@max' => $context['sandbox']['max'],
|
||||
]) . "<br />\n" . $context['message'];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
array_shift($context['sandbox']['migration_ids']);
|
||||
$context['sandbox']['current']++;
|
||||
}
|
||||
|
||||
$context['finished'] = 1 - count($context['sandbox']['migration_ids']) / $context['sandbox']['max'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the logger using the migrate_drupal_ui channel.
|
||||
*
|
||||
* @return \Psr\Log\LoggerInterface
|
||||
* The logger instance.
|
||||
*/
|
||||
protected static function logger() {
|
||||
return \Drupal::logger('migrate_drupal_ui');
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the translation manager.
|
||||
*
|
||||
* @return \Drupal\Core\StringTranslation\TranslationManager
|
||||
* The string translation manager.
|
||||
*/
|
||||
protected static function getTranslation() {
|
||||
return \Drupal::translation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Batch API finished method.
|
||||
*/
|
||||
public static function finished($success, $results, $operations, $elapsed) {
|
||||
static::displayResults($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays counts of success/failures on the migration upgrade complete page.
|
||||
*
|
||||
* @param array $results
|
||||
* An array of result data built during the batch.
|
||||
*/
|
||||
protected static function displayResults($results) {
|
||||
$successes = $results['successes'];
|
||||
$failures = $results['failures'];
|
||||
|
||||
// If we had any successes log that for the user.
|
||||
if ($successes > 0) {
|
||||
if ($results['operation'] == 'import') {
|
||||
drupal_set_message(static::getTranslation()->formatPlural($successes, 'Completed 1 upgrade task successfully', 'Completed @count upgrade tasks successfully'));
|
||||
}
|
||||
}
|
||||
|
||||
// If we had failures, log them and show the migration failed.
|
||||
if ($failures > 0) {
|
||||
if ($results['operation'] == 'import') {
|
||||
drupal_set_message(static::getTranslation()->formatPlural($failures, '1 upgrade failed', '@count upgrades failed'));
|
||||
drupal_set_message(t('Upgrade process not completed'), 'error');
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($results['operation'] == 'import') {
|
||||
// Everything went off without a hitch. We may not have had successes
|
||||
// but we didn't have failures so this is fine.
|
||||
drupal_set_message(t('Congratulations, you upgraded Drupal!'));
|
||||
}
|
||||
}
|
||||
|
||||
if (\Drupal::moduleHandler()->moduleExists('dblog')) {
|
||||
$url = Url::fromRoute('migrate_drupal_ui.log');
|
||||
drupal_set_message(Link::fromTextAndUrl(t('Review the detailed upgrade log'), $url), $failures ? 'error' : 'status');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to item import.
|
||||
*
|
||||
* @param \Drupal\migrate\Event\MigratePostRowSaveEvent $event
|
||||
* The post-save event.
|
||||
*/
|
||||
public static function onPostRowSave(MigratePostRowSaveEvent $event) {
|
||||
// We want to interrupt this batch and start a fresh one.
|
||||
if ((time() - REQUEST_TIME) > static::$maxExecTime) {
|
||||
$event->getMigration()->interruptMigration(MigrationInterface::RESULT_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reacts to item deletion.
|
||||
*
|
||||
* @param \Drupal\migrate\Event\MigrateRowDeleteEvent $event
|
||||
* The post-save event.
|
||||
*/
|
||||
public static function onPostRowDelete(MigrateRowDeleteEvent $event) {
|
||||
// We want to interrupt this batch and start a fresh one.
|
||||
if ((time() - REQUEST_TIME) > static::$maxExecTime) {
|
||||
$event->getMigration()->interruptMigration(MigrationInterface::RESULT_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts up any map save events.
|
||||
*
|
||||
* @param \Drupal\migrate\Event\MigrateMapSaveEvent $event
|
||||
* The map event.
|
||||
*/
|
||||
public static function onMapSave(MigrateMapSaveEvent $event) {
|
||||
static::$numProcessed++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts up any map delete events.
|
||||
*
|
||||
* @param \Drupal\migrate\Event\MigrateMapDeleteEvent $event
|
||||
* The map event.
|
||||
*/
|
||||
public static function onMapDelete(MigrateMapDeleteEvent $event) {
|
||||
static::$numProcessed++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays any messages being logged to the ID map.
|
||||
*
|
||||
* @param \Drupal\migrate\Event\MigrateIdMapMessageEvent $event
|
||||
* The message event.
|
||||
*/
|
||||
public static function onIdMapMessage(MigrateIdMapMessageEvent $event) {
|
||||
if ($event->getLevel() == MigrationInterface::MESSAGE_NOTICE || $event->getLevel() == MigrationInterface::MESSAGE_INFORMATIONAL) {
|
||||
$type = 'status';
|
||||
}
|
||||
else {
|
||||
$type = 'error';
|
||||
}
|
||||
$source_id_string = implode(',', $event->getSourceIdValues());
|
||||
$message = t('Source ID @source_id: @message', ['@source_id' => $source_id_string, '@message' => $event->getMessage()]);
|
||||
static::$messages->display($message, $type);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests that only user 1 can access the migrate UI.
|
||||
*
|
||||
* @group migrate_drupal_ui
|
||||
*/
|
||||
class MigrateAccessTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate_drupal_ui'];
|
||||
|
||||
/**
|
||||
* Tests that only user 1 can access the migrate UI.
|
||||
*/
|
||||
protected function testAccess() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->drupalGet('upgrade');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText(t('Drupal Upgrade'));
|
||||
|
||||
$user = $this->createUser(['administer software updates']);
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet('upgrade');
|
||||
$this->assertResponse(403);
|
||||
$this->assertNoText(t('Drupal Upgrade'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui\Tests;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\migrate\Plugin\MigrateIdMapInterface;
|
||||
use Drupal\migrate_drupal\MigrationCreationTrait;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Provides a base class for testing migration upgrades in the UI.
|
||||
*/
|
||||
abstract class MigrateUpgradeTestBase extends WebTestBase {
|
||||
use MigrationCreationTrait;
|
||||
|
||||
/**
|
||||
* Use the Standard profile to test help implementations of many core modules.
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
|
||||
/**
|
||||
* The source database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $sourceDatabase;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['migrate_drupal_ui', 'telephone'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->createMigrationConnection();
|
||||
$this->sourceDatabase = Database::getConnection('default', 'migrate_drupal_ui');
|
||||
|
||||
// Log in as user 1. Migrations in the UI can only be performed as user 1.
|
||||
$this->drupalLogin($this->rootUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a database fixture into the source database connection.
|
||||
*
|
||||
* @param string $path
|
||||
* Path to the dump file.
|
||||
*/
|
||||
protected function loadFixture($path) {
|
||||
$default_db = Database::getConnection()->getKey();
|
||||
Database::setActiveConnection($this->sourceDatabase->getKey());
|
||||
|
||||
if (substr($path, -3) == '.gz') {
|
||||
$path = 'compress.zlib://' . $path;
|
||||
}
|
||||
require $path;
|
||||
|
||||
Database::setActiveConnection($default_db);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the database connection to the prefixed one.
|
||||
*
|
||||
* @todo Remove when we don't use global. https://www.drupal.org/node/2552791
|
||||
*/
|
||||
protected function createMigrationConnection() {
|
||||
$connection_info = Database::getConnectionInfo('default')['default'];
|
||||
if ($connection_info['driver'] === 'sqlite') {
|
||||
// Create database file in the test site's public file directory so that
|
||||
// \Drupal\simpletest\TestBase::restoreEnvironment() will delete this once
|
||||
// the test is complete.
|
||||
$file = $this->publicFilesDirectory . '/' . $this->testId . '-migrate.db.sqlite';
|
||||
touch($file);
|
||||
$connection_info['database'] = $file;
|
||||
$connection_info['prefix'] = '';
|
||||
}
|
||||
else {
|
||||
$prefix = is_array($connection_info['prefix']) ? $connection_info['prefix']['default'] : $connection_info['prefix'];
|
||||
// Simpletest uses fixed length prefixes. Create a new prefix for the
|
||||
// source database. Adding to the end of the prefix ensures that
|
||||
// \Drupal\simpletest\TestBase::restoreEnvironment() will remove the
|
||||
// additional tables.
|
||||
$connection_info['prefix'] = $prefix . '0';
|
||||
}
|
||||
|
||||
Database::addConnectionInfo('migrate_drupal_ui', 'default', $connection_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown() {
|
||||
Database::removeConnection('migrate_drupal_ui');
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all steps of migrations upgrade.
|
||||
*/
|
||||
protected function testMigrateUpgrade() {
|
||||
$connection_options = $this->sourceDatabase->getConnectionOptions();
|
||||
$this->drupalGet('/upgrade');
|
||||
$this->assertText('Upgrade a Drupal site by importing it into a clean and empty new install of Drupal 8. You will lose any existing configuration once you import your site into it. See the upgrading handbook for more detailed information.');
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Continue'));
|
||||
$this->assertText('Provide credentials for the database of the Drupal site you want to upgrade.');
|
||||
$this->assertFieldByName('mysql[host]');
|
||||
|
||||
$driver = $connection_options['driver'];
|
||||
$connection_options['prefix'] = $connection_options['prefix']['default'];
|
||||
|
||||
// Use the driver connection form to get the correct options out of the
|
||||
// database settings. This supports all of the databases we test against.
|
||||
$drivers = drupal_get_database_types();
|
||||
$form = $drivers[$driver]->getFormOptions($connection_options);
|
||||
$connection_options = array_intersect_key($connection_options, $form + $form['advanced_options']);
|
||||
$edit = [
|
||||
$driver => $connection_options,
|
||||
'source_base_path' => $this->getSourceBasePath(),
|
||||
];
|
||||
if (count($drivers) !== 1) {
|
||||
$edit['driver'] = $driver;
|
||||
}
|
||||
$edits = $this->translatePostValues($edit);
|
||||
|
||||
// Ensure submitting the form with invalid database credentials gives us a
|
||||
// nice warning.
|
||||
$this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade'));
|
||||
$this->assertText('Resolve the issue below to continue the upgrade.');
|
||||
|
||||
$this->drupalPostForm(NULL, $edits, t('Review upgrade'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('Are you sure?');
|
||||
$this->drupalPostForm(NULL, [], t('Perform upgrade'));
|
||||
$this->assertText(t('Congratulations, you upgraded Drupal!'));
|
||||
|
||||
// Have to reset all the statics after migration to ensure entities are
|
||||
// loadable.
|
||||
$this->resetAll();
|
||||
|
||||
$expected_counts = $this->getEntityCounts();
|
||||
foreach (array_keys(\Drupal::entityTypeManager()->getDefinitions()) as $entity_type) {
|
||||
$real_count = count(\Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple());
|
||||
$expected_count = isset($expected_counts[$entity_type]) ? $expected_counts[$entity_type] : 0;
|
||||
$this->assertEqual($expected_count, $real_count, "Found $real_count $entity_type entities, expected $expected_count.");
|
||||
}
|
||||
|
||||
$version_tag = 'Drupal ' . $this->getLegacyDrupalVersion($this->sourceDatabase);
|
||||
$plugin_manager = \Drupal::service('plugin.manager.migration');
|
||||
/** @var \Drupal\migrate\Plugin\Migration[] $all_migrations */
|
||||
$all_migrations = $plugin_manager->createInstancesByTag($version_tag);
|
||||
foreach ($all_migrations as $migration) {
|
||||
$id_map = $migration->getIdMap();
|
||||
foreach ($id_map as $source_id => $map) {
|
||||
// Convert $source_id into a keyless array so that
|
||||
// \Drupal\migrate\Plugin\migrate\id_map\Sql::getSourceHash() works as
|
||||
// expected.
|
||||
$source_id_values = array_values(unserialize($source_id));
|
||||
$row = $id_map->getRowBySource($source_id_values);
|
||||
$destination = serialize($id_map->currentDestination());
|
||||
$message = "Successful migration of $source_id to $destination as part of the {$migration->id()} migration. The source row status is " . $row['source_row_status'];
|
||||
// A completed migration should have maps with
|
||||
// MigrateIdMapInterface::STATUS_IGNORED or
|
||||
// MigrateIdMapInterface::STATUS_IMPORTED.
|
||||
if ($row['source_row_status'] == MigrateIdMapInterface::STATUS_FAILED || $row['source_row_status'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE) {
|
||||
$this->fail($message);
|
||||
}
|
||||
else {
|
||||
$this->pass($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source base path for the concrete test.
|
||||
*
|
||||
* @return string
|
||||
* The source base path.
|
||||
*/
|
||||
abstract protected function getSourceBasePath();
|
||||
|
||||
/**
|
||||
* Gets the expected number of entities per entity type after migration.
|
||||
*
|
||||
* @return int[]
|
||||
* An array of expected counts keyed by entity type ID.
|
||||
*/
|
||||
abstract protected function getEntityCounts();
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui\Tests\d6;
|
||||
|
||||
use Drupal\migrate_drupal_ui\Tests\MigrateUpgradeTestBase;
|
||||
|
||||
/**
|
||||
* Tests Drupal 6 upgrade using the migrate UI.
|
||||
*
|
||||
* The test method is provided by the MigrateUpgradeTestBase class.
|
||||
*
|
||||
* @group migrate_drupal_ui
|
||||
*/
|
||||
class MigrateUpgrade6Test extends MigrateUpgradeTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->loadFixture(drupal_get_path('module', 'migrate_drupal') . '/tests/fixtures/drupal6.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSourceBasePath() {
|
||||
return __DIR__ . '/files';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityCounts() {
|
||||
return [
|
||||
'block' => 30,
|
||||
'block_content' => 2,
|
||||
'block_content_type' => 1,
|
||||
'comment' => 3,
|
||||
'comment_type' => 2,
|
||||
'contact_form' => 5,
|
||||
'editor' => 2,
|
||||
'field_config' => 62,
|
||||
'field_storage_config' => 43,
|
||||
'file' => 7,
|
||||
'filter_format' => 8,
|
||||
'image_style' => 5,
|
||||
'migration' => 105,
|
||||
'node' => 9,
|
||||
'node_type' => 11,
|
||||
'rdf_mapping' => 5,
|
||||
'search_page' => 2,
|
||||
'shortcut' => 2,
|
||||
'shortcut_set' => 1,
|
||||
'action' => 22,
|
||||
'menu' => 8,
|
||||
'taxonomy_term' => 6,
|
||||
'taxonomy_vocabulary' => 6,
|
||||
'tour' => 1,
|
||||
'user' => 7,
|
||||
'user_role' => 6,
|
||||
'menu_link_content' => 4,
|
||||
'view' => 12,
|
||||
'date_format' => 11,
|
||||
'entity_form_display' => 15,
|
||||
'entity_form_mode' => 1,
|
||||
'entity_view_display' => 32,
|
||||
'entity_view_mode' => 12,
|
||||
'base_field_override' => 33,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<h1>SimpleTest HTML</h1>
|
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 183 B |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 125 B |
|
@ -0,0 +1 @@
|
|||
<h1>SimpleTest HTML</h1>
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\migrate_drupal_ui\Tests\d7;
|
||||
|
||||
use Drupal\migrate_drupal_ui\Tests\MigrateUpgradeTestBase;
|
||||
|
||||
/**
|
||||
* Tests Drupal 7 upgrade using the migrate UI.
|
||||
*
|
||||
* The test method is provided by the MigrateUpgradeTestBase class.
|
||||
*
|
||||
* @group migrate_drupal_ui
|
||||
*/
|
||||
class MigrateUpgrade7Test extends MigrateUpgradeTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->loadFixture(drupal_get_path('module', 'migrate_drupal') . '/tests/fixtures/drupal7.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getSourceBasePath() {
|
||||
return __DIR__ . '/files';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityCounts() {
|
||||
return [
|
||||
'block' => 25,
|
||||
'block_content' => 1,
|
||||
'block_content_type' => 1,
|
||||
'comment' => 1,
|
||||
'comment_type' => 7,
|
||||
'contact_form' => 3,
|
||||
'editor' => 2,
|
||||
'field_config' => 41,
|
||||
'field_storage_config' => 31,
|
||||
'file' => 1,
|
||||
'filter_format' => 7,
|
||||
'image_style' => 6,
|
||||
'migration' => 59,
|
||||
'node' => 2,
|
||||
'node_type' => 6,
|
||||
'rdf_mapping' => 5,
|
||||
'search_page' => 2,
|
||||
'shortcut' => 6,
|
||||
'shortcut_set' => 2,
|
||||
'action' => 18,
|
||||
'menu' => 10,
|
||||
'taxonomy_term' => 18,
|
||||
'taxonomy_vocabulary' => 3,
|
||||
'tour' => 1,
|
||||
'user' => 3,
|
||||
'user_role' => 4,
|
||||
'menu_link_content' => 9,
|
||||
'view' => 12,
|
||||
'date_format' => 11,
|
||||
'entity_form_display' => 15,
|
||||
'entity_form_mode' => 1,
|
||||
'entity_view_display' => 22,
|
||||
'entity_view_mode' => 10,
|
||||
'base_field_override' => 7,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
|
Reference in a new issue