From 349ae785257efd9bc701b17261174067bee124b0 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Mon, 4 May 2020 11:05:38 +0100
Subject: [PATCH] Issue #3126566 by greg.1.anderson, jungle, tedbow,
 hussainweb, Kristen Pol, alexpott: Allow Drupal to work with Composer 2

---
 composer.json                                 |  2 +-
 composer.lock                                 | 10 +++----
 .../Plugin/ProjectMessage/MessagePlugin.php   | 12 ++++++++
 composer/Plugin/ProjectMessage/composer.json  |  2 +-
 composer/Plugin/Scaffold/AllowedPackages.php  | 29 +++++++++++++++++--
 composer/Plugin/Scaffold/Plugin.php           | 12 ++++++++
 composer/Plugin/Scaffold/composer.json        |  2 +-
 .../VendorHardening/VendorHardeningPlugin.php | 12 ++++++++
 composer/Plugin/VendorHardening/composer.json |  2 +-
 composer/Template/LegacyProject/composer.json |  2 +-
 .../Template/RecommendedProject/composer.json |  2 +-
 core/drupalci.yml                             |  6 ++++
 .../Template/ComposerProjectTemplatesTest.php |  5 ++++
 .../Functional/ScaffoldUpgradeTest.php        |  4 +++
 14 files changed, 89 insertions(+), 13 deletions(-)

