From 718283a109857839f916ddc196cf4fe5d5317022 Mon Sep 17 00:00:00 2001
From: phenaproxima <phenaproxima@205645.no-reply.drupal.org>
Date: Thu, 28 Oct 2021 14:03:12 +0000
Subject: [PATCH] Issue #3246283 by phenaproxima, tedbow: Make Updater extend
 Package Manager's stage

---
 automatic_updates.services.yml                |  8 +--
 package_manager/package_manager.services.yml  | 11 ----
 .../tests/src/Kernel/StageEventsTest.php      | 44 +++++++++++----
 src/Updater.php                               | 54 ++++---------------
 .../Functional/FileSystemOperationsTest.php   | 12 +----
 .../StagedProjectsValidatorTest.php           |  2 +-
 tests/src/Kernel/UpdaterTest.php              | 18 +++++--
 7 files changed, 65 insertions(+), 84 deletions(-)

diff --git a/automatic_updates.services.yml b/automatic_updates.services.yml
index ca0bd0dedb..e6d01a70d6 100644
--- a/automatic_updates.services.yml
+++ b/automatic_updates.services.yml
@@ -11,10 +11,12 @@ services:
     class: Drupal\automatic_updates\Updater
     arguments:
       - '@state'
-      - '@string_translation'
-      - '@event_dispatcher'
       - '@package_manager.path_locator'
-      - '@package_manager.stage'
+      - '@package_manager.beginner'
+      - '@package_manager.stager'
+      - '@package_manager.committer'
+      - '@package_manager.cleaner'
+      - '@event_dispatcher'
   automatic_updates.update_refresh_subscriber:
     class: Drupal\automatic_updates\Event\UpdateRefreshSubscriber
     arguments:
diff --git a/package_manager/package_manager.services.yml b/package_manager/package_manager.services.yml
index c083562388..da8091f9d9 100644
--- a/package_manager/package_manager.services.yml
+++ b/package_manager/package_manager.services.yml
@@ -84,14 +84,3 @@ services:
     arguments:
       - '@config.factory'
       - '%app.root%'
-
-  # Public API.
-  package_manager.stage:
-    class: Drupal\package_manager\Stage
-    arguments:
-      - '@package_manager.path_locator'
-      - '@package_manager.beginner'
-      - '@package_manager.stager'
-      - '@package_manager.committer'
-      - '@package_manager.cleaner'
-      - '@event_dispatcher'
diff --git a/package_manager/tests/src/Kernel/StageEventsTest.php b/package_manager/tests/src/Kernel/StageEventsTest.php
index 11cdf2071f..e313d19e24 100644
--- a/package_manager/tests/src/Kernel/StageEventsTest.php
+++ b/package_manager/tests/src/Kernel/StageEventsTest.php
@@ -12,6 +12,7 @@ use Drupal\package_manager\Event\PreCreateEvent;
 use Drupal\package_manager\Event\PreDestroyEvent;
 use Drupal\package_manager\Event\PreRequireEvent;
 use Drupal\package_manager\Event\StageEvent;
+use Drupal\package_manager\Stage;
 use Drupal\package_manager\StageException;
 use Drupal\package_manager\ValidationResult;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -40,6 +41,29 @@ class StageEventsTest extends KernelTestBase implements EventSubscriberInterface
    */
   private $events = [];
 
