#8 Support Drupal 11 / 10.3 on composer 2.x

Open
fgm wants to merge 1 commits from fgm/7-drupal11 into fgm/composer2

+ 1 - 0
.gitignore

@@ -1,4 +1,5 @@
 /.idea/
 /.idea/
+/.phpunit.result.cache
 /.phpunit.cache
 /.phpunit.cache
 /composer.lock
 /composer.lock
 /coverage/*
 /coverage/*

+ 14 - 10
composer.json

@@ -11,6 +11,10 @@
     }
     }
   },
   },
   "config": {
   "config": {
+    "allow-plugins": {
+      "composer/installers": true,
+      "dealerdirect/phpcodesniffer-composer-installer": true
+    },
     "bin-dir": "vendor/bin",
     "bin-dir": "vendor/bin",
     "discard-changes": true,
     "discard-changes": true,
     "optimize-autoloader": true,
     "optimize-autoloader": true,
@@ -25,18 +29,18 @@
   "name": "fgm/drupal_composer_builder",
   "name": "fgm/drupal_composer_builder",
   "prefer-stable": true,
   "prefer-stable": true,
   "require": {
   "require": {
-    "php": "^7.4 || ^8",
-    "composer-plugin-api": "^1.1 || ^2.0.0",
-    "composer/installers": "^1.12"
+    "php": "^8.2",
+    "composer-plugin-api": "^2.3.0",
+    "composer/installers": "^v2.3.0"
   },
   },
   "require-dev": {
   "require-dev": {
     "composer/composer": "^2.1",
     "composer/composer": "^2.1",
-    "dealerdirect/phpcodesniffer-composer-installer": "dev-master",
-    "drupal/coder": "^8.3.13",
-    "phpstan/phpstan": "^0.12.99",
-    "phpunit/phpunit": "^9.5",
+    "dealerdirect/phpcodesniffer-composer-installer": "^1",
+    "drupal/coder": "^8.3.24",
+    "phpstan/phpstan": "^1",
+    "phpunit/phpunit": "^11",
     "squizlabs/php_codesniffer": "^3.6",
     "squizlabs/php_codesniffer": "^3.6",
-    "twig/twig": "^1"
+    "twig/twig": "^v2"
   },
   },
   "scripts": {
   "scripts": {
     "check": [
     "check": [
@@ -45,9 +49,9 @@
       "@test",
       "@test",
       "@cover"
       "@cover"
     ],
     ],
-    "cover": "phpunit --coverage-filter=src --coverage-html=coverage --coverage-text",
+    "cover": "phpunit --coverage-filter=src --coverage-html=coverage tests",
     "cs": "phpcs --standard=PSR1,Drupal -v src",
     "cs": "phpcs --standard=PSR1,Drupal -v src",
-    "stan": "phpstan analyse --level 5 src tests",
+    "stan": "phpstan analyze --level 6 src tests",
     "test": "phpunit tests"
     "test": "phpunit tests"
   },
   },
   "type": "composer-plugin"
   "type": "composer-plugin"

+ 13 - 10
phpunit.xml

@@ -1,28 +1,31 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.2/phpunit.xsd"
          colors="true"
          colors="true"
-         verbose="true"
-         cacheResultFile=".phpunit.cache/test-results"
+         beStrictAboutTestsThatDoNotTestAnything="true"
+         beStrictAboutOutputDuringTests="true"
+         beStrictAboutChangesToGlobalState="true"
          failOnRisky="true"
          failOnRisky="true"
-         failOnWarning="true">
+         failOnWarning="true"
+>
   <testsuites>
   <testsuites>
     <testsuite name="unit">
     <testsuite name="unit">
       <directory>tests</directory>
       <directory>tests</directory>
     </testsuite>
     </testsuite>
   </testsuites>
   </testsuites>
-
-  <coverage cacheDirectory=".phpunit.cache/code-coverage"
-            processUncoveredFiles="true"
-            ignoreDeprecatedCodeUnits="true">
+  <!-- Filter for coverage reports. -->
+  <coverage
+    includeUncoveredFiles="true"
+    ignoreDeprecatedCodeUnits="true">
+  </coverage>
+  <source ignoreIndirectDeprecations="true">
     <include>
     <include>
       <directory suffix=".php">src</directory>
       <directory suffix=".php">src</directory>
     </include>
     </include>
-
     <exclude>
     <exclude>
       <directory>vendor</directory>
       <directory>vendor</directory>
     </exclude>
     </exclude>
-  </coverage>
+  </source>
 
 
   <php>
   <php>
     <ini name="precision" value="14"/>
     <ini name="precision" value="14"/>

+ 9 - 11
src/BaseBuilderCommand.php

@@ -4,8 +4,6 @@ declare(strict_types=1);
 
 
 namespace Fgm\Drupal\Composer;
 namespace Fgm\Drupal\Composer;
 
 
-require_once __DIR__ . '/../../../../vendor/autoload.php';
-
 use Composer\Command\BaseCommand;
 use Composer\Command\BaseCommand;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
@@ -49,14 +47,14 @@ abstract class BaseBuilderCommand extends BaseCommand {
    * @param string $buildName
    * @param string $buildName
    *   The template name as a composer.json extra section.
    *   The template name as a composer.json extra section.
    *
    *
-   * @return array
+   * @return array{string,int}
    *   - string Template name
    *   - string Template name
    *   - int Error
    *   - int Error
    */
    */
   public function validateTemplateName(
   public function validateTemplateName(
     InputInterface $input,
     InputInterface $input,
     OutputInterface $output,
     OutputInterface $output,
-    string $buildName
+    string $buildName,
   ): array {
   ): array {
     $conf = $this->getComposer()->getPackage()->getExtra()[Builder::NAME] ?? [];
     $conf = $this->getComposer()->getPackage()->getExtra()[Builder::NAME] ?? [];
     $templateName = $conf['templates'][$buildName] ?? '';
     $templateName = $conf['templates'][$buildName] ?? '';
@@ -77,19 +75,19 @@ abstract class BaseBuilderCommand extends BaseCommand {
    *
    *
    * @param \Twig\TemplateWrapper $wrapper
    * @param \Twig\TemplateWrapper $wrapper
    *   A Twig user-space template wrapper.
    *   A Twig user-space template wrapper.
-   * @param array $context
+   * @param mixed[] $context
    *   The data context with which to perform the rendering.
    *   The data context with which to perform the rendering.
    * @param string $destination
    * @param string $destination
    *   The path where to write the rendering result.
    *   The path where to write the rendering result.
    *
    *
-   * @return array
+   * @return array{string,int}
    *   - string message
    *   - string message
    *   - int status: 0 on success, other values on errors.
    *   - int status: 0 on success, other values on errors.
    */
    */
   protected function render(
   protected function render(
     TemplateWrapper $wrapper,
     TemplateWrapper $wrapper,
     array $context,
     array $context,
-    string $destination
+    string $destination,
   ): array {
   ): array {
     if (file_exists($destination)) {
     if (file_exists($destination)) {
       $ok = unlink($destination);
       $ok = unlink($destination);
@@ -117,7 +115,7 @@ abstract class BaseBuilderCommand extends BaseCommand {
    * @param string $buildName
    * @param string $buildName
    *   Machine name of build process.
    *   Machine name of build process.
    *
    *
-   * @return array
+   * @return array{?\Twig\TemplateWrapper,array<string,mixed>,string,int}
    *   - TemplateWrapper|NULL: Twig template wrapper
    *   - TemplateWrapper|NULL: Twig template wrapper
    *   - array: template parameters
    *   - array: template parameters
    *   - string: error message
    *   - string: error message
@@ -130,7 +128,7 @@ abstract class BaseBuilderCommand extends BaseCommand {
   protected function prepare(
   protected function prepare(
     InputInterface $input,
     InputInterface $input,
     OutputInterface $output,
     OutputInterface $output,
-    string $buildName
+    string $buildName,
   ): array {
   ): array {
     [
     [
       $templateName,
       $templateName,
@@ -141,7 +139,7 @@ abstract class BaseBuilderCommand extends BaseCommand {
     };
     };
 
 
     $settingsPath = $this->getSettingsPath();
     $settingsPath = $this->getSettingsPath();
-    $templatePath = "${settingsPath}/${templateName}";
+    $templatePath = "{$settingsPath}/{$templateName}";
     $realTemplatePath = realpath($templatePath);
     $realTemplatePath = realpath($templatePath);
     if (empty($realTemplatePath)) {
     if (empty($realTemplatePath)) {
       return [
       return [
@@ -172,7 +170,7 @@ abstract class BaseBuilderCommand extends BaseCommand {
   /**
   /**
    * Get parameters as obtained from configuration.
    * Get parameters as obtained from configuration.
    *
    *
-   * @return array
+   * @return array{array<string,mixed>,string,int}
    *   - array: parameters
    *   - array: parameters
    *   - string: error message
    *   - string: error message
    *   - int: error, 0 if OK. If non-zero, only the error message is reliable.
    *   - int: error, 0 if OK. If non-zero, only the error message is reliable.

+ 1 - 1
src/BuildSettingsCommand.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-declare(strict_types = 1);
+declare(strict_types=1);
 
 
 namespace Fgm\Drupal\Composer;
 namespace Fgm\Drupal\Composer;
 
 

+ 32 - 35
src/Builder.php

@@ -37,27 +37,6 @@ class Builder implements Capable, Capability, EventSubscriberInterface, PluginIn
    */
    */
   protected $io;
   protected $io;
 
 
-  /**
-   * {@inheritdoc}
-   *
-   * Available events:
-   *
-   * - Composer\Installer\InstallerEvents::*
-   *    -> Composer\Installer\InstallerEvent
-   * - Composer\Installer\PackageEvents::* -> Composer\Installer\PackageEvent
-   * - Composer\Installer\PluginEvents::INIT -> Composer\EventDispatcher\Event
-   * - Composer\Installer\PluginEvents::COMMAND -> Composer\Plugin\CommandEvent
-   * - Composer\Installer\PluginEvents::PRE_FILE_DOWNLOAD
-   *     -> Composer\Plugin\PreFileDownloadEvent
-   * - Composer\Script\ScriptEvents::* -> Composer\Script\Event
-   */
-  public static function getSubscribedEvents() {
-    return [
-      ScriptEvents::POST_INSTALL_CMD => 'onScriptEvent',
-      ScriptEvents::POST_UPDATE_CMD => 'onScriptEvent',
-    ];
-  }
-
   /**
   /**
    * Apply plugin modifications to Composer.
    * Apply plugin modifications to Composer.
    *
    *
@@ -71,6 +50,16 @@ class Builder implements Capable, Capability, EventSubscriberInterface, PluginIn
     $this->io = $io;
     $this->io = $io;
   }
   }
 
 
+  /**
+   * {@inheritdoc}
+   */
+  public function deactivate(Composer $composer, IOInterface $io) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uninstall(Composer $composer, IOInterface $io) {}
+
   /**
   /**
    * Composer plugin API: describe the plugin capabilities.
    * Composer plugin API: describe the plugin capabilities.
    */
    */
@@ -80,6 +69,27 @@ class Builder implements Capable, Capability, EventSubscriberInterface, PluginIn
     ];
     ];
   }
   }
 
 
+  /**
+   * {@inheritdoc}
+   *
+   * Available events:
+   *
+   * - Composer\Installer\InstallerEvents::*
+   *    -> Composer\Installer\InstallerEvent
+   * - Composer\Installer\PackageEvents::* -> Composer\Installer\PackageEvent
+   * - Composer\Installer\PluginEvents::INIT -> Composer\EventDispatcher\Event
+   * - Composer\Installer\PluginEvents::COMMAND -> Composer\Plugin\CommandEvent
+   * - Composer\Installer\PluginEvents::PRE_FILE_DOWNLOAD
+   *     -> Composer\Plugin\PreFileDownloadEvent
+   * - Composer\Script\ScriptEvents::* -> Composer\Script\Event
+   */
+  public static function getSubscribedEvents() {
+    return [
+      ScriptEvents::POST_INSTALL_CMD => 'onScriptEvent',
+      ScriptEvents::POST_UPDATE_CMD => 'onScriptEvent',
+    ];
+  }
+
   /**
   /**
    * Event callback: run build:settings  on post-install|update only.
    * Event callback: run build:settings  on post-install|update only.
    *
    *
@@ -88,7 +98,7 @@ class Builder implements Capable, Capability, EventSubscriberInterface, PluginIn
    *
    *
    * @throws \Exception
    * @throws \Exception
    */
    */
-  public function onScriptEvent(ScriptEvent $event) {
+  public function onScriptEvent(ScriptEvent $event): void {
     if (in_array($event->getName(), [
     if (in_array($event->getName(), [
       ScriptEvents::POST_INSTALL_CMD,
       ScriptEvents::POST_INSTALL_CMD,
       ScriptEvents::POST_UPDATE_CMD,
       ScriptEvents::POST_UPDATE_CMD,
@@ -99,17 +109,4 @@ class Builder implements Capable, Capability, EventSubscriberInterface, PluginIn
     }
     }
   }
   }
 
 
-  /**
-   * {@inheritdoc}
-   */
-  public function deactivate(Composer $composer, IOInterface $io) {
-    parent::deactivate($composer, $io);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function uninstall(Composer $composer, IOInterface $io) {
-  }
-
 }
 }

+ 3 - 3
src/BuilderCommandProvider.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-declare(strict_types = 1);
+declare(strict_types=1);
 
 
 namespace Fgm\Drupal\Composer;
 namespace Fgm\Drupal\Composer;
 
 
@@ -37,10 +37,10 @@ class BuilderCommandProvider implements CommandProvider {
   /**
   /**
    * BuilderCommandProvider constructor.
    * BuilderCommandProvider constructor.
    *
    *
-   * @param array|null $args
+   * @param mixed[]|null $args
    *   Guaranteed to contain composer/io/plugin as per CommandProvider.
    *   Guaranteed to contain composer/io/plugin as per CommandProvider.
    */
    */
-  public function __construct(array $args = NULL) {
+  public function __construct(?array $args = NULL) {
     $this->composer = $args['composer'];
     $this->composer = $args['composer'];
     $this->io = $args['io'];
     $this->io = $args['io'];
     $this->plugin = $args['plugin'];
     $this->plugin = $args['plugin'];

+ 1 - 1
src/HugoConfigCommand.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-declare(strict_types = 1);
+declare(strict_types=1);
 
 
 namespace Fgm\Drupal\Composer;
 namespace Fgm\Drupal\Composer;
 
 

+ 7 - 7
src/MergeParamsCommand.php

@@ -1,6 +1,6 @@
 <?php
 <?php
 
 
-declare(strict_types = 1);
+declare(strict_types=1);
 
 
 namespace Fgm\Drupal\Composer;
 namespace Fgm\Drupal\Composer;
 
 
@@ -48,12 +48,12 @@ EOT
   /**
   /**
    * Perform merging.
    * Perform merging.
    *
    *
-   * @param array $dist
+   * @param mixed[] $dist
    *   Distribution parameters (default).
    *   Distribution parameters (default).
-   * @param array $local
+   * @param mixed[] $local
    *   Local parameters (overrides).
    *   Local parameters (overrides).
    *
    *
-   * @return array
+   * @return mixed[]
    *   The merge result.
    *   The merge result.
    */
    */
   protected function merge(array $dist, array $local): array {
   protected function merge(array $dist, array $local): array {
@@ -126,15 +126,15 @@ EOT
    * the deepest array replace the less deep array. This is unlike the original
    * the deepest array replace the less deep array. This is unlike the original
    * function introduced in Drupal 8.x, from which this derives.
    * function introduced in Drupal 8.x, from which this derives.
    *
    *
-   * @param array $arrays
+   * @param mixed[] $arrays
    *   An arrays of arrays to merge.
    *   An arrays of arrays to merge.
    *
    *
-   * @return array
+   * @return mixed[]
    *   The merged array.
    *   The merged array.
    *
    *
    * @see \Fgm\Drupal\Composer\MergeParamsCommandTest::testMergeDeepArray()
    * @see \Fgm\Drupal\Composer\MergeParamsCommandTest::testMergeDeepArray()
    */
    */
-  public static function mergeDeepArray(array $arrays) {
+  public static function mergeDeepArray(array $arrays): array {
 
 
     $result = [];
     $result = [];
     foreach ($arrays as $array) {
     foreach ($arrays as $array) {

+ 5 - 4
src/PhpMemcacheAdminConfigCommand.php

@@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\InputArgument;
 use Symfony\Component\Console\Input\InputDefinition;
 use Symfony\Component\Console\Input\InputDefinition;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
+use Twig\TemplateWrapper;
 
 
 /**
 /**
  * Class Installer sets up PhpMemcacheAdmin in vendor/phpmemcacheadmin/Config.
  * Class Installer sets up PhpMemcacheAdmin in vendor/phpmemcacheadmin/Config.
@@ -109,15 +110,15 @@ EOT
   /**
   /**
    * Render the config from params.local.yml and the template.
    * Render the config from params.local.yml and the template.
    *
    *
-   * @param \Twig_TemplateWrapper $template
+   * @param \Twig\TemplateWrapper $template
    *   The template used to format the parameters.
    *   The template used to format the parameters.
-   * @param array $params
+   * @param mixed[] $params
    *   The parameters loaded from the local params file.
    *   The parameters loaded from the local params file.
    *
    *
-   * @return array
+   * @return mixed[]
    *   An array made of the relevant parameters.
    *   An array made of the relevant parameters.
    */
    */
-  protected function buildConfig(\Twig_TemplateWrapper $template, array $params) {
+  protected function buildConfig(TemplateWrapper $template, array $params): array {
     $params[static::BUILD_NAME]['basic']['file_path'] = realpath($params[static::BUILD_NAME]['basic']['file_path']);
     $params[static::BUILD_NAME]['basic']['file_path'] = realpath($params[static::BUILD_NAME]['basic']['file_path']);
     $variables = array_merge(
     $variables = array_merge(
       $params[static::BUILD_NAME]['basic'],
       $params[static::BUILD_NAME]['basic'],

+ 3 - 3
tests/MergeParamsCommandTest.php

@@ -3,16 +3,16 @@ declare(strict_types=1);
 
 
 namespace Fgm\Drupal\Composer;
 namespace Fgm\Drupal\Composer;
 
 
+use PHPUnit\Framework\Attributes\CoversMethod;
 use PHPUnit\Framework\TestCase;
 use PHPUnit\Framework\TestCase;
 
 
+#[CoversMethod(MergeParamsCommand::class,'mergeDeepArray')]
 final class MergeParamsCommandTest extends TestCase {
 final class MergeParamsCommandTest extends TestCase {
 
 
   /**
   /**
    * Test MergeParamsCommand::mergeDeepArray().
    * Test MergeParamsCommand::mergeDeepArray().
-   *
-   * @covers \Fgm\Drupal\Composer\MergeParamsCommand::mergeDeepArray
    */
    */
-  public function testMergeDeepArray() {
+  public function testMergeDeepArray(): void {
     // Base array (like a dist.params.local.yml).
     // Base array (like a dist.params.local.yml).
     $dist = [
     $dist = [
       'keyedArray1' => [
       'keyedArray1' => [