Drupal 9: Fix Composer modules prohibiting upgrade

Drupal 9: Fix Composer modules prohibiting upgrade

Drupal 9: Fix Composer modules prohibiting upgrade

How packages.drupal.org sets drupal/core version constraints that prevent updating to Drupal 9.

I went about to update a Drupal 8 project to Drupal 9. As preparation, I updated all Composer dependencies to their latest major versions and Drupal to the latest version of Drupal 8.

I quickly noticed that a few modules didn’t have a version out that supports Drupal 9 yet. Luckily all of them already had patches ready to fix this. Easy, just apply the patches inside the composer.json’s extra: { patches: { } } block (assuming you’re using the cweagans/composer-patches library). And done. Sadly this does not work. As documented in the composer-patches readme.

Have a look at the require part. composer.json file of the module:

{
  "name": "drupal/facets_pretty_paths",
  "type": "drupal-module",
  "description": "Facets Pretty Paths module.",
  "keywords": ["drupal"],
  "license": "GPL-2.0+",
  "minimum-stability": "dev",
  "prefer-stable": true,
  "authors": [
    {
      "name": "All contributors",
      "homepage": "https://www.drupal.org/node/2625160/committers"
    }
  ],
  **"require": {
    "drupal/facets": "~1",
    "drupal/pathauto": "~1"
  },**
  "require-dev": {
    "composer/installers": "^1.2",
    "cweagans/composer-patches": "~1.4",
    "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
    "drupal-composer/drupal-scaffold": "^2.2",
    "drupal/admin_toolbar": "^1.24",
    "drupal/coder": "^8.3",
    "drupal/config_installer": "~1",
    "drupal/console": "~1",
    "drupal/search_api": "~1.5",
    "drush/drush": "~9",
    "openeuropa/drupal-core-require-dev": "~8.6@rc",
    "openeuropa/task-runner": "~1.0-beta2"
  },
  "repositories": [
    {
      "type": "composer",
      "url": "https://packages.drupal.org/8"
    }
  ],
  "autoload": {
    "psr-4": {
      "Drupal\\facets_pretty_paths\\": "./src"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "Drupal\\Tests\\facets_pretty_paths\\": "./tests/src"
    }
  },
  "scripts": {
    "drupal-scaffold": "DrupalComposer\\DrupalScaffold\\Plugin::scaffold",
    "post-install-cmd": "./vendor/bin/run drupal:site-setup",
    "post-update-cmd": "./vendor/bin/run drupal:site-setup"
  },
  "extra": {
    "composer-exit-on-patch-failure": true,
    "enable-patching": true,
    "installer-paths": {
      "build/core": ["type:drupal-core"],
      "build/modules/contrib/{$name}": ["type:drupal-module"],
      "build/profiles/contrib/{$name}": ["type:drupal-profile"],
      "build/themes/contrib/{$name}": ["type:drupal-theme"]
    }
  },
  "config": {
    "sort-packages": true
  }
}

Code Source

This generates the following entry inside the composer.lock file:

{
    "name": "drupal/facets_pretty_paths",
    "version": "1.0.0",
    "source": {
        "type": "git",
        "url": "https://git.drupalcode.org/project/facets_pretty_paths.git",
        "reference": "8.x-1.0"
    },
    "dist": {
        "type": "zip",
        "url": "https://ftp.drupal.org/files/projects/facets_pretty_paths-8.x-1.0.zip",
        "reference": "8.x-1.0",
        "shasum": "c6660cd296dd68e2f22d42337035eca65ce94ffb"
    },
    "require": {
       ** "drupal/core": "~8.0",**
        "drupal/facets": "~1",
        "drupal/pathauto": "~1"
    },
    "require-dev": {
        "composer/installers": "^1.2",
        "cweagans/composer-patches": "~1.4",
        "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
        "drupal-composer/drupal-scaffold": "^2.2",
        "drupal/admin_toolbar": "^1.24",
        "drupal/coder": "^8.3",
        "drupal/config_installer": "~1",
        "drupal/console": "~1",
        "drupal/search_api": "~1.5",
        "drush/drush": "~9",
        "openeuropa/drupal-core-require-dev": "~8.6@rc",
        "openeuropa/task-runner": "~1.0-beta2"
    },
    "type": "drupal-module",
    "extra": {
        "branch-alias": {
            "dev-1.x": "1.x-dev"
        },
        "drupal": {
            "version": "8.x-1.0",
            "datestamp": "1568102885",
            "security-coverage": {
                "status": "not-covered",
                "message": "Project has not opted into security advisory coverage!"
            }
        },
        "composer-exit-on-patch-failure": true,
        "enable-patching": true,
        "installer-paths": {
            "build/core": [
                "type:drupal-core"
            ],
            "build/modules/contrib/{$name}": [
                "type:drupal-module"
            ],
            "build/profiles/contrib/{$name}": [
                "type:drupal-profile"
            ],
            "build/themes/contrib/{$name}": [
                "type:drupal-theme"
            ]
        }
    },
    "autoload": {
        "psr-4": {
            "Drupal\\facets_pretty_paths\\": "./src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Drupal\\Tests\\facets_pretty_paths\\": "./tests/src"
        }
    },
    "notification-url": "https://packages.drupal.org/8/downloads",
    "scripts": {
        "drupal-scaffold": [
            "DrupalComposer\\DrupalScaffold\\Plugin::scaffold"
        ],
        "post-install-cmd": [
            "./vendor/bin/run drupal:site-setup"
        ],
        "post-update-cmd": [
            "./vendor/bin/run drupal:site-setup"
        ]
    },
    "license": [
        "GPL-2.0+"
    ],
    "authors": [
        {
            "name": "All contributors",
            "homepage": "https://www.drupal.org/node/2625160/committers"
        },
        {
            "name": "Upchuk",
            "homepage": "https://www.drupal.org/user/1885838"
        },
        {
            "name": "dasjo",
            "homepage": "https://www.drupal.org/user/228295"
        }
    ],
    "description": "Facets Pretty Paths module.",
    "homepage": "https://www.drupal.org/project/facets_pretty_paths",
    "keywords": [
        "drupal"
    ],
    "support": {
        "source": "https://git.drupalcode.org/project/facets_pretty_paths"
    }
}

