Issue #2936365 by quietone, mikelutz, heddn, larowlan, masipila, effulgentsia, maxocub, Gábor Hojtsy, webchick, phenaproxima, jhodgdon, catch: Migrate UI - allow modules to declare the state of their migrations

merge-requests/1119/head
Gábor Hojtsy 2019-07-10 20:14:17 +02:00
parent 0d82715b4b
commit c1734c6185
76 changed files with 2250 additions and 361 deletions

View File

@ -8,7 +8,7 @@ source:
plugin: variable
variables:
- actions_max_stack
source_module: action
source_module: system
process:
recursion_limit: actions_max_stack
destination:

View File

@ -0,0 +1,5 @@
finished:
6:
system: action
7:
system: action

View File

@ -0,0 +1,5 @@
finished:
6:
aggregator: aggregator
7:
aggregator: aggregator

View File

@ -0,0 +1,3 @@
finished:
7:
system: ban

View File

@ -0,0 +1,5 @@
finished:
6:
block: block
7:
block: block

View File

@ -0,0 +1,5 @@
finished:
6:
block: block_content
7:
block: block_content

View File

@ -11,7 +11,7 @@ use Drupal\content_translation\Plugin\migrate\source\I18nQueryTrait;
*
* @MigrateSource(
* id = "d7_block_custom_translation",
* source_module = "block"
* source_module = "i18n_block"
* )
*/
class BlockCustomTranslation extends DrupalSqlBase {

View File

@ -0,0 +1,5 @@
finished:
6:
book: book
7:
book: book

View File

@ -0,0 +1,3 @@
finished:
7:
color: color

View File

@ -0,0 +1,7 @@
finished:
6:
comment: comment
node: comment
7:
comment: comment
node: comment

View File

@ -0,0 +1,28 @@
finished:
6:
i18nprofile: config_translation
7:
i18n_variable: config_translation
not_finished:
6:
# language content comment settings.
locale: language
# @TODO: Move to finished when remaining Drupal 6 i18n issues are resolved.
# See https://www.drupal.org/project/drupal/issues/2208401
i18n: config_translation
# field labels and descriptions, synchronized fields.
i18ncck: config_translation
# Block, menu, taxonomy, User profiles.
i18nstrings: config_translation
i18ntaxonomy: config_translation
7:
# language content comment settings.
locale: language
# @TODO: Move to finished when remaining Drupal 7 i18n issues are resolved.
# See https://www.drupal.org/project/drupal/issues/2208401
i18n: config_translation
# field labels and descriptions, field options.
i18n_field: config_translation
i18n_string: config_translation
# localized. vocabulary language settings, taxonomy term language.
i18n_taxonomy: config_tanslation

View File

@ -0,0 +1,5 @@
finished:
6:
contact: contact
7:
contact: contact

View File

@ -0,0 +1,39 @@
finished:
6:
i18nblocks:
- block
- block_content
- content_translation
i18nmenu:
- content_translation
- menu_link_content
locale: content_translation
menu: content_translation
statistics: statistics
taxonomy: content_translation
7:
entity_translation: content_translation
i18n_block:
- block
- block_content
- content_translation
locale: content_translation
menu: content_translation
statistics: statistics
not_finished:
# Also D6 and D7 node revision translations.
6:
# @TODO: Move to finished when remaining Drupal 6 i18n issues are resolved.
# See https://www.drupal.org/project/drupal/issues/2208401
i18n: content_translation
# Taxonomy term references.
i18ntaxonomy: content_translation
7:
# @TODO: Move to finished when remaining Drupal 7 i18n issues are resolved.
# See https://www.drupal.org/project/drupal/issues/2208401
i18n: content_translation
# menu links.
i18n_menu: content_translation
# localized.
i18n_taxonomy: content_translation

View File

@ -0,0 +1,5 @@
finished:
6:
date: datetime
7:
date: datetime

View File

@ -0,0 +1,5 @@
finished:
6:
dblog: dblog
7:
dblog: dblog

View File

@ -10,6 +10,8 @@ source:
constants:
entity_type: node
langcode: en
# Phone is here since it does not use a migrate field plugin.
source_module: phone
process:
entity_type: 'constants/entity_type'
status: active

View File

@ -0,0 +1,12 @@
finished:
6:
content: field
email: core
# Phone does not use a migrate field plugin so it is added here.
phone: field
7:
email: core
entityreference: core
field: field
field_sql_storage: field
number: core

View File

@ -0,0 +1,8 @@
finished:
6:
filefield: file
system: file
upload: file
7:
file: file
system: file

View File

@ -0,0 +1,5 @@
finished:
6:
filter: filter
7:
filter: filter

View File

@ -0,0 +1,5 @@
finished:
6:
forum: forum
7:
forum: forum

View File

@ -0,0 +1,6 @@
finished:
6:
imagecache: image
imagefield: image
7:
image: image

View File

@ -7,7 +7,7 @@ source:
plugin: variable
variables:
- language_negotiation
source_module: language
source_module: locale
process:
session/parameter:
plugin: default_value

View File

@ -7,7 +7,7 @@ source:
plugin: variable
variables:
- language_negotiation
source_module: language
source_module: locale
process:
all:
plugin: default_value

View File

@ -13,7 +13,7 @@ source:
- locale_language_providers_weight_language
- locale_language_providers_weight_language_content
- locale_language_providers_weight_language_url
source_module: language
source_module: locale
process:
all:
plugin: language_types

View File

@ -0,0 +1,11 @@
finished:
6:
locale:
- language
- system
system: language
taxonomy: language
7:
locale:
- language
- system

View File

@ -0,0 +1,5 @@
finished:
6:
link: link
7:
link: link

View File

@ -0,0 +1,5 @@
finished:
6:
locale: locale
7:
locale: locale

View File

@ -0,0 +1,5 @@
finished:
6:
menu: menu_link_content
7:
menu: menu_link_content

View File

@ -0,0 +1,5 @@
finished:
6:
menu: menu_ui
7:
menu: menu_ui

View File

@ -17,7 +17,7 @@ class MigrateStatusTest extends MigrateTestBase {
public function testStatus() {
// Create a minimally valid migration.
$definition = [
'id' => 'migration_status_test',
'id' => 'migrate_status_test',
'migration_tags' => ['Testing'],
'source' => ['plugin' => 'empty'],
'destination' => [

View File

@ -25,3 +25,6 @@ services:
- '@plugin.manager.migrate.field'
- '@plugin.manager.migration'
- '@logger.channel.migrate_drupal'
migrate_drupal.migration_state:
class: Drupal\migrate_drupal\MigrationState
arguments: ['@plugin.manager.migrate.field', '@module_handler', '@messenger', '@string_translation']

View File

@ -0,0 +1,95 @@
# The modules listed here do not have an migration. A status of finished is
# assigned so that they appear in the will not be upgraded list on the Review
# form.
finished:
6:
nodereference: core
userreference: core
# Blog requires node.
blog: node
# The following do not have an upgrade path.
blogapi: core
calendarsignup: core
color: core
content_copy: core
content_multigroup: core
content_permissions: core
date_api: core
date_locale: core
date_php4: core
date_popup: core
date_repeat: core
date_timezone: core
date_tools: core
datepicker: core
ddblock: core
event: core
fieldgroup: core
filefield_meta: core
help: core
# i18n modules require content_translation.
i18ncontent: content_translation
i18npoll: content_translation
i18nstrings: content_translation
i18nsync: content_translation
imageapi: core
imageapi_gd: core
imageapi_imagemagick: core
imagecache_ui: core
nodeaccess: core
number: core
openid: core
php: core
ping: core
poll: core
throttle: core
tracker: core
translation: core
trigger: core
variable: core
variable_admin: core
views_export: core
views_ui: core
7:
# Blog requires node.
blog: node
# The following do not need have an upgrade path.
bulk_export: core
contextual: core
ctools: core
ctools_access_ruleset: core
ctools_ajax_sample: core
ctools_custom_content: core
dashboard: core
date_all_day: core
date_api: core
date_context: core
date_migrate: core
date_popup: core
date_repeat: core
date_repeat_field: core
date_tools: core
date_views: core
entity: core
entity_feature: core
entity_token: core
entityreference: core
field_ui: core
help: core
openid: core
overlay: core
page_manager: core
php: core
poll: core
search_embedded_form: core
search_extra_type: core
search_node_tags: core
simpletest: core
stylizer: core
term_depth: core
title: core
toolbar: core
translation: core
trigger: core
views_content: core
views_ui: core

View File

@ -0,0 +1,494 @@
<?php
namespace Drupal\migrate_drupal;
use Drupal\Core\Discovery\YamlDiscovery;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
/**
* Determines the migrate state for all modules enabled on the source.
*
* Retrieves migrate info from *.migrate_drupal.yml files.
*
* Knowing which modules will be upgraded and those that will not is needed by
* anyone upgrading a legacy Drupal version. This service provides that
* information by analyzing the existing migrations and data in
* migrate_drupal.yml files. Modules that are enabled or disabled in the source
* are included in the analysis modules that are uninstalled are ignored.
*
* Deciding the upgrade state of a source module is a complicated task. A
* destination module is not limited in any way to the source modules or the
* current major version destination modules it is providing migrations for. We
* see this in core where the Drupal 6 Menu module is upgraded by having
* migrations in three Drupal 8 modules; menu_link_content, menu_ui and system.
* If migrations for any of those three modules are not complete or if any of
* them are not installed on the destination site then the Drupal 6 Menu module
* cannot be listed as upgraded. If any one of the conditions are not met then
* it should be listed as will not be upgraded.
*
* Another challenge is to ensure that legacy source modules that do not need an
* upgrade path are handled correctly. These will not have migrations but should
* be listed as will be upgraded, which even though there are not migrations
* under the hood, it lets a site admin know that upgrading with this module
* enabled is safe.
*
* There is not enough information in the existing system to determine the
* correct state of the upgrade path for these, and other scenarios.
*
* The solution is for every destination module that is the successor to a
* module built for a legacy Drupal version to declare the state of the upgrade
* path(s) for the module. A module's upgrade path from a previous version may
* consist of one or more migrations sets. Each migration set definition
* consists of a source module supporting a legacy Drupal version, and one or
* more current destination modules. This allows a module to indicate that a
* provided migration set requires additional modules to be enabled in the
* destination.
*
* A migration set can be marked 'finished', which indicates that all
* migrations that are going to be provided by this destination module for this
* migration set have been written and are complete. A migration set may also
* be marked 'not_finished' which indicates that the module either has not
* provided any migrations for the set, or needs to provide additional
* migrations to complete the set. Note that other modules may still provide
* additional finished or not_finished migrations for the same migration set.
*
* Modules inform the upgrade process of the migration sets by adding them to
* their <module_name>.migrate_drupal.yml file.
*
* The <module_name>.migrate_drupal.yml file uses the following structure:
*
* # (optional) List of the source_module/destination_module(s) for the
* # migration sets that this module provides and are complete.
* finished:
* # One or more Drupal legacy version number mappings (i.e. 6 and/or 7).
* 6:
* # A mapping of legacy module machine names to either an array of modules
* # or a single destination module machine name to define this migration
* # set.
* <source_module_1>: <destination_module_1>
* <source_module_2>:
* - <destination_module_1>
* - <destination_module_2>
* 7:
* <source_module_1>: <destination_module_1>
* <source_module_2>:
* - <destination_module_1>
* - <destination_module_2>
* # (optional) List of the migration sets that this module provides, or will be
* # providing, that are incomplete or do not yet exist.
* not_finished:
* 6:
* <source_module_1>: <destination_module_1>
* <source_module_2>:
* - <destination_module_1>
* - <destination_module_2>
*
* Examples:
*
* @code
* finished:
* 6:
* node: node
* 7:
* node: node
* entity_translation: node
* not_finished:
* 7:
* commerce_product: commerce_product
* other_module:
* - other_module
* - further_module
* @endcode
*
* In this example the module has completed the upgrade path for data from the
* Drupal 6 and Drupal 7 Node modules to the Drupal 8 Node module and for data
* from the Drupal 7 Entity Translation module to the Drupal 8 Node module.
*
* @code
* finished:
* 6:
* pirate: pirate
* 7:
* pirate: pirate
* @endcode
*
* The Pirate module does not require an upgrade path. By declaring the upgrade
* finished the Pirate module will be included in the finished list. That is,
* as long as no other module has an entry "pirate: <any module name>' in its
* not_finished section.
*/
class MigrationState {
use MessengerTrait;
use StringTranslationTrait;
/**
* Source module upgrade state when all its migrations are complete.
*
* @var string
*/
const FINISHED = 'finished';
/**
* Source module upgrade state when all its migrations are not complete.
*
* @var string
*/
const NOT_FINISHED = 'not_finished';
/**
* The field plugin manager service.
*
* @var \Drupal\Core\Extension\ModuleHandler
*/
protected $moduleHandler;
/**
* The field plugin manager service.
*
* @var \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface
*/
protected $fieldPluginManager;
/**
* Source modules that will not be migrated determined using legacy method.
*
* @var array
*/
protected $unmigratedSourceModules = [];
/**
* Source modules that will be migrated determined using legacy method, keyed
* by version.
*
* @var array
*/
protected $migratedSourceModules = [];
/**
* An array of migration states declared for each source migration.
*
* States are keyed by version. Each value is an array keyed by name of the
* source module and the value is an array of all the states declared for this
* source module.
*
* @var array
*/
protected $stateBySource;
/**
* An array of destinations declared for each source migration.
*
* Destinations are keyed by version. Each value is an array keyed by the name
* of the source module and the value is an array of the destination modules.
*
* @var array
*/
protected $declaredBySource;
/**
* An array of migration source and destinations derived from migrations.
*
* The key is the source version and the value is an array where the key is
* the source module and the value is an array of destinations derived from
* migration plugins.
*
* @var array
*/
protected $discoveredBySource;
/**
* An array of migration source and destinations.
*
* Values are derived from migration plugins and declared states. The key is
* the source version and the value is an array where the key is the source
* module and the value is an array of declared or derived destinations.
*
* @var array
*/
protected $destinations = [];
/**
* Array of enabled modules.
*
* @var array
*/
protected $enabledModules = [];
/**
* Construct a new MigrationState object.
*
* @param \Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface $fieldPluginManager
* Field plugin manager.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
* Module handler.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* Messenger sevice.
* @param \Drupal\Core\StringTranslation\TranslationInterface $stringTranslation
* String translation service.
*/
public function __construct(MigrateFieldPluginManagerInterface $fieldPluginManager, ModuleHandlerInterface $moduleHandler, MessengerInterface $messenger, TranslationInterface $stringTranslation) {
$this->fieldPluginManager = $fieldPluginManager;
$this->moduleHandler = $moduleHandler;
$this->enabledModules = array_keys($this->moduleHandler->getModuleList());
$this->enabledModules[] = 'core';
$this->messenger = $messenger;
$this->stringTranslation = $stringTranslation;
}
/**
* Gets the upgrade states for all enabled source modules.
*
* @param string $version
* The legacy drupal version.
* @param array $source_system_data
* The data from the source site system table.
* @param array $migrations
* An array of migrations.
*
* @return array
* An associative array of data with keys of state, source modules and a
* value which is a comma separated list of destination modules.
*/
public function getUpgradeStates($version, array $source_system_data, array $migrations) {
return $this->buildUpgradeState($version, $source_system_data, $migrations);
}
/**
* Gets migration state information from *.migrate_drupal.yml.
*
* @return array
* An association array keyed by module of the finished and not_finished
* migrations for each module.
* */
protected function getMigrationStates() {
// Always instantiate a new YamlDiscovery object so that we always search on
// the up-to-date list of modules.
$discovery = new YamlDiscovery('migrate_drupal', array_map(function (&$value) {
return $value . '/migrations/state';
}, $this->moduleHandler->getModuleDirectories()));
return $discovery->findAll();
}
/**
* Determines migration state for each source module enabled on the source.
*
* If there are no migrations for a module and no declared state the state is
* set to NOT_FINISHED. When a module does not need any migrations, such as
* Overlay, a state of finished is declared in system.migrate_drupal.yml.
*
* If there are migrations for a module the following happens. If the
* destination module is 'core' the state is set to FINISHED. If there are
* any occurrences of 'not_finished' in the *.migrate_drupal.yml information
* for this source module then the state is set to NOT_FINISHED. And finally,
* if there is an occurrence of 'finished' the state is set to FINISHED.
*
* @param string $version
* The legacy drupal version.
* @param array $source_system_data
* The data from the source site system table.
* @param array $migrations
* An array of migrations.
*
* @return array
* An associative array of data with keys of state, source modules and a
* value which is a comma separated list of destination modules.
* Example.
*
* @code
* [
* 'finished' => [
* 'menu' => [
* 'menu_link_content','menu_ui','system'
* ]
* ],
* ]
* @endcode
*/
protected function buildUpgradeState($version, array $source_system_data, array $migrations) {
// Remove core profiles from the system data.
unset($source_system_data['module']['standard'], $source_system_data['module']['minimal']);
$this->buildDiscoveredDestinationsBySource($version, $migrations, $source_system_data);
$this->buildDeclaredStateBySource($version);
$upgrade_state = [];
// Loop through every source module that is enabled on the source site.
foreach ($source_system_data['module'] as $module) {
// The source plugins check requirements requires that all
// source_modules are enabled so do the same here.
if ($module['status']) {
$source_module = $module['name'];
// If there is not a declared state for this source module then use the
// legacy method for determining the migration state.
if (!isset($this->stateBySource[$version][$source_module])) {
// No migrations found for this source module.
if (!empty($this->unmigratedSourceModules[$version]) && array_key_exists($source_module, $this->unmigratedSourceModules[$version])) {
$upgrade_state[static::NOT_FINISHED][$source_module] = '';
continue;
}
if (!empty($this->migratedSourceModules[$version]) && array_key_exists($source_module, $this->migratedSourceModules[$version])) {
@trigger_error(sprintf("Using migration plugin definitions to determine the migration state of the module '%s' is deprecated in Drupal 8.7. Add the module to a migrate_drupal.yml file. See https://www.drupal.org/node/2929443", $source_module), E_USER_DEPRECATED);
if (array_diff(array_keys($this->migratedSourceModules[$version][$source_module]), $this->enabledModules)) {
$upgrade_state[static::NOT_FINISHED][$source_module] = implode(', ', array_keys($this->migratedSourceModules[$version][$source_module]));
continue;
}
$upgrade_state[static::FINISHED][$source_module] = implode(', ', array_keys($this->migratedSourceModules[$version][$source_module]));
}
continue;
}
$upgrade_state[$this->getSourceState($version, $source_module)][$source_module] = implode(', ', $this->getDestinationsForSource($version, $source_module));
}
}
foreach ($upgrade_state as $key => $value) {
ksort($upgrade_state[$key]);
}
return $upgrade_state;
}
/**
* Builds migration source and destination module information.
*
* @param string $version
* The legacy Drupal version.
* @param array $migrations
* The discovered migrations.
* @param array $source_system_data
* The data from the source site system table.
*/
protected function buildDiscoveredDestinationsBySource($version, array $migrations, array $source_system_data) {
$discovered_upgrade_paths = [];
$table_data = [];
foreach ($migrations as $migration) {
$migration_id = $migration->getPluginId();
$source_module = $migration->getSourcePlugin()->getSourceModule();
if (!$source_module) {
$this->messenger()
->addError($this->t('Source module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
$destination_module = $migration->getDestinationPlugin()
->getDestinationModule();
if (!$destination_module) {
$this->messenger()
->addError($this->t('Destination module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
if ($source_module && $destination_module) {
$discovered_upgrade_paths[$source_module][] = $destination_module;
$table_data[$source_module][$destination_module][$migration_id] = $migration->label();
}
}
// Add entries for the field plugins to discovered_upgrade_paths.
$definitions = $this->fieldPluginManager->getDefinitions();
foreach ($definitions as $definition) {
// This is not strict so that we find field plugins with an annotation
// where the Drupal core version is an integer and when it is a string.
if (in_array($version, $definition['core'])) {
$source_module = $definition['source_module'];
$destination_module = $definition['destination_module'];
$discovered_upgrade_paths[$source_module][] = $destination_module;
$table_data[$source_module][$destination_module][$definition['id']] = $definition['id'];
}
}
ksort($table_data);
foreach ($table_data as $source_module => $destination_module_info) {
ksort($table_data[$source_module]);
}
$tmp = array_diff_key($source_system_data['module'], $table_data);
foreach ($tmp as $source_module => $module_data) {
if ($module_data['status']) {
$this->unmigratedSourceModules[$version][$source_module] = $module_data;
}
}
$this->migratedSourceModules[$version] = $table_data;
$this->discoveredBySource[$version] = array_map('array_unique', $discovered_upgrade_paths);
}
/**
* Gets migration data from *.migrate_drupal.yml sorted by source module.
*
* @param string $version
* The legacy Drupal version.
*/
protected function buildDeclaredStateBySource($version) {
$migration_states = $this->getMigrationStates();
$state_by_source = [];
$dest_by_source = [];
$states = [static::FINISHED, static::NOT_FINISHED];
foreach ($migration_states as $module => $info) {
foreach ($states as $state) {
if (isset($info[$state][$version])) {
foreach ($info[$state][$version] as $source => $destination) {
// Add the state.
$state_by_source[$source][] = $state;
// Add the destination modules.
$dest_by_source += [$source => []];
$dest_by_source[$source] = array_merge($dest_by_source[$source], (array) $destination);
}
}
}
}
$this->stateBySource[$version] = array_map('array_unique', $state_by_source);
$this->declaredBySource[$version] = array_map('array_unique', $dest_by_source);
}
/**
* Tests if a destination exists for the given source module.
*
* @param string $version
* Source version of Drupal.
* @param string $source_module
* Source module.
*
* @return string
* Migration state, either 'finished' or 'not_finished'.
*/
protected function getSourceState($version, $source_module) {
// The state is finished only when no declarations of 'not_finished'
// were found and each destination module is enabled.
if (!$destinations = $this->getDestinationsForSource($version, $source_module)) {
// No discovered or declared state.
return MigrationState::NOT_FINISHED;
}
if (in_array(MigrationState::NOT_FINISHED, $this->stateBySource[$version][$source_module], TRUE) || !in_array(MigrationState::FINISHED, $this->stateBySource[$version][$source_module], TRUE)) {
return MigrationState::NOT_FINISHED;
}
if (array_diff($destinations, $this->enabledModules)) {
return MigrationState::NOT_FINISHED;
}
return MigrationState::FINISHED;
}
/**
* Get net destinations for source module.
*
* @param string $version
* Source version.
* @param string $source_module
* Source module.
*
* @return array
* Destination modules either declared by {modulename}.migrate_drupal.yml
* files or discovered from migration plugins.
*/
protected function getDestinationsForSource($version, $source_module) {
if (!isset($this->destinations[$version][$source_module])) {
$this->discoveredBySource[$version] += [$source_module => []];
$this->declaredBySource[$version] += [$source_module => []];
$destination = array_unique(array_merge($this->discoveredBySource[$version][$source_module], $this->declaredBySource[$version][$source_module]));
sort($destination);
$this->destinations[$version][$source_module] = $destination;
}
return $this->destinations[$version][$source_module];
}
}

View File

@ -0,0 +1,6 @@
name: Migrate state active test
type: module
description: Tests the 'active' migrate state
package: Testing
version: VERSION
core: 8.x

View File

@ -0,0 +1,19 @@
id: migrate_state_finished_test
label: Block content body field configuration
migration_tags:
- Drupal 6
- Drupal 7
- Configuration
source:
plugin: embedded_data
data_rows:
-
id: 1
ids:
id:
type: string
source_module: action
process: []
destination:
plugin: entity:field_config
destination_module: migrate_state_finished_test

View File

@ -0,0 +1,19 @@
id: migrate_state_finished_test1
label: Block content body field configuration
migration_tags:
- Drupal 6
- Drupal 7
- Configuration
source:
plugin: embedded_data
data_rows:
-
id: 1
ids:
id:
type: string
source_module: action
process: []
destination:
plugin: entity:field_config
destination_module: migrate_state_not_finished_test

View File

@ -0,0 +1,20 @@
finished:
6:
# A field migration
# migrate_state_finished_test: migrate_state_finished_test
aggregator: migrate_state_finished_test
action:
- migrate_state_finished_test
- migrate_state_not_finished_test
7:
# A field migration
# migrate_state_finished_test: migrate_state_finished_test
aggregator: migrate_state_finished_test
# Migrations
action:
- migrate_state_finished_test
- migrate_state_not_finished_test
not_finished:
7:
# Migrations
action: system

View File

@ -0,0 +1,18 @@
<?php
namespace Drupal\migrate_state_active_test\Plugin\migrate\field\d7;
use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase;
/**
* Field migration for testing migration states.
*
* @MigrateField(
* id = "fieldleft",
* core = {6,7},
* source_module = "aggregator",
* destination_module = "migrate_state_finished_test"
* )
*/
class FieldLeft extends FieldPluginBase {
}

View File

@ -0,0 +1,18 @@
<?php
namespace Drupal\migrate_state_active_test\Plugin\migrate\field\d7;
use Drupal\migrate_drupal\Plugin\migrate\field\FieldPluginBase;
/**
* Field migration for testing migration states.
*
* @MigrateField(
* id = "fieldright",
* core = {6,7},
* source_module = "aggregator",
* destination_module = "migrate_state_finished_test"
* )
*/
class FieldRight extends FieldPluginBase {
}

View File

@ -0,0 +1,6 @@
name: Migrate state no migrate_drupal.yml file test
type: module
description: Has a migration but Does not have a migrate_drupal.yml file.
package: Testing
version: VERSION
core: 8.x

View File

@ -0,0 +1,19 @@
id: migrate_state_no_file_test
label: Test
migration_tags:
- Drupal 6
- Drupal 7
- Configuration
source:
plugin: embedded_data
data_rows:
-
id: 1
ids:
id:
type: string
source_module: migrate_state_no_file_test
process: []
destination:
plugin: entity:field_config
destination_module: migrate_state_no_file_test

View File

@ -0,0 +1,6 @@
name: Migrate state no migration and no migrate_drupal.yml file test
type: module
description: Does not have a migration or migrate_drupal.yml file.
package: Testing
version: VERSION
core: 8.x

View File

@ -0,0 +1,6 @@
name: Migrate state incomplete test
type: module
description: Tests the 'incomplete' migrate state
package: Testing
version: VERSION
core: 8.x

View File

@ -0,0 +1,20 @@
id: migrate_state_not_finished_test
label: Migrate state incomplete test
migration_tags:
- Drupal 6
- Drupal 7
- Configuration
source:
plugin: embedded_data
data_rows:
-
entity_type: block_content
ids:
entity_type:
type: string
source_module: block
process:
entity_type: entity_type
destination:
plugin: entity:field_config
destination_module: migrate_state_not_finished_test

View File

@ -0,0 +1,9 @@
not_finished:
6:
block: migrate_state_not_finished_test
7:
# Override any finished declarations for this field plugin.
aggregator: field_left
# Override any finished declarations for this migration.
action: migrate_state_not_finished_test
block: migrate_state_not_finished_test

View File

@ -0,0 +1,48 @@
<?php
namespace Drupal\Tests\migrate_drupal\Kernel;
use Drupal\KernelTests\KernelTestBase;
/**
* Defines a class for testing deprecation error from MigrationState.
*
* @group migrate_drupal
* @group legacy
*/
class MigrationStateDeprecationTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = [
'migrate_drupal',
'migrate',
'migrate_state_no_file_test',
];
/**
* Tests migration state deprecation notice.
*
* Test that a module with a migration but without a .migrate_drupal.yml
* trigger deprecation errors.
*
* @doesNotPerformAssertions
* @expectedDeprecation Using migration plugin definitions to determine the migration state of the module 'migrate_state_no_file_test' is deprecated in Drupal 8.7. Add the module to a migrate_drupal.yml file. See https://www.drupal.org/node/2929443
*/
public function testUndeclaredDestinationDeprecation() {
$plugin_manager = \Drupal::service('plugin.manager.migration');
$all_migrations = $plugin_manager->createInstancesByTag('Drupal 7');
\Drupal::service('migrate_drupal.migration_state')
->getUpgradeStates(7, [
'module' => [
'migrate_state_no_file_test' => [
'name' => 'migrate_state_no_file_test',
'status' => TRUE,
],
],
], ['import' => $all_migrations['migrate_state_no_file_test']]);
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace Drupal\Tests\migrate_drupal\Kernel;
use Drupal\Component\Discovery\YamlDiscovery;
use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait;
use Drupal\migrate_drupal\MigrationConfigurationTrait;
/**
* Tests that core modules have a migrate_drupal.yml file as needed.
*
* Checks that each module that requires a migrate_drupal.yml has the file.
* Because more that one migrate_drupal.yml file may have the same entry the
* ValidateMigrationStateTest, which validates the file contents, is not able
* to determine that all the required files exits.
*
* @group migrate_drupal
*/
class StateFileExists extends MigrateDrupalTestBase {
use FileSystemModuleDiscoveryDataProviderTrait;
use MigrationConfigurationTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
// Test migrations states.
'migrate_state_finished_test',
'migrate_state_not_finished_test',
// Test missing migrate_drupal.yml.
'migrate_state_no_file_test',
];
/**
* Modules that should have a migrate_drupal.yml file.
*
* @var array
*/
protected $stateFileRequired = [
'action',
'aggregator',
'ban',
'block',
'block_content',
'book',
'color',
'comment',
'config_translation',
'contact',
'content_translation',
'datetime',
'dblog',
'field',
'file',
'filter',
'forum',
'image',
'language',
'link',
'locale',
'menu_link_content',
'migrate_state_finished_test',
'migrate_state_not_finished_test',
'menu_ui',
'migrate_drupal',
'node',
'options',
'path',
'rdf',
'search',
'shortcut',
'simpletest',
'statistics',
'syslog',
'system',
'taxonomy',
'telephone',
'text',
'tracker',
'update',
'user',
];
/**
* Tests that the migrate_drupal.yml files exist as needed.
*/
public function testMigrationState() {
// Install all available modules.
$module_handler = $this->container->get('module_handler');
$all_modules = $this->coreModuleListDataProvider();
$modules_enabled = $module_handler->getModuleList();
$modules_to_enable = array_keys(array_diff_key($all_modules, $modules_enabled));
$this->enableModules($modules_to_enable);
// Modules with a migrate_drupal.yml file.
$has_state_file = (new YamlDiscovery('migrate_drupal', array_map(function (&$value) {
return $value . '/migrations/state';
}, $module_handler->getModuleDirectories())))->findAll();
foreach ($this->stateFileRequired as $module) {
$this->assertArrayHasKey($module, $has_state_file, sprintf("Module '%s' should have a migrate_drupal.yml file", $module));
}
$this->assertEquals(count($this->stateFileRequired), count($has_state_file));
}
}

View File

@ -0,0 +1,170 @@
<?php
namespace Drupal\Tests\migrate_drupal\Kernel;
use Drupal\Component\Discovery\YamlDiscovery;
use Drupal\KernelTests\FileSystemModuleDiscoveryDataProviderTrait;
use Drupal\migrate_drupal\MigrationState;
/**
* Tests the migration state information in module.migrate_drupal.yml.
*
* This test checks that the discovered upgrade paths, which are based on the
* source_module and destination_module definition matches the declared
* upgrade paths in all the migrate_drupal.yml files.
*
* @group migrate_drupal
*/
class ValidateMigrationStateTest extends MigrateDrupalTestBase {
use FileSystemModuleDiscoveryDataProviderTrait;
/**
* {@inheritdoc}
*/
public static $modules = [
// Test migrations states.
'migrate_state_finished_test',
'migrate_state_not_finished_test',
];
/**
* Level separator of destination and source properties.
*/
const SEPARATOR = ',';
/**
* Tests the migration information in .migrate_drupal.yml.
*
* Checks that every discovered pair has a corresponding declaration in the
* declared pairs. The alternate check, that each declared pair has a
* corresponding discovered pair is not possible because declarations can be
* made for the two cases where migrations are yet to be written and where
* migrations are not needed.
*/
public function testMigrationState() {
$this->enableAllModules();
// Build an array for each migration keyed by provider. The value is a
// string consisting of the version number, the provider, the source_module
// and the destination module.
$discovered = [];
$versions = ['6', '7'];
/** @var \Drupal\migrate\Plugin\MigrationPluginManager $plugin_manager */
$plugin_manager = $this->container->get('plugin.manager.migration');
foreach ($versions as $version) {
$migrations = $plugin_manager->createInstancesByTag('Drupal ' . $version);
/** @var \Drupal\migrate\Plugin\Migration $migration */
foreach ($migrations as $migration) {
$definition = $migration->getPluginDefinition();
if (is_array($definition['provider'])) {
$provider = reset($definition['provider']);
}
else {
$provider = $definition['provider'];
}
$source_module = $migration->getSourcePlugin()->getSourceModule();
$destination_module = $migration->getDestinationPlugin()
->getDestinationModule();
$discovered[$version][] = implode(static::SEPARATOR, [
$version,
$provider,
$source_module,
$destination_module,
]);
}
}
// Add the field migrations.
/** @var \Drupal\migrate\Plugin\MigrationPluginManager $plugin_manager */
$definitions = $this->container->get('plugin.manager.migrate.field')
->getDefinitions();
foreach ($definitions as $key => $definition) {
foreach ($definition['core'] as $version) {
$discovered[$version][] = implode(static::SEPARATOR, [
$version,
$definition['provider'],
$definition['source_module'],
$definition['destination_module'],
]);
}
}
// Get the declared migration state information from .migrate_drupal.yml
// and build an array of source modules and there migration state. The
// destination is not used yet but can be later for validating the
// source/destination pairs with the actual source/destination pairs in the
// migrate plugins.
$system_info = (new YamlDiscovery('migrate_drupal', array_map(function (&$value) {
return $value . '/migrations/state/';
}, \Drupal::moduleHandler()->getModuleDirectories())))->findAll();
$declared = [];
$states = [MigrationState::FINISHED, MigrationState::NOT_FINISHED];
foreach ($system_info as $module => $info) {
foreach ($states as $state) {
if (isset($info[$state])) {
foreach ($info[$state] as $info_version => $migrate_info) {
foreach ($migrate_info as $source => $destination) {
// Do not add the source module i18nstrings or i18_string. The
// 18n migrations can have up to three source modules but only one
// can be handled in the migration.
if (($source !== 'i18nstrings') && ($source !== 'i18n_string')) {
foreach ((array) $destination as $dest) {
$key = [$info_version, $module, $source, trim($dest)];
$declared[$info_version][$state][] = implode(static::SEPARATOR, $key);
}
}
}
}
}
}
}
$versions = ['6', '7'];
foreach ($versions as $version) {
// Sort and make the array values unique.
sort($declared[$version][MigrationState::FINISHED]);
sort($declared[$version][MigrationState::NOT_FINISHED]);
$declared_unique[$version][MigrationState::FINISHED] = array_unique($declared[$version][MigrationState::FINISHED]);
$declared_unique[$version][MigrationState::NOT_FINISHED] = array_unique($declared[$version][MigrationState::NOT_FINISHED]);
sort($discovered[$version]);
$discovered_unique[$version] = array_unique($discovered[$version]);
// Assert that each discovered migration has a corresponding declaration
// in a migrate_drupal.yml.
foreach ($discovered_unique[$version] as $datum) {
$data = str_getcsv($datum);
$in_finished = in_array($datum, $declared_unique[$version][MigrationState::FINISHED]);
$in_not_finished = in_array($datum, $declared_unique[$version][MigrationState::NOT_FINISHED]);
$found = $in_finished || $in_not_finished;
$this->assertTrue($found, sprintf("No migration state found for version '%s' with source_module '%s' and destination_module '%s' declared in module '%s'", $data[0], $data[2], $data[3], $data[1]));
}
// Remove the declared finished from the discovered, leaving just the not
// finished, if there are any. These should have an entry in the declared
// not finished.
$discovered_not_finished = array_diff($discovered_unique[$version], $declared_unique[$version][MigrationState::FINISHED]);
foreach ($discovered_not_finished as $datum) {
$data = str_getcsv($datum);
$this->assertContains($datum, $declared_unique[$version][MigrationState::NOT_FINISHED], sprintf("No migration found for version '%s' with source_module '%s' and destination_module '%s' declared in module '%s'", $data[0], $data[2], $data[3], $data[1]));
}
}
}
/**
* Enable all available modules.
*/
protected function enableAllModules() {
// Install all available modules.
$module_handler = $this->container->get('module_handler');
$modules = $this->coreModuleListDataProvider();
$modules_enabled = $module_handler->getModuleList();
$modules_to_enable = array_keys(array_diff_key($modules, $modules_enabled));
$this->enableModules($modules_to_enable);
return $modules;
}
}

View File

@ -0,0 +1,618 @@
<?php
namespace Drupal\Tests\migrate_drupal\Unit;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_drupal\MigrationState;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
use Drupal\Tests\UnitTestCase;
use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\vfsStreamDirectory;
use org\bovigo\vfs\vfsStreamWrapper;
/**
* Defines a class for testing \Drupal\migrate_drupal\MigrationState.
*
* @group migrate_drupal
* @group legacy
*
* @coversDefaultClass \Drupal\migrate_drupal\MigrationState
*/
class MigrationStateUnitTest extends UnitTestCase {
/**
* Tests ::getUpgradeStates.
*
* @dataProvider providerGetUpgradeStates
*
* @covers ::getUpgradeStates
* @covers ::buildDiscoveredDestinationsBySource
* @covers ::buildDeclaredStateBySource
* @covers ::buildUpgradeState
* @covers ::getMigrationStates
* @covers ::getSourceState
* @covers ::getDestinationsForSource
*/
public function testGetUpgradeStates($modules_to_enable, $files, $field_plugins, $migrations, $source_system_data, $expected_7, $expected_6) {
$fieldPluginManager = $this->prophesize(MigrateFieldPluginManagerInterface::class);
$fieldPluginManager->getDefinitions()->willReturn($field_plugins);
$moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
$moduleHandler->getModuleList()->willReturn($modules_to_enable);
vfsStreamWrapper::register();
$root = new vfsStreamDirectory('modules');
vfsStreamWrapper::setRoot($root);
$url = vfsStream::url('modules');
foreach ($files as $module => $contents) {
$path = $url . '/' . $module . '/migrations/state';
mkdir($path, '0755', TRUE);
file_put_contents($path . '/' . $module . '.migrate_drupal.yml', $contents);
}
$moduleHandler->getModuleDirectories()
->willReturn(array_combine(array_keys($files), array_map(function ($module) use ($url) {
return $url . '/' . $module;
}, array_keys($files))));
$migrationState = new MigrationState($fieldPluginManager->reveal(), $moduleHandler->reveal(), $this->createMock(MessengerInterface::class), $this->getStringTranslationStub());
$all_migrations = [];
foreach ($migrations as $name => $values) {
$migration = $this->prophesize(MigrationInterface::class);
$source = $this->prophesize(MigrateSourceInterface::class);
$destination = $this->prophesize(MigrateDestinationInterface::class);
$source->getSourceModule()->willReturn($values['source_module']);
$destination->getDestinationModule()
->willReturn($values['destination_module']);
$migration->getSourcePlugin()->willReturn($source->reveal());
$migration->getDestinationPlugin()->willReturn($destination->reveal());
$migration->getPluginId()->willReturn($name);
$migration->label()->willReturn($name);
$all_migrations[] = $migration->reveal();
}
// Tests Drupal 7 states.
$states = $migrationState->getUpgradeStates(7, $source_system_data, $all_migrations);
$this->assertEquals($expected_7, $states);
$source_system_data['module']['content'] = [
'name' => 'content',
'status' => TRUE,
];
// Tests Drupal 6 states.
unset($source_system_data['module']['rdf'], $source_system_data['module']['filter']);
$states = $migrationState->getUpgradeStates(6, $source_system_data, []);
$this->assertEquals($expected_6, $states);
}
/**
* Data provider for testGetUpgradeStates.
*/
public function providerGetUpgradeStates() {
// Tests multiple scenarios:
// Not enabled and not declared.
// Destination module is not enabled.
// Destination module not enabled.
// Declared not finished.
// Not finished.
// No discovered or declared state.
// Declared finished by one module but not finished by another.
// Not declared and non compatible field plugin.
// Update path not needed.
$tests[0] = [
'modules_to_enable' => [
'entity_test' => [],
'node' => [],
'link' => [],
'rdf' => [],
],
'files' => [
'node' => <<<NODE
finished:
6:
content: node
node: node
7:
node: node
NODE
,
'entity_test' => <<<ENTITY_TEST
not_finished:
6:
entity_test: entity_test
7:
entity_test:
- entity_test
- entity_test_rev
ENTITY_TEST
,
'comment' => <<<COMMENT
finished:
6:
comment:
- comment
- node
7:
comment:
- comment
- node
COMMENT
,
'user' => <<<USER
finished:
6:
user: user
7:
user: user
USER
,
'profile' => <<<PROFILE
not_finished:
6:
profile: user
7:
profile: user
PROFILE
,
],
'field_plugins' => [
'datetime' => [
'id' => 'datetime',
'core' => [7],
'source_module' => 'date',
'destination_module' => 'datetime',
],
'link' => [
'id' => 'link',
'core' => [6, 7],
'source_module' => 'link',
'destination_module' => 'link',
],
],
'migrations' => [
'rdf' => [
'source_module' => 'rdf',
'destination_module' => 'rdf',
],
'filter' => [
'source_module' => 'filter',
'destination_module' => 'filter',
],
],
'source_system_data' => [
'module' => [
'entity_test' => [
'name' => 'entity_test',
'status' => TRUE,
],
'rdf' => [
'name' => 'rdf',
'status' => TRUE,
],
'node' => [
'name' => 'node',
'status' => TRUE,
],
'date' => [
'name' => 'date',
'status' => TRUE,
],
'link' => [
'name' => 'link',
'status' => TRUE,
],
'search' => [
'name' => 'search',
'status' => TRUE,
],
'filter' => [
'name' => 'filter',
'status' => TRUE,
],
'comment' => [
'name' => 'comment',
'status' => TRUE,
],
'standard' => [
'name' => 'standard',
'status' => TRUE,
],
'color' => [
'name' => 'color',
'status' => TRUE,
],
'user' => [
'name' => 'user',
'status' => TRUE,
],
'profile' => [
'name' => 'profile',
'status' => TRUE,
],
// Disabled, hence ignored.
'dblog' => [
'name' => 'dblog',
'status' => FALSE,
],
],
],
'expected_7' => [
MigrationState::NOT_FINISHED => [
// Not enabled and not declared.
'color' => '',
// Destination module comment is not enabled.
'comment' => 'comment, node',
// Destination module not enabled.
'date' => 'datetime',
// Declared not finished.
'entity_test' => 'entity_test, entity_test_rev',
// Destination module not enabled.
'filter' => 'filter',
// Not finished.
'profile' => 'user',
// No discovered or declared state.
'search' => '',
// Declared finished by one module but not finished by another.
'user' => 'user',
],
MigrationState::FINISHED => [
'link' => 'link',
'node' => 'node',
'rdf' => 'rdf',
],
],
'expected_6' => [
MigrationState::NOT_FINISHED => [
// Declared not finished.
'entity_test' => 'entity_test',
// Destination module comment is not enabled.
'comment' => 'comment, node',
'user' => 'user',
// Not finished.
'profile' => 'user',
// Not declared and non compatible field plugin.
'date' => '',
// No discovered or declared state.
'search' => '',
'color' => '',
],
MigrationState::FINISHED => [
'node' => 'node',
'content' => 'node',
// Update path not needed.
'link' => 'link',
],
],
];
// Test menu migration with all three required destination modules enabled.
$tests[1] = [
'modules_to_enable' => [
'menu_link_content' => [],
'menu_ui' => [],
'system' => [],
],
'files' => [
'system' => <<<SYSTEM
finished:
6:
menu:
- system
- menu_link_content
- menu_ui
7:
menu:
- system
- menu_link_content
- menu_ui
SYSTEM
,
'menu_link_content' => <<<MENU_LINK_CONTENT
finished:
6:
menu: menu_link_content
7:
menu: menu_link_content
MENU_LINK_CONTENT
,
'menu' => <<<MENU_UI
finished:
6:
menu: menu_ui
7:
menu: menu_ui
MENU_UI
,
],
'field_plugins' => [],
'migrations' => [
'system' => [
'source_module' => 'menu',
'destination_module' => 'system',
],
'menu_ui' => [
'source_module' => 'menu',
'destination_module' => 'menu_ui',
],
'menu_link_content' => [
'source_module' => 'menu',
'destination_module' => 'menu_link_content',
],
],
'source_system_data' => [
'module' => [
'menu' => [
'name' => 'menu',
'status' => TRUE,
],
'system' => [
'name' => 'system',
'status' => TRUE,
],
],
],
'expected_7' => [
MigrationState::NOT_FINISHED => [
'system' => '',
],
MigrationState::FINISHED => [
'menu' => 'menu_link_content, menu_ui, system',
],
],
'expected_6' => [
MigrationState::NOT_FINISHED => [
'system' => '',
'content' => '',
],
MigrationState::FINISHED => [
'menu' => 'menu_link_content, menu_ui, system',
],
],
];
// Test menu migration with menu_link_content uninstalled.
$tests[2] = $tests[1];
unset($tests[2]['modules_to_enable']['menu_link_content']);
unset($tests[2]['files']['menu_link_content']);
unset($tests[2]['migrations']['menu_link_content']);
$tests[2]['expected_7'] = [
MigrationState::NOT_FINISHED => [
'menu' => 'menu_link_content, menu_ui, system',
'system' => '',
],
];
$tests[2]['expected_6'] = [
MigrationState::NOT_FINISHED => [
'menu' => 'menu_link_content, menu_ui, system',
'system' => '',
'content' => '',
],
];
// Test menu migration with menu_ui uninstalled.
$tests[3] = $tests[1];
unset($tests[3]['modules_to_enable']['menu_ui']);
unset($tests[3]['files']['menu_ui']);
unset($tests[3]['migrations']['menu_ui']);
$tests[3]['expected_7'] = [
MigrationState::NOT_FINISHED => [
'menu' => 'menu_link_content, menu_ui, system',
'system' => '',
],
];
$tests[3]['expected_6'] = [
MigrationState::NOT_FINISHED => [
'menu' => 'menu_link_content, menu_ui, system',
'system' => '',
'content' => '',
],
];
// Test an i18n migration with all three required destination modules
// enabled.
$tests[4] = [
'modules_to_enable' => [
'block' => [],
'block_content' => [],
'content_translation' => [],
'system' => [],
],
'files' => [
'system' => <<<SYSTEM
finished:
6:
i18nblocks:
- block
- block_content
- content_translation
7:
i18nblocks:
- block
- block_content
- content_translation
SYSTEM
,
'block' => <<<BLOCK
finished:
6:
block: block
7:
block: block
BLOCK
,
'block_content' => <<<BLOCK_CONTENT
finished:
6:
block: block_content
7:
block: block_content
BLOCK_CONTENT
,
],
'field_plugins' => [],
'migrations' => [
'block' => [
'source_module' => 'block',
'destination_module' => 'block',
],
'block_content' => [
'source_module' => 'block',
'destination_module' => 'block_content',
],
'i18nblocks' => [
'source_module' => 'i18nblocks',
'destination_module' => 'content_translation',
],
],
'source_system_data' => [
'module' => [
'block' => [
'name' => 'block',
'status' => TRUE,
],
'i18nblocks' => [
'name' => 'i18nblocks',
'status' => TRUE,
],
'system' => [
'name' => 'system',
'status' => TRUE,
],
],
],
'expected_7' => [
MigrationState::NOT_FINISHED => [
'system' => '',
],
MigrationState::FINISHED => [
'block' => 'block, block_content',
'i18nblocks' => 'block, block_content, content_translation',
],
],
'expected_6' => [
MigrationState::NOT_FINISHED => [
'system' => '',
'content' => '',
],
MigrationState::FINISHED => [
'block' => 'block, block_content',
'i18nblocks' => 'block, block_content, content_translation',
],
],
];
// Test i18n_block migration with block uninstalled.
$tests[5] = $tests[4];
unset($tests[5]['modules_to_enable']['block']);
unset($tests[5]['files']['block']);
unset($tests[5]['migrations']['block']);
$tests[5]['expected_7'] = [
MigrationState::NOT_FINISHED => [
'system' => '',
'i18nblocks' => 'block, block_content, content_translation',
],
MigrationState::FINISHED => [
'block' => 'block_content',
],
];
$tests[5]['expected_6'] = [
MigrationState::NOT_FINISHED => [
'system' => '',
'content' => '',
'i18nblocks' => 'block, block_content, content_translation',
],
MigrationState::FINISHED => [
'block' => 'block_content',
],
];
// Tests modules that don't require an upgrade path.
$tests[6] = [
'modules_to_enable' => [
'system' => [],
'content_translation' => [],
],
'files' => [
'system' => <<<SYSTEM
finished:
6:
help: core
i18ncontent: content_translation
7:
help: core
i18ncontent: content_translation
SYSTEM
,
],
'field_plugins' => [],
'migrations' => [],
'source_system_data' => [
'module' => [
'system' => [
'name' => 'system',
'status' => TRUE,
],
'help' => [
'name' => 'help',
'status' => TRUE,
],
'i18ncontent' => [
'name' => 'i18ncontent',
'status' => TRUE,
],
],
],
'expected_7' => [
MigrationState::NOT_FINISHED => [
'system' => '',
],
MigrationState::FINISHED => [
'help' => 'core',
'i18ncontent' => 'content_translation',
],
],
'expected_6' => [
MigrationState::NOT_FINISHED => [
'system' => '',
'content' => '',
],
MigrationState::FINISHED => [
'help' => 'core',
'i18ncontent' => 'content_translation',
],
],
];
$tests[7] = $tests[6];
unset($tests[7]['modules_to_enable']['content_translation']);
$tests[7]['expected_7'] = [
MigrationState::NOT_FINISHED => [
'system' => '',
'i18ncontent' => 'content_translation',
],
MigrationState::FINISHED => [
'help' => 'core',
],
];
$tests[7]['expected_6'] = [
MigrationState::NOT_FINISHED => [
'system' => '',
'content' => '',
'i18ncontent' => 'content_translation',
],
MigrationState::FINISHED => [
'help' => 'core',
],
];
return $tests;
}
}

View File

@ -5,18 +5,26 @@ namespace Drupal\migrate_drupal_ui\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\migrate_drupal\MigrationState;
use Drupal\migrate_drupal\Plugin\MigrateFieldPluginManagerInterface;
use Drupal\migrate_drupal_ui\Batch\MigrateUpgradeImportBatch;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Migrate Upgrade review form.
*
* This confirmation form uses the source_module and destination_module
* properties on the source, destination and field plugins as well as the
* system data from the source to determine if there is a migration path for
* each module in the source.
* This confirmation form provides the user with a summary of all the modules
* enabled on the source site and whether they will be upgraded or not. Data
* from a module's .migrate_drupal.yml file and all the migration plugins
* (source, destination and field) for each enabled Drupal 8 module are used to
* decide the migration status for each enabled module on the source site.
*
* The migration status displayed on the Review page is a list of all the
* enabled modules on the source site divided into two categories, those that
* will not be upgraded and those that will be upgraded. The intention is to
* provide the admin with enough information to decide if it is OK to proceed
* with the upgrade.
*
* @internal
*/
@ -51,101 +59,11 @@ class ReviewForm extends MigrateUpgradeFormBase {
protected $migrations;
/**
* List of extensions that do not need an upgrade path.
* Migration state service.
*
* This property is an array where the keys are the major Drupal core version
* from which we are upgrading, and the values are arrays of extension names
* that do not need an upgrade path.
*
* @var array[]
* @var \Drupal\migrate_drupal\MigrationState
*/
protected $noUpgradePaths = [
'6' => [
'blog',
'blogapi',
'calendarsignup',
'color',
'content_copy',
'content_multigroup',
'content_permissions',
'date_api',
'date_locale',
'date_php4',
'date_popup',
'date_repeat',
'date_timezone',
'date_tools',
'datepicker',
'ddblock',
'event',
'fieldgroup',
'filefield_meta',
'help',
'i18nstrings',
'i18nsync',
'imageapi',
'imageapi_gd',
'imageapi_imagemagick',
'imagecache_ui',
'jquery_ui',
'nodeaccess',
'number',
'openid',
'php',
'ping',
'poll',
'throttle',
'tracker',
'translation',
'trigger',
'variable',
'variable_admin',
'views_export',
'views_ui',
],
'7' => [
'blog',
'bulk_export',
'contextual',
'ctools',
'ctools_access_ruleset',
'ctools_ajax_sample',
'ctools_custom_content',
'dashboard',
'date_all_day',
'date_api',
'date_context',
'date_migrate',
'date_popup',
'date_repeat',
'date_repeat_field',
'date_tools',
'date_views',
'entity',
'entity_feature',
'entity_token',
'entityreference',
'field_ui',
'help',
'openid',
'overlay',
'page_manager',
'php',
'poll',
'search_embedded_form',
'search_extra_type',
'search_node_tags',
'simpletest',
'stylizer',
'term_depth',
'title',
'toolbar',
'translation',
'trigger',
'views_content',
'views_ui',
],
];
protected $migrationState;
/**
* ReviewForm constructor.
@ -158,12 +76,15 @@ class ReviewForm extends MigrateUpgradeFormBase {
* The field plugin manager service.
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
* The private tempstore factory.
* @param \Drupal\migrate_drupal\MigrationState $migrationState
* Migration state service.
*/
public function __construct(StateInterface $state, MigrationPluginManagerInterface $migration_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, PrivateTempStoreFactory $tempstore_private) {
public function __construct(StateInterface $state, MigrationPluginManagerInterface $migration_plugin_manager, MigrateFieldPluginManagerInterface $field_plugin_manager, PrivateTempStoreFactory $tempstore_private, MigrationState $migrationState) {
parent::__construct($tempstore_private);
$this->state = $state;
$this->pluginManager = $migration_plugin_manager;
$this->fieldPluginManager = $field_plugin_manager;
$this->migrationState = $migrationState;
}
/**
@ -174,7 +95,8 @@ class ReviewForm extends MigrateUpgradeFormBase {
$container->get('state'),
$container->get('plugin.manager.migration'),
$container->get('plugin.manager.migrate.field'),
$container->get('tempstore.private')
$container->get('tempstore.private'),
$container->get('migrate_drupal.migration_state')
);
}
@ -192,7 +114,7 @@ class ReviewForm extends MigrateUpgradeFormBase {
// Get all the data needed for this form.
$version = $this->store->get('version');
$this->migrations = $this->store->get('migrations');
// Fetch the system data at the first opportunity.
// Fetch the source system data at the first opportunity.
$system_data = $this->store->get('system_data');
// If data is missing or this is the wrong step, start over.
@ -204,58 +126,10 @@ class ReviewForm extends MigrateUpgradeFormBase {
$form = parent::buildForm($form, $form_state);
$form['#title'] = $this->t('What will be upgraded?');
// Get the source_module and destination_module for each migration.
$migrations = $this->pluginManager->createInstances(array_keys($this->store->get('migrations')));
$table_data = [];
foreach ($migrations as $migration) {
$migration_id = $migration->getPluginId();
$source_module = $migration->getSourcePlugin()->getSourceModule();
if (!$source_module) {
$this->messenger()->addError($this->t('Source module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
$destination_module = $migration->getDestinationPlugin()->getDestinationModule();
if (!$destination_module) {
$this->messenger()->addError($this->t('Destination module not found for @migration_id.', ['@migration_id' => $migration_id]));
}
if ($source_module && $destination_module) {
$table_data[$source_module][$destination_module][$migration_id] = $migration->label();
}
}
// Get the source_module and destination_module from the field plugins.
$definitions = $this->fieldPluginManager->getDefinitions();
foreach ($definitions as $definition) {
// This is not strict so that we find field plugins with an annotation
// where the Drupal core version is an integer and when it is a string.
if (in_array($version, $definition['core'])) {
$source_module = $definition['source_module'];
$destination_module = $definition['destination_module'];
$table_data[$source_module][$destination_module][$definition['id']] = $definition['id'];
}
}
// Add source_module and destination_module for modules that do not need an
// upgrade path and are enabled on the source site.
foreach ($this->noUpgradePaths[$version] as $extension) {
if (isset($system_data['module'][$extension]) && $system_data['module'][$extension]['status']) {
$table_data[$extension]['core'][$extension] = $extension;
}
}
// Sort the table by source module names and within that destination
// module names.
ksort($table_data);
foreach ($table_data as $source_module => $destination_module_info) {
ksort($table_data[$source_module]);
}
// Remove core profiles from the system data.
foreach (['standard', 'minimal'] as $profile) {
unset($system_data['module'][$profile]);
}
$unmigrated_source_modules = array_diff_key($system_data['module'], $table_data);
// Get the upgrade states for the source modules.
$display = $this->migrationState->getUpgradeStates($version, $system_data, $migrations);
// Missing migrations.
$missing_module_list = [
@ -263,7 +137,7 @@ class ReviewForm extends MigrateUpgradeFormBase {
'#open' => TRUE,
'#title' => $this->t('Modules that will not be upgraded'),
'#summary_attributes' => ['id' => ['error']],
'#description' => $this->t('There are no modules installed on your new site to replace these modules. If you proceed with the upgrade now, configuration and/or content needed by these modules will not be available on your new site. For more information, see <a href=":review">Review the pre-upgrade analysis</a> in the <a href=":migrate">Upgrading to Drupal 8</a> handbook.', [':review' => 'https://www.drupal.org/docs/8/upgrade/upgrade-using-web-browser#pre-upgrade-analysis', ':migrate' => 'https://www.drupal.org/docs/8/upgrade']),
'#description' => $this->t("The new site is missing modules corresponding to the old site's modules. Unless they are installed prior to the upgrade, configuration and/or content needed by them will not be available on your new site. <a href=':review'>Read the checklist</a> to help decide what to do.", [':review' => 'https://www.drupal.org/docs/8/upgrade/upgrade-using-web-browser#pre-upgrade-analysis']),
'#weight' => 2,
];
$missing_module_list['module_list'] = [
@ -273,12 +147,14 @@ class ReviewForm extends MigrateUpgradeFormBase {
$this->t('Drupal 8'),
],
];
$missing_count = 0;
ksort($unmigrated_source_modules);
foreach ($unmigrated_source_modules as $source_module => $module_data) {
if ($module_data['status']) {
if (isset($display[MigrationState::NOT_FINISHED])) {
foreach ($display[MigrationState::NOT_FINISHED] as $source_module => $destination_modules) {
$missing_count++;
$missing_module_list['module_list'][$source_module] = [
// Get the migration status for this $source_module, if a module of the
// same name exists on the destination site.
$missing_module_list['module_list'][] = [
'source_module' => [
'#type' => 'html_tag',
'#tag' => 'span',
@ -290,7 +166,9 @@ class ReviewForm extends MigrateUpgradeFormBase {
],
],
],
'destination_module' => ['#plain_text' => 'Not upgraded'],
'destination_module' => [
'#plain_text' => $destination_modules,
],
];
}
}
@ -300,7 +178,7 @@ class ReviewForm extends MigrateUpgradeFormBase {
'#type' => 'details',
'#title' => $this->t('Modules that will be upgraded'),
'#summary_attributes' => ['id' => ['checked']],
'#weight' => 3,
'#weight' => 4,
];
$available_module_list['module_list'] = [
@ -312,29 +190,26 @@ class ReviewForm extends MigrateUpgradeFormBase {
];
$available_count = 0;
foreach ($table_data as $source_module => $destination_module_info) {
$available_count++;
$destination_details = [];
foreach ($destination_module_info as $destination_module => $migration_ids) {
$destination_details[$destination_module] = [
'#type' => 'item',
'#plain_text' => $destination_module,
];
}
$available_module_list['module_list'][$source_module] = [
'source_module' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $source_module,
'#attributes' => [
'class' => [
'upgrade-analysis-report__status-icon',
'upgrade-analysis-report__status-icon--checked',
if (isset($display[MigrationState::FINISHED])) {
foreach ($display[MigrationState::FINISHED] as $source_module => $destination_modules) {
$available_count++;
$available_module_list['module_list'][] = [
'source_module' => [
'#type' => 'html_tag',
'#tag' => 'span',
'#value' => $source_module,
'#attributes' => [
'class' => [
'upgrade-analysis-report__status-icon',
'upgrade-analysis-report__status-icon--checked',
],
],
],
],
'destination_module' => $destination_details,
];
'destination_module' => [
'#plain_text' => $destination_modules,
],
];
}
}
$counters = [];

View File

@ -117,7 +117,7 @@ abstract class MigrateUpgradeExecuteTestBase extends MigrateUpgradeTestBase {
// Ensure there are no errors about any other missing migration providers.
$session->pageTextNotContains(t('module not found'));
// Test the upgrade paths.
// Test the review page.
$available_paths = $this->getAvailablePaths();
$missing_paths = $this->getMissingPaths();
$this->assertReviewPage($session, $available_paths, $missing_paths);
@ -146,12 +146,7 @@ abstract class MigrateUpgradeExecuteTestBase extends MigrateUpgradeTestBase {
$this->drupalPostForm(NULL, [], t('I acknowledge I may lose data. Continue anyway.'));
$session->statusCodeEquals(200);
// Need to update available and missing path lists.
$all_available = $this->getAvailablePaths();
$all_available[] = 'aggregator';
$all_missing = $this->getMissingPaths();
$all_missing = array_diff($all_missing, ['aggregator']);
$this->assertReviewPage($session, $all_available, $all_missing);
// Run the incremental migration and check the results.
$this->drupalPostForm(NULL, [], t('Perform upgrade'));
$session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
$this->assertMigrationResults($this->getEntityCountsIncremental(), $version);

View File

@ -169,13 +169,13 @@ abstract class MigrateUpgradeTestBase extends BrowserTestBase {
* Helper method to assert the text on the 'Upgrade analysis report' page.
*
* @param \Drupal\Tests\WebAssert $session
* The current session.
* @param array $all_available
* Array of modules that will be upgraded.
* @param array $all_missing
* Array of modules that will not be upgraded.
* The web-assert session.
* @param array $available_paths
* An array of modules that will be upgraded.
* @param array $missing_paths
* An array of modules that will not be upgraded.
*/
protected function assertReviewPage(WebAssert $session, array $all_available, array $all_missing) {
protected function assertReviewPage(WebAssert $session, array $available_paths, array $missing_paths) {
$this->assertText('What will be upgraded?');
// Ensure there are no errors about the missing modules from the test module.
@ -185,17 +185,7 @@ abstract class MigrateUpgradeTestBase extends BrowserTestBase {
// Ensure there are no errors about any other missing migration providers.
$session->pageTextNotContains(t('module not found'));
// Test the available migration paths.
foreach ($all_available as $available) {
$session->elementExists('xpath', "//span[contains(@class, 'checked') and text() = '$available']");
$session->elementNotExists('xpath', "//span[contains(@class, 'error') and text() = '$available']");
}
// Test the missing migration paths.
foreach ($all_missing as $missing) {
$session->elementExists('xpath', "//span[contains(@class, 'error') and text() = '$missing']");
$session->elementNotExists('xpath', "//span[contains(@class, 'checked') and text() = '$missing']");
}
$this->assertUpgradePaths($session, $available_paths, $missing_paths);
}
/**

View File

@ -36,11 +36,11 @@ abstract class MultilingualReviewPageTestBase extends MigrateUpgradeTestBase {
* Overlay.
*
* To do this all modules in the source fixtures are enabled, except test and
* example modules. This means that we can test that the modules listed in the
* the $noUpgradePath property of the update form class are correct, since
* there will be no available migrations which declare those modules as their
* source_module. It is assumed that the test fixtures include all modules
* that have moved to or dropped from core.
* example modules. This means that we can test that the modules that do not
* need any migrations, such as Overlay, since there will be no available
* migrations which declare those modules as their source_module. It is
* assumed that the test fixtures include all modules that have moved to or
* dropped from core.
*
* The upgrade review form will also display errors for each migration that
* does not have a source_module definition. That function is not tested here.
@ -68,10 +68,9 @@ abstract class MultilingualReviewPageTestBase extends MigrateUpgradeTestBase {
$missing_paths = $this->getMissingPaths();
$this->assertUpgradePaths($session, $available_paths, $missing_paths);
// Check there are no errors when a module in noUpgradePaths is not in the
// source system tables. Test with a module that is listed in noUpgradePaths
// for both Drupal 6 and Drupal 7.
// @see \Drupal\migrate_drupal_ui\Form\ReviewForm::$noUpgradePaths
// Check there are no errors when a module does not have any migrations and
// does not need any. Test with a module that is was in both Drupal 6 and
// Drupal 7 core.
$module = 'help';
$query = $this->sourceDatabase->delete('system');
$query->condition('type', 'module');
@ -84,7 +83,8 @@ abstract class MultilingualReviewPageTestBase extends MigrateUpgradeTestBase {
$this->drupalPostForm(NULL, $this->edits, t('Review upgrade'));
$this->drupalPostForm(NULL, [], t('I acknowledge I may lose data. Continue anyway.'));
// Test the upgrade paths.
// Test the upgrade paths. First remove the module from the available paths
// list.
$available_paths = $this->getAvailablePaths();
$available_paths = array_diff($available_paths, [$module]);
$missing_paths = $this->getMissingPaths();
@ -138,6 +138,16 @@ abstract class MultilingualReviewPageTestBase extends MigrateUpgradeTestBase {
$conditions->condition('name', 'simpletest');
$update->condition($conditions);
$update->execute();
// Create entries for D8 test modules.
$insert = $this->sourceDatabase->insert('system')
->fields([
'filename' => 'migrate_status_active_test',
'name' => 'migrate_status_active_test',
'type' => 'module',
'status' => 1,
]);
$insert->execute();
}
/**

View File

@ -11,6 +11,8 @@ use Drupal\Tests\migrate_drupal_ui\Functional\MultilingualReviewPageTestBase;
*
* @group migrate_drupal_6
* @group migrate_drupal_ui
*
* @group legacy
*/
class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
@ -31,6 +33,13 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
'update',
// Required for translation migrations.
'migrate_drupal_multilingual',
// Test migrations states.
'migrate_state_finished_test',
'migrate_state_not_finished_test',
// Test missing migrate_drupal.yml.
'migrate_state_no_file_test',
// Test missing migrate_drupal.yml.
'migrate_state_no_upgrade_path',
];
/**
@ -53,55 +62,20 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
*/
protected function getAvailablePaths() {
return [
// Aggregator is set not_finished in migrate_sate_not_finished_test.
'aggregator',
'block',
'blog',
'blogapi',
'book',
'calendarsignup',
'color',
'comment',
'contact',
'content',
'date',
'dblog',
'email',
'filefield',
'filter',
'forum',
'i18n',
'i18nblocks',
'i18ncck',
'i18nmenu',
'i18nprofile',
'i18nstrings',
'i18ntaxonomy',
'imagecache',
'imagefield',
'language',
'link',
'locale',
'menu',
'node',
'nodereference',
'optionwidgets',
'path',
'profile',
'search',
'statistics',
'syslog',
'system',
'taxonomy',
'text',
'update',
'upload',
'user',
'userreference',
// Include modules that do not have an upgrade path, defined in the
// $noUpgradePath property in MigrateUpgradeForm.
'blog',
'blogapi',
'calendarsignup',
'color',
'content_copy',
'content_multigroup',
'content_permissions',
'date',
'date_api',
'date_locale',
'date_php4',
@ -110,27 +84,57 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
'date_timezone',
'date_tools',
'datepicker',
'dblog',
'ddblock',
'email',
'event',
'fieldgroup',
'filefield',
'filefield_meta',
'filter',
'forum',
'help',
'i18nblocks',
'i18ncontent',
'i18nmenu',
'i18npoll',
'i18nprofile',
'i18nsync',
'imageapi',
'imageapi_gd',
'imageapi_imagemagick',
'imagecache',
'imagecache_ui',
'imagefield',
'jquery_ui',
'link',
'menu',
'node',
'nodeaccess',
'nodereference',
'number',
'openid',
'optionwidgets',
'path',
'phone',
'php',
'ping',
'poll',
'profile',
'search',
'statistics',
'syslog',
'system',
'taxonomy',
'text',
'throttle',
'tracker',
'translation',
'trigger',
'update',
'upload',
'user',
'userreference',
'variable',
'variable_admin',
'views_export',
@ -143,13 +147,18 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
*/
protected function getMissingPaths() {
return [
// Block is set not_finished in migrate_sate_not_finished_test.
'block',
'devel',
'devel_generate',
'devel_node_access',
'i18ncontent',
'i18npoll',
'i18n',
'i18ncck',
'i18nstrings',
'i18ntaxonomy',
'i18nviews',
'phone',
'locale',
'migrate_status_active_test',
'views',
];
}

View File

@ -12,6 +12,8 @@ use Drupal\Tests\migrate_drupal_ui\Functional\NoMultilingualReviewPageTestBase;
*
* @group migrate_drupal_6
* @group migrate_drupal_ui
*
* @group legacy
*/
class NoMultilingualReviewPageTest extends NoMultilingualReviewPageTestBase {
@ -28,6 +30,11 @@ class NoMultilingualReviewPageTest extends NoMultilingualReviewPageTestBase {
'syslog',
'tracker',
'update',
// Test migrations states.
'migrate_state_finished_test',
'migrate_state_not_finished_test',
// Test missing migrate_drupal.yml.
'migrate_state_no_file_test',
];
/**
@ -51,47 +58,18 @@ class NoMultilingualReviewPageTest extends NoMultilingualReviewPageTestBase {
protected function getAvailablePaths() {
return [
'aggregator',
'block',
'blog',
'blogapi',
'book',
'calendarsignup',
'color',
'comment',
'contact',
'content',
'date',
'dblog',
'email',
'filefield',
'filter',
'forum',
'imagecache',
'imagefield',
'language',
'link',
'locale',
'menu',
'node',
'nodereference',
'optionwidgets',
'path',
'profile',
'search',
'statistics',
'syslog',
'system',
'taxonomy',
'text',
'update',
'upload',
'user',
'userreference',
// Include modules that do not have an upgrade path, defined in the
// $noUpgradePath property in MigrateUpgradeForm.
'blog',
'blogapi',
'calendarsignup',
'color',
'content_copy',
'content_multigroup',
'content_permissions',
'date',
'date_api',
'date_locale',
'date_php4',
@ -100,28 +78,52 @@ class NoMultilingualReviewPageTest extends NoMultilingualReviewPageTestBase {
'date_timezone',
'date_tools',
'datepicker',
'dblog',
'ddblock',
'email',
'event',
'fieldgroup',
'filefield',
'filefield_meta',
'filter',
'forum',
'help',
'i18nstrings',
'i18nsync',
'imageapi',
'imageapi_gd',
'imageapi_imagemagick',
'imagecache',
'imagecache_ui',
'imagefield',
'jquery_ui',
'link',
'locale',
'menu',
'node',
'nodeaccess',
'nodereference',
'number',
'openid',
'optionwidgets',
'path',
'phone',
'php',
'ping',
'poll',
'profile',
'search',
'statistics',
'syslog',
'system',
'taxonomy',
'text',
'throttle',
'tracker',
'translation',
'trigger',
'update',
'upload',
'user',
'userreference',
'variable',
'variable_admin',
'views_export',
@ -129,11 +131,20 @@ class NoMultilingualReviewPageTest extends NoMultilingualReviewPageTestBase {
];
}
/**
* {@inheritdoc}
*/
protected function getIncompletePaths() {
return [];
}
/**
* {@inheritdoc}
*/
protected function getMissingPaths() {
return [
// Block is set not_finished in migrate_state_not_finished_test.
'block',
'devel',
'devel_generate',
'devel_node_access',
@ -144,9 +155,11 @@ class NoMultilingualReviewPageTest extends NoMultilingualReviewPageTestBase {
'i18nmenu',
'i18npoll',
'i18nprofile',
'i18nstrings',
'i18nsync',
'i18ntaxonomy',
'i18nviews',
'phone',
'migrate_status_active_test',
'views',
];
}

View File

@ -128,7 +128,6 @@ class NoMultilingualTest extends MigrateUpgradeExecuteTestBase {
'forum',
'imagecache',
'imagefield',
'language',
'link',
'locale',
'menu',
@ -146,8 +145,7 @@ class NoMultilingualTest extends MigrateUpgradeExecuteTestBase {
'user',
'userreference',
// Include modules that do not have an upgrade path and are enabled in the
// source database, defined in the $noUpgradePath property
// in MigrateUpgradeForm.
// source database.
'date_api',
'date_timezone',
'event',

View File

@ -12,6 +12,8 @@ use Drupal\user\Entity\User;
* The test method is provided by the MigrateUpgradeTestBase class.
*
* @group migrate_drupal_ui
*
* @group legacy
*/
class Upgrade6Test extends MigrateUpgradeExecuteTestBase {
@ -130,40 +132,33 @@ class Upgrade6Test extends MigrateUpgradeExecuteTestBase {
'contact',
'content',
'date',
'dblog',
'email',
'filefield',
'filter',
'forum',
'i18n',
'i18nblocks',
'i18ncck',
'i18ncontent',
'i18nmenu',
'i18nprofile',
'i18nstrings',
'i18ntaxonomy',
'i18nsync',
'imagecache',
'imagefield',
'language',
'link',
'locale',
'menu',
'node',
'nodereference',
'optionwidgets',
'path',
'profile',
'search',
'statistics',
'system',
'taxonomy',
'text',
'translation',
'upload',
'user',
'userreference',
// Include modules that do not have an upgrade path and are enabled in the
// source database, defined in the $noUpgradePath property
// in MigrateUpgradeForm.
// source database'.
'date_api',
'date_timezone',
'event',
@ -180,7 +175,11 @@ class Upgrade6Test extends MigrateUpgradeExecuteTestBase {
*/
protected function getMissingPaths() {
return [
'i18ncontent',
'i18n',
'i18ncck',
'i18nstrings',
'i18ntaxonomy',
'locale',
];
}

View File

@ -11,6 +11,8 @@ use Drupal\Tests\migrate_drupal_ui\Functional\MultilingualReviewPageTestBase;
*
* @group migrate_drupal_7
* @group migrate_drupal_ui
*
* @group legacy
*/
class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
@ -30,6 +32,11 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
'update',
// Required for translation migrations.
'migrate_drupal_multilingual',
// Test migrations states.
'migrate_state_finished_test',
'migrate_state_not_finished_test',
// Test missing migrate_drupal.yml.
'migrate_state_no_file_test',
];
/**
@ -52,55 +59,21 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
*/
protected function getAvailablePaths() {
return [
'aggregator',
'block',
'blog',
'book',
'bulk_export',
'color',
'comment',
'contact',
'date',
'dblog',
'email',
'field',
'field_sql_storage',
'file',
'filter',
'forum',
'image',
'i18n_block',
'language',
'link',
'list',
'locale',
'menu',
'node',
'number',
'options',
'path',
'phone',
'rdf',
'search',
'shortcut',
'statistics',
'syslog',
'system',
'taxonomy',
'text',
'tracker',
'update',
'user',
// Include modules that do not have an upgrade path, defined in the
// $noUpgradePath property in MigrateUpgradeForm.
'blog',
'bulk_export',
'contextual',
'ctools',
'ctools_access_ruleset',
'ctools_ajax_sample',
'ctools_custom_content',
'dashboard',
'date_all_day',
'date',
'date_api',
'date_all_day',
'date_context',
'date_migrate',
'date_popup',
@ -108,28 +81,58 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
'date_repeat_field',
'date_tools',
'date_views',
'dblog',
'email',
'entity',
'entity_feature',
'entity_token',
'entityreference',
'entity_translation',
'entityreference',
'field',
'field_sql_storage',
'field_ui',
'file',
'filter',
'forum',
'help',
'i18n_block',
'image',
'link',
'list',
'locale',
'menu',
'node',
'number',
'openid',
'options',
'overlay',
'page_manager',
'path',
'phone',
'php',
'poll',
'profile',
'rdf',
'search',
'search_embedded_form',
'search_extra_type',
'search_node_tags',
'shortcut',
'simpletest',
'statistics',
'stylizer',
'syslog',
'system',
'taxonomy',
'term_depth',
'text',
'title',
'toolbar',
'tracker',
'translation',
'trigger',
'update',
'user',
'views_content',
'views_ui',
];
@ -140,6 +143,11 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
*/
protected function getMissingPaths() {
return [
// Action is set not_finished in migrate_sate_not_finished_test.
// Aggregator is set not_finished in migrate_sate_not_finished_test.
'aggregator',
// Block is set not_finished in migrate_sate_not_finished_test.
'block',
'breakpoints',
'entity_translation_i18n_menu',
'entity_translation_upgrade',
@ -162,7 +170,7 @@ class MultilingualReviewPageTest extends MultilingualReviewPageTestBase {
'i18n_user',
'i18n_variable',
'picture',
'profile',
'migrate_status_active_test',
'variable',
'variable_admin',
'variable_realm',

View File

@ -148,8 +148,7 @@ class NoMultilingualTest extends MigrateUpgradeExecuteTestBase {
'text',
'user',
// Include modules that do not have an upgrade path and are enabled in the
// source database, defined in the $noUpgradePath property
// in MigrateUpgradeForm.
// source database.
'blog',
'contextual',
'date_api',
@ -164,6 +163,13 @@ class NoMultilingualTest extends MigrateUpgradeExecuteTestBase {
];
}
/**
* {@inheritdoc}
*/
protected function getIncompletePaths() {
return [];
}
/**
* {@inheritdoc}
*/

View File

@ -12,6 +12,8 @@ use Drupal\user\Entity\User;
* The test method is provided by the MigrateUpgradeTestBase class.
*
* @group migrate_drupal_ui
*
* @group legacy
*/
class Upgrade7Test extends MigrateUpgradeExecuteTestBase {
@ -128,21 +130,22 @@ class Upgrade7Test extends MigrateUpgradeExecuteTestBase {
'color',
'comment',
'contact',
'ctools',
'date',
'dblog',
'email',
'entity_translation',
'entityreference',
'field',
'field_sql_storage',
'file',
'filter',
'forum',
'i18n_block',
'i18n_variable',
'image',
'language',
'link',
'list',
'locale',
'menu',
'node',
'number',
@ -156,10 +159,10 @@ class Upgrade7Test extends MigrateUpgradeExecuteTestBase {
'system',
'taxonomy',
'text',
'title',
'user',
// Include modules that do not have an upgrade path and are enabled in the
// source database, defined in the $noUpgradePath property
// in MigrateUpgradeForm.
// source database.
'blog',
'contextual',
'date_api',
@ -180,6 +183,9 @@ class Upgrade7Test extends MigrateUpgradeExecuteTestBase {
protected function getMissingPaths() {
return [
'i18n',
'i18n_field',
'i18n_string',
'locale',
'variable',
'variable_realm',
'variable_store',

View File

@ -0,0 +1,6 @@
finished:
6:
content: node
node: node
7:
node: node

View File

@ -0,0 +1,6 @@
finished:
6:
optionwidgets: options
7:
options: options
list: options

View File

@ -0,0 +1,5 @@
finished:
6:
path: path
7:
path: path

View File

@ -0,0 +1,3 @@
finished:
7:
rdf: rdf

View File

@ -0,0 +1,5 @@
finished:
6:
search: search
7:
search: search

View File

@ -0,0 +1,3 @@
finished:
7:
shortcut: shortcut

View File

@ -0,0 +1,5 @@
finished:
6:
simpletest: simpletest
7:
simpletest: simpletest

View File

@ -0,0 +1,5 @@
finished:
6:
statistics: statistics
7:
statistics: statistics

View File

@ -0,0 +1,5 @@
finished:
6:
syslog: syslog
7:
syslog: syslog

View File

@ -0,0 +1,15 @@
finished:
6:
menu:
- system
- menu_link_content
- menu_ui
system: system
# An upgrade path is not needed for jquery_ui.
jquery_ui: core
7:
menu:
- system
- menu_link_content
- menu_ui
system: system

View File

@ -0,0 +1,9 @@
finished:
6:
taxonomy:
- core
- taxonomy
7:
taxonomy:
- core
- taxonomy

View File

@ -0,0 +1,3 @@
finished:
7:
phone: telephone

View File

@ -0,0 +1,5 @@
finished:
6:
text: text
7:
text: text

View File

@ -0,0 +1,3 @@
finished:
7:
tracker: tracker

View File

@ -0,0 +1,5 @@
finished:
6:
update: update
7:
update: update

View File

@ -0,0 +1,7 @@
finished:
6:
profile: user
user: user
7:
profile: user
user: user