From 06e82f14d230c71ca4790d5ff5322db157a6669a Mon Sep 17 00:00:00 2001
From: Adam G-H <32250-phenaproxima@users.noreply.drupalcode.org>
Date: Wed, 6 Sep 2023 17:39:06 +0000
Subject: [PATCH] Issue #3384637 by phenaproxima: FailureMarker should be
 responsible for excluding the marker file from stage operations

---
 package_manager/package_manager.services.yml  |  4 ++-
 package_manager/src/FailureMarker.php         | 25 ++++++++++++++++++-
 package_manager/src/StageBase.php             |  7 +-----
 .../tests/src/Kernel/FailureMarkerTest.php    | 17 +++++++++++++
 4 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/package_manager/package_manager.services.yml b/package_manager/package_manager.services.yml
index ee4ed39b97..e60c2df9e8 100644
--- a/package_manager/package_manager.services.yml
+++ b/package_manager/package_manager.services.yml
@@ -40,7 +40,9 @@ services:
   Drupal\package_manager\PathLocator:
     arguments:
       $appRoot: '%app.root%'
-  Drupal\package_manager\FailureMarker: ~
+  Drupal\package_manager\FailureMarker:
+    tags:
+      - { name: event_subscriber }
   Drupal\package_manager\EventSubscriber\UpdateDataSubscriber:
     # @todo Autowire this service when https://drupal.org/i/3325557 lands.
     arguments:
diff --git a/package_manager/src/FailureMarker.php b/package_manager/src/FailureMarker.php
index 04cf6c51a5..6f2a60b90f 100644
--- a/package_manager/src/FailureMarker.php
+++ b/package_manager/src/FailureMarker.php
@@ -4,6 +4,8 @@ declare(strict_types = 1);
 
 namespace Drupal\package_manager;
 
+use Drupal\package_manager\Event\CollectPathsToExcludeEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\Yaml\Exception\ParseException;
 use Symfony\Component\Yaml\Yaml;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
@@ -23,7 +25,7 @@ use Drupal\package_manager\Exception\StageFailureMarkerException;
  *   at any time without warning. External code should not interact with this
  *   class.
  */
-final class FailureMarker {
+final class FailureMarker implements EventSubscriberInterface {
 
   /**
    * Constructs a FailureMarker object.
@@ -142,4 +144,25 @@ final class FailureMarker {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents(): array {
+    return [
+      CollectPathsToExcludeEvent::class => 'excludeMarkerFile',
+    ];
+  }
+
+  /**
+   * Excludes the failure marker file from stage operations.
+   *
+   * @param \Drupal\package_manager\Event\CollectPathsToExcludeEvent $event
+   *   The event being handled.
+   */
+  public function excludeMarkerFile(CollectPathsToExcludeEvent $event): void {
+    $event->addPathsRelativeToProjectRoot([
+      $this->getPath(),
+    ]);
+  }
+
 }
diff --git a/package_manager/src/StageBase.php b/package_manager/src/StageBase.php
index c49c1a7beb..6b55b1ff3e 100644
--- a/package_manager/src/StageBase.php
+++ b/package_manager/src/StageBase.php
@@ -443,15 +443,10 @@ abstract class StageBase implements LoggerAwareInterface {
     $stage_dir = $this->pathFactory->create($this->getStageDirectory());
 
     $excluded_paths = $this->getPathsToExclude();
-    // Exclude the failure file from the commit operation.
-    $excluded_paths->add(
-      str_replace($active_dir->absolute() . DIRECTORY_SEPARATOR, '', $this->failureMarker->getPath()),
-    );
-
+    $event = new PreApplyEvent($this, $excluded_paths);
     // If an error occurs while dispatching the events, ensure that ::destroy()
     // doesn't think we're in the middle of applying the staged changes to the
     // active directory.
-    $event = new PreApplyEvent($this, $excluded_paths);
     $this->tempStore->set(self::TEMPSTORE_APPLY_TIME_KEY, $this->time->getRequestTime());
     $this->dispatch($event, $this->setNotApplying(...));
 
diff --git a/package_manager/tests/src/Kernel/FailureMarkerTest.php b/package_manager/tests/src/Kernel/FailureMarkerTest.php
index a56ef95759..f8235bdde3 100644
--- a/package_manager/tests/src/Kernel/FailureMarkerTest.php
+++ b/package_manager/tests/src/Kernel/FailureMarkerTest.php
@@ -4,8 +4,11 @@ declare(strict_types = 1);
 
 namespace Drupal\Tests\package_manager\Kernel;
 
+use Drupal\package_manager\Event\CollectPathsToExcludeEvent;
 use Drupal\package_manager\Exception\StageFailureMarkerException;
 use Drupal\package_manager\FailureMarker;
+use Drupal\package_manager\PathLocator;
+use PhpTuf\ComposerStager\API\Path\Factory\PathFactoryInterface;
 
 /**
  * @coversDefaultClass \Drupal\package_manager\FailureMarker
@@ -80,4 +83,18 @@ REGEXP
     $failure_marker->assertNotExists();
   }
 
+  /**
+   * @covers ::getSubscribedEvents
+   * @covers ::excludeMarkerFile
+   */
+  public function testMarkerFileIsExcluded(): void {
+    $event = new CollectPathsToExcludeEvent(
+      $this->createStage(),
+      $this->container->get(PathLocator::class),
+      $this->container->get(PathFactoryInterface::class),
+    );
+    $this->container->get('event_dispatcher')->dispatch($event);
+    $this->assertContains('PACKAGE_MANAGER_FAILURE.yml', $event->getAll());
+  }
+
 }
-- 
GitLab