From 68c1000f77094b6b20d5f693f11ad1e0313538e9 Mon Sep 17 00:00:00 2001
From: Dave Long <dave@longwaveconsulting.com>
Date: Thu, 15 Jun 2023 17:06:38 +0100
Subject: [PATCH] Issue #3052115 by huzooka, HitchShock, floydm,
 ranjith_kumar_k_u, Sam152, edysmp, codebymikey, herved, Wim Leers, quietone,
 hchonov, Berdir, DamienMcKenna, rclemings, donquixote, benjifisher, fengtan,
 jwilson3: Mark an entity as 'syncing' during a migration update

---
 .../src/Plugin/migrate/destination/Entity.php |  4 +
 .../migrate/destination/EntityContentBase.php |  2 +
 .../migrate/destination/EntityRevision.php    |  1 +
 .../destination/EntityContentBaseTest.php     |  4 +
 .../Unit/destination/EntityRevisionTest.php   |  4 +
 .../MigrateUpgradeExecuteTestBase.php         | 33 +++++++++
 .../tests/src/Functional/d6/Upgrade6Test.php  |  2 +-
 .../d6/Upgrade6TestWithContentModeration.php  | 73 +++++++++++++++++++
 .../tests/src/Functional/d7/Upgrade7Test.php  |  2 +-
 .../d7/Upgrade7TestWithContentModeration.php  | 65 +++++++++++++++++
 10 files changed, 188 insertions(+), 2 deletions(-)
 create mode 100644 core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6TestWithContentModeration.php
 create mode 100644 core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7TestWithContentModeration.php

diff --git a/core/modules/migrate/src/Plugin/migrate/destination/Entity.php b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php
index 3a2f93be4daa..b7faaae49101 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/Entity.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Entity.php
@@ -3,6 +3,7 @@
 namespace Drupal\migrate\Plugin\migrate\destination;
 
 use Drupal\Component\Plugin\DependentPluginInterface;