Check out the require part. “drupal/core”: “~8.0” is also required. Hmm.. looks like the drupal.org Packagist adds this automatically 🤔

I found this in the documentation about using composer.json files for Drupal modules:

Having a composer.json file is not required for Drupal 9 compatibility. A Drupal 9 compatible info.yml file is required and is enough. If your project does have a composer.json file, having a drupal/core version requirement is also not required for Drupal 9 compatibility. It is better not to provide a drupal/core version requirement in composer.json because Drupal's composer facade will generate the appropriate metadata based on the info.yml file. If for some reason you do need to have a drupal/core version requirement in your composer.json file's require section, then it needs to be Drupal 9 compatible.

Alright, so the Packagist takes the version requirement from the module’s .info.yml file then. Which looks like this for this particular module:

name: 'Facets Pretty Paths'
type: module
description: 'Pretty paths for Facets.'
**core: 8.x**
package: Search
dependencies:
  - facets:facets
  - pathauto:pathauto

Code Source

Since the updated version requirement (core_version_requirement: ^8 || ^9) is not committed to the module’s .info.yml file yet, and only available as a patch, the Packagist adds the requirement for Drupal 8 to the composer.json file, and does not allow Drupal 9.

Not great..

Option 1: You can copy the Git repo to your own Git instance (or GitHub, GitLab, whatever..) of the module and add a repository of type “git” to the repositories section inside the composer.json (Note: Needs te be above the packages.drupal.org entry).

Option 2: I prefer this variant. Create a composer.json repositories entry of type “package”. For example:

"**my-author**/facets_pretty_paths": {
    "type": "package",
    "package": {
        "name": "**my-author**/facets_pretty_paths",
        "version": "dev-6db0247",
        "source": {
            "type": "git",
            "url": "https://git.drupalcode.org/project/facets_pretty_paths.git",
            "reference": "6db0247"
        },
        "require": {
            "drupal/core": "^8.8 || ^9.0"
        },
        "type": "drupal-module"
    }
}

This way you “create your own” module using the Git repository of the module.

Note the my-author part. Otherwise Composer would always get the module from the packages.drupal.org repository, even when setting the — prefer-source flag. I couldn’t find any .zip URLs for specific commits that could be added as “dist” to the package definition.

You can specify any version using the “version” and “reference” properties. Documented here. If you want to know how Git references work, you can look it up in the Git docs.

In this case I used a specific commit, because the patch that makes the module compatible with Drupal 9 didn’t apply to a tagged version.

You can remove this and replace your “custom module” with the real one once the maintainer made it compatible with Drupal 9.

Option ?: Feel free to post a comment if you found a better solution :)

Resolving issues with Drupal Console & Drush

If you use Drush

I needed to add consolidation/site-process to the Composer update statement.

Drupal Console ist not ready for Drupal 9

At the time of writing, the drupal/console library does not support Drupal 9 yet. Thus I needed to remove it.

composer remove drupal/console

There is an open issue for Drupal 9 compatibility: https://github.com/hechoendrupal/drupal-console/issues/4250

Finally: Updating Drupal Core

Change the version constraint of drupal/core to ^9.0 inside the composer.json file.

Update Drupal Core and it’s dependencies:

composer update symfony/* symfony-cmf/* twig/twig laminas/* drupal/core

🎉