6 minute read Published: Author: Matt Parker
Drupal Planet , Migrations



Easy commit credits with migrations, part 5: Declaring a module’s migration status

This is the fifth in a series of blog posts on writing migrations for contrib modules:

Stay tuned for more in this series!

Background

While migrating off Drupal 7 Core is very easy, there are still many contrib modules without any migrations. Any sites built using a low-code approach likely use a lot of contrib modules, and are likely blocked from migrating because of contrib. But — as of this writing — Drupal 7 still makes up 60% of all Drupal sites, and time is running out to migrate them!

If we are to make Drupal the go-to technology for site builders, we need to remember that migrating contrib is part of the Site Builder experience too. If we make migrating easy, then fewer site builders will put off the upgrade or abandon Drupal. Plus, contributing to migrations gives us the opportunity to gain recognition in the Drupal community with contribution credits.

Problem / motivation

In the last blog post, we walked through the process of creating a simple configuration migration — but I noted that, even after you’ve built the migration, when you get to the “What will be upgraded?” step in the migration wizard, the module will still show up in the list of “Modules that will not be upgraded”. This happens because core’s Migrate Drupal UI has no way of knowing whether you’ve written all the migrations that you intended to write!

If you look closely at the “What will be upgraded?” step, you’ll see there is a row for each module that has stored data on the D7 site — that is to say, D7 modules which do not store data are not listed; and D9 modules are only mentioned if they declare a migration for the data in one of those D7 modules.

Also, to date, this blog series has assumed that you are migrating to D9 from an older D7 version of the same module — but that doesn’t necessarily need to be the case: for example, the D9 Address module didn’t exist in D7: its predecessor module was named AddressField. Address module migrations would be written to migrate data from the AddressField module.

Recall that the main goal of this blog series is to improve the upgrade experience for Site Builders… as a Site Builder facing an upgrade, I want as many of my D7 modules to be (accurately) accounted for in the “What will be upgraded?” step of the migration wizard, so that I know how much manual migration that I need to do after running the migration wizard.

Proposed resolution

In Drupal 8.8, the migration team introduced a way for modules to declare their upgrade status. The status determines whether the “What will be upgraded?” report will list a D7 module in the list of “Module(s) that will be upgraded” or “Module(s) that will not be upgraded”.

A migration status looks like…

# In migrations/state/D9_DESTINATION_MODULE.migrate_drupal.yml
finished:
  6:
    d6_source_module_1: D9_DESTINATION_MODULE
  7:
    d7_source_module_2: D9_DESTINATION_MODULE
    d7_source_module_3:
      - D9_DESTINATION_MODULE
      - other_d9_destination_module

not_finished:
  7:
    d7_source_module_4: D9_DESTINATION_MODULE

You can see from this example that:

  1. You declare migrations as either finished or not_finished.

    In the “What will be upgraded?” report, a source module that does not have a migration declared for it — or whose migration is declared as not_finished — will appear in the “Module(s) that will not be upgraded” list.

    If a migration is declared as finished, then the module will appear in the “Module(s) that will be upgraded” list.

  2. You declare migration statuses for D6 and D7 modules separately.

    This allows you to tackle D6 and D7 migrations separately.

  3. You can declare migrations from one or more source modules to one or more destination modules.

    For example, core’s telephone module declares that it can migrate content from both the D7 Phone module and the the D7 Telephone module.

    Unfortunately, I’m not aware of an example where more than one D9 destination module is defined for a D7 source module.

  4. You declare migrations as finished or not_finished for the module as a whole.

    For example, this means that if a D7 module stores both content AND configuration, and you’ve only written a migration for configuration, then the module’s status is not_finished. Only once you’ve written the migration for the content, you can declare the status as finished.

Steps to complete

Let’s try to follow the principles of test driven development (TDD) by writing a test before we write the code to make that test pass. Put the following template at your module’s tests/src/Kernel/Migrate/d7/ValidateMigrationStateTest.php:

<?php

namespace Drupal\Tests\MODULE_NAME\Kernel\Migrate\d7;

use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
use Drupal\Tests\migrate_drupal\Traits\ValidateMigrationStateTestTrait;

/**
 * Tests that the MODULE_NAME test has a declared migration status.
 *
 * ValidateMigrationStateTestTrait::testMigrationState() will succeed if the
 * modules enabled in \Drupal\Tests\KernelTestBase::bootKernel() have a valid
 * migration status (i.e.: finished or not_finished); but will fail if they do
 * not have a declared migration status.
 *
 * @group MODULE_NAME
 */
class ValidateMigrationStateTest extends MigrateDrupal7TestBase {
  use ValidateMigrationStateTestTrait;

  /**
   * {@inheritdoc}
   */
  protected static $modules = ['MODULE_NAME'];

}

The test inherits from MigrateDrupal7TestBase, which automatically sets up a migration; and the test includes code fromValidateMigrationStateTestTrait — which has a public function testMigrationState() — so the migration state is automatically tested if you just fill in the MODULE_NAME.

Since we haven’t declared a state yet, if you run this test, it will fail.

Now, let’s write a migration state! At migrations/state/MODULE_NAME.migrate_drupal.yml

not_finished:
  7:
    D7_MODULE_NAME: D9_MODULE_NAME

Now, when you run the test, it will pass, because the module has declared a status (even though the status is not_finished).

Once you’re confident that you’ve written migrations for all the data that your D7 module can store, you can change that not_finished to finished.

Next steps

If you’ve already contributed some migrations, you can update those contributions to declare the migration status for that module. Remember, only declare the status as finished if you’ve written migrations for all the data stored by the D7 module that can be stored by the D9 module.


The article Easy commit credits with migrations, part 5: Declaring a module’s migration status first appeared on the Consensus Enterprises blog.

We've disabled blog comments to prevent spam, but if you have questions or comments about this post, get in touch!