+  /**
+   * The stage under test.
+   *
+   * @var \Drupal\package_manager\Stage
+   */
+  private $stage;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->stage = new Stage(
+      $this->container->get('package_manager.path_locator'),
+      $this->container->get('package_manager.beginner'),
+      $this->container->get('package_manager.stager'),
+      $this->container->get('package_manager.committer'),
+      $this->container->get('package_manager.cleaner'),
+      $this->container->get('event_dispatcher')
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -66,7 +90,7 @@ class StageEventsTest extends KernelTestBase implements EventSubscriberInterface
     array_push($this->events, get_class($event));
 
     // The event should have a reference to the stage which fired it.
-    $this->assertSame($event->getStage(), $this->container->get('package_manager.stage'));
+    $this->assertSame($event->getStage(), $this->stage);
 
     // Adding a warning to the event, should not trigger an exception.
     $result = ValidationResult::createWarning([
@@ -81,11 +105,10 @@ class StageEventsTest extends KernelTestBase implements EventSubscriberInterface
   public function testEvents(): void {
     $this->container->get('event_dispatcher')->addSubscriber($this);
 
-    $stage = $this->container->get('package_manager.stage');
-    $stage->create();
-    $stage->require(['ext-json:*']);
-    $stage->apply();
-    $stage->destroy();
+    $this->stage->create();
+    $this->stage->require(['ext-json:*']);
+    $this->stage->apply();
+    $this->stage->destroy();
 
     $this->assertSame($this->events, [
       PreCreateEvent::class,
@@ -139,11 +162,10 @@ class StageEventsTest extends KernelTestBase implements EventSubscriberInterface
       ->addListener($event_class, $handler);
 
     try {
-      $stage = $this->container->get('package_manager.stage');
-      $stage->create();
-      $stage->require(['ext-json:*']);
-      $stage->apply();
-      $stage->destroy();
+      $this->stage->create();
+      $this->stage->require(['ext-json:*']);
+      $this->stage->apply();
+      $this->stage->destroy();
 
       $this->fail('Expected \Drupal\package_manager\StageException to be thrown.');
     }
diff --git a/src/Updater.php b/src/Updater.php
index b5d01335a3..3a18139534 100644
--- a/src/Updater.php
+++ b/src/Updater.php
@@ -6,20 +6,14 @@ use Drupal\automatic_updates\Event\PreStartEvent;
 use Drupal\automatic_updates\Event\UpdateEvent;
 use Drupal\automatic_updates\Exception\UpdateException;
 use Drupal\Core\State\StateInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\package_manager\ComposerUtility;
-use Drupal\package_manager\PathLocator as PackageManagerPathLocator;
 use Drupal\package_manager\Stage;
 use Drupal\system\SystemManager;
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
 /**
  * Defines a service to perform updates.
  */
-class Updater {
-
-  use StringTranslationTrait;
+class Updater extends Stage {
 
   /**
    * The state key in which to store the status of the update.
@@ -35,47 +29,17 @@ class Updater {
    */
   protected $state;
 
-  /**
-   * The event dispatcher service.
-   *
-   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
-   */
-  protected $eventDispatcher;
-
-  /**
-   * The path locator service.
-   *
-   * @var \Drupal\package_manager\PathLocator
-   */
-  protected $pathLocator;
-
-  /**
-   * The stage service.
-   *
-   * @var \Drupal\package_manager\Stage
-   */
-  protected $stage;
-
   /**
    * Constructs an Updater object.
    *
    * @param \Drupal\Core\State\StateInterface $state
    *   The state service.
-   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
-   *   The string translation service.
-   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
-   *   The event dispatcher service.
-   * @param \Drupal\package_manager\PathLocator $path_locator
-   *   The path locator service.
-   * @param \Drupal\package_manager\Stage $stage
-   *   The stage service.
+   * @param mixed ...$arguments
+   *   Additional arguments to pass to the parent constructor.
    */
-  public function __construct(StateInterface $state, TranslationInterface $translation, EventDispatcherInterface $event_dispatcher, PackageManagerPathLocator $path_locator, Stage $stage) {
+  public function __construct(StateInterface $state, ...$arguments) {
     $this->state = $state;
-    $this->setStringTranslation($translation);
-    $this->eventDispatcher = $event_dispatcher;
-    $this->pathLocator = $path_locator;
-    $this->stage = $stage;
+    parent::__construct(...$arguments);
   }
 
   /**
@@ -116,7 +80,7 @@ class Updater {
     }
     $stage_key = $this->createActiveStage($packages);
     $this->dispatchUpdateEvent(new PreStartEvent($composer, $packages));
-    $this->stage->create();
+    $this->create();
     return $stage_key;
   }
 
@@ -125,21 +89,21 @@ class Updater {
    */
   public function stage(): void {
     $current = $this->state->get(static::STATE_KEY);
-    $this->stage->require($current['package_versions']);
+    $this->require($current['package_versions']);
   }
 
   /**
    * Commits the current update.
    */
   public function commit(): void {
-    $this->stage->apply();
+    $this->apply();
   }
 
   /**
    * Cleans the current update.
    */
   public function clean(): void {
-    $this->stage->destroy();
+    $this->destroy();
     $this->state->delete(static::STATE_KEY);
   }
 
diff --git a/tests/src/Functional/FileSystemOperationsTest.php b/tests/src/Functional/FileSystemOperationsTest.php
index 78a481fb0d..4d325efd3a 100644
--- a/tests/src/Functional/FileSystemOperationsTest.php
+++ b/tests/src/Functional/FileSystemOperationsTest.php
@@ -6,7 +6,6 @@ use Drupal\package_manager\Cleaner;
 use Drupal\automatic_updates\Updater;
 use Drupal\Core\Site\Settings;
 use Drupal\package_manager\PathLocator;
-use Drupal\package_manager\Stage;
 
 /**
  * Tests handling of files and directories during an update.
@@ -70,7 +69,8 @@ class FileSystemOperationsTest extends AutomaticUpdatesFunctionalTestBase {
       $locator->reveal()
     );
 
-    $stage = new Stage(
+    $this->updater = new Updater(
+      $this->container->get('state'),
       $locator->reveal(),
       $this->container->get('package_manager.beginner'),
       $this->container->get('package_manager.stager'),
@@ -79,14 +79,6 @@ class FileSystemOperationsTest extends AutomaticUpdatesFunctionalTestBase {
       $this->container->get('event_dispatcher')
     );
 
-    $this->updater = new Updater(
-      $this->container->get('state'),
-      $this->container->get('string_translation'),
-      $this->container->get('event_dispatcher'),
-      $locator->reveal(),
-      $stage
-    );
-
     // Use the public and private files directories in the fake site fixture.
     $settings = Settings::getAll();
     $settings['file_public_path'] = 'files/public';
diff --git a/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php b/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php
index b552398246..3bb3721f94 100644
--- a/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php
+++ b/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php
@@ -39,7 +39,7 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase {
     $this->container->set('package_manager.path_locator', $locator->reveal());
 
     $event = new PreApplyEvent(
-      $this->container->get('package_manager.stage')
+      $this->container->get('automatic_updates.updater')
     );
 
     $this->container->get('event_dispatcher')->dispatch($event);
diff --git a/tests/src/Kernel/UpdaterTest.php b/tests/src/Kernel/UpdaterTest.php
index 6b3f47497d..5428964341 100644
--- a/tests/src/Kernel/UpdaterTest.php
+++ b/tests/src/Kernel/UpdaterTest.php
@@ -3,6 +3,8 @@
 namespace Drupal\Tests\automatic_updates\Kernel;
 
 use Drupal\package_manager\PathLocator;
+use PhpTuf\ComposerStager\Domain\StagerInterface;
+use Prophecy\Argument;
 
 /**
  * @coversDefaultClass \Drupal\automatic_updates\Updater
@@ -43,9 +45,19 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase {
     $kernel = $this->container->get('kernel');
     $kernel->rebuildContainer();
     $this->container = $kernel->getContainer();
-    $stage = $this->prophesize('\Drupal\package_manager\Stage');
-    $stage->require(['drupal/core-recommended:9.8.1'])->shouldBeCalled();
-    $this->container->set('package_manager.stage', $stage->reveal());
+    // When we call Updater::stage(), the stored project versions should be
+    // read from state and passed to Composer Stager's Stager service, in the
+    // form of a Composer command. We set up a mock here to ensure that those
+    // calls are made as expected.
+    $stager = $this->prophesize(StagerInterface::class);
+    $command = [
+      'require',
+      'drupal/core-recommended:9.8.1',
+      '--update-with-all-dependencies',
+    ];
+    $stager->stage($command, Argument::cetera())->shouldBeCalled();
+    $this->container->set('package_manager.stager', $stager->reveal());
+
     $this->container->get('automatic_updates.updater')->stage();
   }
 
-- 
GitLab