+use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Entity\DependencyTrait;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
@@ -215,6 +216,9 @@ public function rollback(array $destination_identifier) {
     // Delete the specified entity from Drupal if it exists.
     $entity = $this->storage->load(reset($destination_identifier));
     if ($entity) {
+      if ($entity instanceof ContentEntityInterface) {
+        $entity->setSyncing(TRUE);
+      }
       $entity->delete();
     }
   }
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
index 2b439cd2cb31..cd1c24c2916e 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityContentBase.php
@@ -233,6 +233,7 @@ public function validateEntity(FieldableEntityInterface $entity) {
    *   An array containing the entity ID.
    */
   protected function save(ContentEntityInterface $entity, array $old_destination_id_values = []) {
+    $entity->setSyncing(TRUE);
     $entity->save();
     return [$entity->id()];
   }
@@ -380,6 +381,7 @@ public function rollback(array $destination_identifier) {
               $translation = $entity->getTranslation($langcode);
               if (!$translation->isDefaultTranslation()) {
                 $entity->removeTranslation($langcode);
+                $entity->setSyncing(TRUE);
                 $entity->save();
               }
             }
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/EntityRevision.php b/core/modules/migrate/src/Plugin/migrate/destination/EntityRevision.php
index b387815724b3..16d986999ced 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/EntityRevision.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/EntityRevision.php
@@ -164,6 +164,7 @@ protected function getEntity(Row $row, array $old_destination_id_values) {
    * {@inheritdoc}
    */
   protected function save(ContentEntityInterface $entity, array $old_destination_id_values = []) {
+    $entity->setSyncing(TRUE);
     $entity->save();
     return [$entity->getRevisionId()];
   }
diff --git a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
index 3319b71a19d2..0f1f38f1019d 100644
--- a/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
+++ b/core/modules/migrate/tests/src/Unit/Plugin/migrate/destination/EntityContentBaseTest.php
@@ -14,6 +14,7 @@
 use Drupal\migrate\Plugin\migrate\destination\EntityContentBase;
 use Drupal\migrate\Plugin\MigrateIdMapInterface;
 use Drupal\migrate\Row;
+use Prophecy\Argument;
 
 /**
  * Tests base entity migration destination functionality.
@@ -44,6 +45,9 @@ public function testImport() {
     // Assert that save is called.
     $entity->save()
       ->shouldBeCalledTimes(1);
+    // Syncing should be set once.
+    $entity->setSyncing(Argument::exact(TRUE))
+      ->shouldBeCalledTimes(1);
     // Set an id for the entity
     $entity->id()
       ->willReturn(5);
diff --git a/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php b/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php
index 374db8a94613..096f9a231ae4 100644
--- a/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php
+++ b/core/modules/migrate/tests/src/Unit/destination/EntityRevisionTest.php
@@ -15,6 +15,7 @@
 use Drupal\migrate\Plugin\migrate\destination\EntityRevision as RealEntityRevision;
 use Drupal\migrate\Row;
 use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
 
 /**
  * Tests entity revision destination.
@@ -178,6 +179,9 @@ public function testSave() {
     $entity = $this->prophesize('\Drupal\Core\Entity\ContentEntityInterface');
     $entity->save()
       ->shouldBeCalled();
+    // Syncing should be set once.
+    $entity->setSyncing(Argument::exact(TRUE))
+      ->shouldBeCalledTimes(1);
     $entity->getRevisionId()
       ->shouldBeCalled()
       ->willReturn(1234);
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
index f28f6b4dc4a2..10288106c3ff 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\migrate_drupal_ui\Functional;
 
+use Drupal\Core\Entity\ContentEntityStorageInterface;
 use Drupal\Tests\migrate_drupal\Traits\CreateTestContentEntitiesTrait;
 
 /**
@@ -69,4 +70,36 @@ public function useTestMailCollector() {
     $this->writeSettings($settings);
   }
 
+  /**
+   * Checks the number of the specified entity's revisions.
+   *
+   * Revision translations are excluded.
+   *
+   * @param string $content_entity_type_id
+   *   The entity type ID of the content entity, e.g. 'node', 'media',
+   *   'block_content'.
+   * @param int $expected_revision_count
+   *   The expected number of the revisions.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   */
+  protected function assertEntityRevisionsCount(string $content_entity_type_id, int $expected_revision_count) {
+    $entity_storage = \Drupal::entityTypeManager()->getStorage($content_entity_type_id);
+    assert($entity_storage instanceof ContentEntityStorageInterface);
+    $revision_ids = $entity_storage
+      ->getQuery()
+      ->allRevisions()
+      ->accessCheck(FALSE)
+      ->execute();
+    $this->assertCount(
+      $expected_revision_count,
+      $revision_ids,
+      sprintf(
+        "The number of %s revisions is different than expected",
+        $content_entity_type_id
+      )
+    );
+  }
+
 }
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6Test.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6Test.php
index 1e6249c2e27f..c7eed2b2d901 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6Test.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6Test.php
@@ -200,7 +200,7 @@ public function testUpgradeAndIncremental() {
     $this->assertUserLogIn(2, 'john.doe_pass');
 
     $this->assertFollowUpMigrationResults();
-
+    $this->assertEntityRevisionsCount('node', 26);
     $this->assertEmailsSent();
   }
 
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6TestWithContentModeration.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6TestWithContentModeration.php
new file mode 100644
index 000000000000..4a46e7f36319
--- /dev/null
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/Upgrade6TestWithContentModeration.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Drupal\Tests\migrate_drupal_ui\Functional\d6;
+
+use Drupal\workflows\Entity\Workflow;
+use Drupal\workflows\WorkflowInterface;
+
+/**
+ * Tests Drupal 6 upgrade using the migrate UI with Content Moderation.
+ *
+ * @group migrate_drupal_ui
+ */
+class Upgrade6TestWithContentModeration extends Upgrade6Test {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'content_moderation',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    // Set up a moderation flow.
+    $types = [
+      'story',
+      'test_planet',
+      'company',
+      'employee',
+    ];
+    foreach ($types as $type) {
+      $this->drupalCreateContentType(['type' => $type]);
+    }
+    $editorial = Workflow::load('editorial');
+    assert($editorial instanceof WorkflowInterface);
+    $type_settings = $editorial->getTypePlugin()->getConfiguration();
+    $type_settings['default_moderation_state'] = 'published';
+    $type_settings['entity_types']['node'] = array_merge(
+      ['page', 'forum'],
+      $types
+    );
+    $type_plugin = $editorial->getTypePlugin();
+    $type_plugin->setConfiguration($type_settings);
+    $editorial->trustData()->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCounts() {
+    $entity_counts = parent::getEntityCounts() + [
+      'content_moderation_state' => 18,
+      'workflow' => 1,
+    ];
+    $entity_counts['field_config'] = $entity_counts['field_config'] + 1;
+    $entity_counts['view'] = $entity_counts['view'] + 1;
+    return $entity_counts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCountsIncremental() {
+    $entity_counts_incremental = parent::getEntityCountsIncremental();
+    $entity_counts_incremental['content_moderation_state'] = $entity_counts_incremental['content_moderation_state'] + 1;
+    return $entity_counts_incremental;
+  }
+
+}
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
index 05baccd79858..960fffae0a49 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
@@ -227,7 +227,7 @@ public function testUpgradeAndIncremental() {
     $this->assertUserLogIn(2, 'a password');
 
     $this->assertFollowUpMigrationResults();
-
+    $this->assertEntityRevisionsCount('node', 19);
     $this->assertEmailsSent();
   }
 
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7TestWithContentModeration.php b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7TestWithContentModeration.php
new file mode 100644
index 000000000000..5d4ec2dc6d9e
--- /dev/null
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7TestWithContentModeration.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\Tests\migrate_drupal_ui\Functional\d7;
+
+use Drupal\workflows\Entity\Workflow;
+use Drupal\workflows\WorkflowInterface;
+
+/**
+ * Tests Drupal 7 upgrade using the migrate UI with Content Moderation.
+ *
+ * @group migrate_drupal_ui
+ */
+class Upgrade7TestWithContentModeration extends Upgrade7Test {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'content_moderation',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    // Set up a moderation flow.
+    $types = [
+      'blog',
+      'et',
+      'test_content_type',
+    ];
+    foreach ($types as $type) {
+      $this->drupalCreateContentType(['type' => $type]);
+    }
+
+    $editorial = Workflow::load('editorial');
+    assert($editorial instanceof WorkflowInterface);
+    $type_settings = $editorial->getTypePlugin()->getConfiguration();
+    $type_settings['default_moderation_state'] = 'published';
+    $type_settings['entity_types']['node'] = array_merge(
+      ['article', 'forum'],
+      $types
+    );
+    $type_plugin = $editorial->getTypePlugin();
+    $type_plugin->setConfiguration($type_settings);
+    $editorial->trustData()->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEntityCounts() {
+    $entity_counts = parent::getEntityCounts() + [
+      'content_moderation_state' => 7,
+      'workflow' => 1,
+    ];
+    $entity_counts['entity_view_display'] = $entity_counts['entity_view_display'] + 1;
+    $entity_counts['field_config'] = $entity_counts['field_config'] + 2;
+    $entity_counts['view'] = $entity_counts['view'] + 1;
+    return $entity_counts;
+  }
+
+}
-- 
GitLab