diff --git a/composer.json b/composer.json
index cc37fe26194b..338e28bc92b0 100644
--- a/composer.json
+++ b/composer.json
@@ -9,7 +9,7 @@
         "chat": "https://www.drupal.org/node/314178"
     },
     "require": {
-        "composer/installers": "^1.0.24",
+        "composer/installers": "^1.9",
         "drupal/core": "self.version",
         "drupal/core-project-message": "self.version",
         "drupal/core-vendor-hardening": "self.version"
diff --git a/composer.lock b/composer.lock
index 00e8e53d4dfd..953182d8c502 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "966c0ed90c2996cad45b441c58d01aa2",
+    "content-hash": "bf3f5b1c0d2f35255e03825589a1ee4f",
     "packages": [
         {
             "name": "asm89/stack-cors",
@@ -705,10 +705,10 @@
             "dist": {
                 "type": "path",
                 "url": "composer/Plugin/ProjectMessage",
-                "reference": "0691ca6beba657e6da57a893b1c6da757d16afc8"
+                "reference": "b4efdbe26634b41a1b89e4f3770a8074769088a6"
             },
             "require": {
-                "composer-plugin-api": "^1.1",
+                "composer-plugin-api": "^1.1 || ^2",
                 "php": ">=7.3.0"
             },
             "type": "composer-plugin",
@@ -735,10 +735,10 @@
             "dist": {
                 "type": "path",
                 "url": "composer/Plugin/VendorHardening",
-                "reference": "0b015340af38f90df46923a934d0b22026134f18"
+                "reference": "d54f0b3cc8b4237f3a41a0860a808db242f9da9e"
             },
             "require": {
-                "composer-plugin-api": "^1.1",
+                "composer-plugin-api": "^1.1 || ^2",
                 "php": ">=7.3.0"
             },
             "type": "composer-plugin",
diff --git a/composer/Plugin/ProjectMessage/MessagePlugin.php b/composer/Plugin/ProjectMessage/MessagePlugin.php
index 8a5333d8f1ca..9e57e6a363b4 100644
--- a/composer/Plugin/ProjectMessage/MessagePlugin.php
+++ b/composer/Plugin/ProjectMessage/MessagePlugin.php
@@ -45,6 +45,18 @@ public function activate(Composer $composer, IOInterface $io) {
     $this->io = $io;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function deactivate(Composer $composer, IOInterface $io) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstall(Composer $composer, IOInterface $io) {
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/composer/Plugin/ProjectMessage/composer.json b/composer/Plugin/ProjectMessage/composer.json
index 96ade5102c84..3741b3160010 100644
--- a/composer/Plugin/ProjectMessage/composer.json
+++ b/composer/Plugin/ProjectMessage/composer.json
@@ -15,6 +15,6 @@
   },
   "require": {
     "php": ">=7.3.0",
-    "composer-plugin-api": "^1.1"
+    "composer-plugin-api": "^1.1 || ^2"
   }
 }
diff --git a/composer/Plugin/Scaffold/AllowedPackages.php b/composer/Plugin/Scaffold/AllowedPackages.php
index 9b28368bbd45..481492f009ab 100644
--- a/composer/Plugin/Scaffold/AllowedPackages.php
+++ b/composer/Plugin/Scaffold/AllowedPackages.php
@@ -3,6 +3,7 @@
 namespace Drupal\Composer\Plugin\Scaffold;
 
 use Composer\Composer;
+use Composer\DependencyResolver\Operation\OperationInterface;
 use Composer\Installer\PackageEvent;
 use Composer\IO\IOInterface;
 use Composer\Package\PackageInterface;
@@ -96,8 +97,12 @@ public function getAllowedPackages() {
    */
   public function event(PackageEvent $event) {
     $operation = $event->getOperation();
-    // Determine the package.
-    $package = $operation->getJobType() == 'update' ? $operation->getTargetPackage() : $operation->getPackage();
+    // Determine the package. Later, in evaluateNewPackages(), we will report
+    // which of the newly-installed packages have scaffold operations, and
+    // whether or not they are allowed to scaffold by the allowed-packages
+    // option in the root-level composer.json file.
+    $operationType = $this->getOperationType($operation);
+    $package = $operationType === 'update' ? $operation->getTargetPackage() : $operation->getPackage();
     if (ScaffoldOptions::hasOptions($package->getExtra())) {
       $this->newPackages[$package->getName()] = $package;
     }
@@ -176,6 +181,26 @@ protected function evaluateNewPackages(array $allowed_packages) {
     return $allowed_packages;
   }
 
+  /**
+   * Determine the type of the provided operation.
+   *
+   * Adjusts API used for Composer 1 or Composer 2.
+   *
+   * @param \Composer\DependencyResolver\Operation\OperationInterface $operation
+   *   The operation object.
+   *
+   * @return string
+   *   The operation type.
+   */
+  protected function getOperationType(OperationInterface $operation) {
+    // Use Composer 2 method.
+    if (method_exists($operation, 'getOperationType')) {
+      return $operation->getOperationType();
+    }
+    // Fallback to Composer 1 method.
+    return $operation->getJobType();
+  }
+
   /**
    * Retrieves a package from the current composer process.
    *
diff --git a/composer/Plugin/Scaffold/Plugin.php b/composer/Plugin/Scaffold/Plugin.php
index a1252cfac140..9a694ec349b6 100644
--- a/composer/Plugin/Scaffold/Plugin.php
+++ b/composer/Plugin/Scaffold/Plugin.php
@@ -60,6 +60,18 @@ public function activate(Composer $composer, IOInterface $io) {
     $this->requireWasCalled = FALSE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function deactivate(Composer $composer, IOInterface $io) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstall(Composer $composer, IOInterface $io) {
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/composer/Plugin/Scaffold/composer.json b/composer/Plugin/Scaffold/composer.json
index 5cbb4ad79b99..ca9d6d7b48d2 100644
--- a/composer/Plugin/Scaffold/composer.json
+++ b/composer/Plugin/Scaffold/composer.json
@@ -6,7 +6,7 @@
   "homepage": "https://www.drupal.org/project/drupal",
   "license": "GPL-2.0-or-later",
   "require": {
-    "composer-plugin-api": "^1.0.0",
+    "composer-plugin-api": "^1 || ^2",
     "php": ">=7.3.0"
   },
   "conflict": {
diff --git a/composer/Plugin/VendorHardening/VendorHardeningPlugin.php b/composer/Plugin/VendorHardening/VendorHardeningPlugin.php
index c8e6182e113c..2cd7bdec52c9 100644
--- a/composer/Plugin/VendorHardening/VendorHardeningPlugin.php
+++ b/composer/Plugin/VendorHardening/VendorHardeningPlugin.php
@@ -65,6 +65,18 @@ public function activate(Composer $composer, IOInterface $io) {
     $this->config = new Config($this->composer->getPackage());
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function deactivate(Composer $composer, IOInterface $io) {
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstall(Composer $composer, IOInterface $io) {
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/composer/Plugin/VendorHardening/composer.json b/composer/Plugin/VendorHardening/composer.json
index 4ed1adedd0d6..5f78bc6abdaa 100644
--- a/composer/Plugin/VendorHardening/composer.json
+++ b/composer/Plugin/VendorHardening/composer.json
@@ -15,6 +15,6 @@
   },
   "require": {
     "php": ">=7.3.0",
-    "composer-plugin-api": "^1.1"
+    "composer-plugin-api": "^1.1 || ^2"
   }
 }
diff --git a/composer/Template/LegacyProject/composer.json b/composer/Template/LegacyProject/composer.json
index c7f532dfe61c..9162033006d7 100644
--- a/composer/Template/LegacyProject/composer.json
+++ b/composer/Template/LegacyProject/composer.json
@@ -15,7 +15,7 @@
         }
     ],
     "require": {
-        "composer/installers": "^1.2",
+        "composer/installers": "^1.9",
         "drupal/core-composer-scaffold": "^9",
         "drupal/core-project-message": "^9",
         "drupal/core-recommended": "^9",
diff --git a/composer/Template/RecommendedProject/composer.json b/composer/Template/RecommendedProject/composer.json
index 56aa5cdb2ce4..9de50df252f8 100644
--- a/composer/Template/RecommendedProject/composer.json
+++ b/composer/Template/RecommendedProject/composer.json
@@ -15,7 +15,7 @@
         }
     ],
     "require": {
-        "composer/installers": "^1.2",
+        "composer/installers": "^1.9",
         "drupal/core-composer-scaffold": "^9",
         "drupal/core-project-message": "^9",
         "drupal/core-recommended": "^9"
diff --git a/core/drupalci.yml b/core/drupalci.yml
index d6c5787ffc54..63df934307ed 100644
--- a/core/drupalci.yml
+++ b/core/drupalci.yml
@@ -50,3 +50,9 @@ build:
       # Run nightwatch testing.
       # @see https://www.drupal.org/project/drupal/issues/2869825
       nightwatchjs:
+      # Re-run Composer plugin tests after installing Composer 2
+      container_command.composer-upgrade:
+        commands:
+          - "sudo composer self-update --snapshot"
+          - "./vendor/bin/phpunit -c core --group VendorHardening,ProjectMessage,Scaffold"
+        halt-on-fail: true
diff --git a/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php b/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php
index e9bf83011683..641dba464b6c 100644
--- a/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php
+++ b/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php
@@ -105,6 +105,11 @@ public function testVerifyTemplateTestProviderIsAccurate() {
    * @dataProvider provideTemplateCreateProject
    */
   public function testTemplateCreateProject($project, $package_dir, $docroot_dir) {
+    $composerVersionLine = exec('composer --version');
+    if (strpos($composerVersionLine, 'Composer version 2') !== FALSE) {
+      $this->markTestSkipped('We cannot run the template create project test with Composer 2 until we have a stable version of composer/semver 2.x. The create project test installs drupal/core-recommended and the Drupal Composer plugins from Packagist, so these must also be compatible with Composer 2.x in order for this test to work.');
+    }
+
     $this->copyCodebase();
 
     // Get the Drupal core version branch. For instance, this should be
diff --git a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
index 3f6eeedd454d..99eb705b2856 100644
--- a/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
+++ b/core/tests/Drupal/Tests/Composer/Plugin/Scaffold/Functional/ScaffoldUpgradeTest.php
@@ -44,6 +44,10 @@ protected function setUp(): void {
    * Test upgrading the Composer Scaffold plugin.
    */
   public function testScaffoldUpgrade() {
+    $composerVersionLine = exec('composer --version');
+    if (strpos($composerVersionLine, 'Composer version 2') !== FALSE) {
+      $this->markTestSkipped('We cannot run the scaffold upgrade test with Composer 2 until we have a stable version of drupal/core-composer-scaffold to start from that we can install with Composer 2.x.');
+    }
     $this->fixturesDir = $this->fixtures->tmpDir($this->getName());
     $replacements = ['SYMLINK' => 'false', 'PROJECT_ROOT' => $this->fixtures->projectRoot()];
     $this->fixtures->cloneFixtureProjects($this->fixturesDir, $replacements);
-- 
GitLab