14
  • Given I have Drupal 9 composer installation with composer-patches plugin
  • and given a contrib module with a stable v8 release, but no v9 release (not even dev branch)
  • and given that contrib module has a working v9 patch in the issue queue

is there any method to install that module + patch in composer? Even if I manually add both, the package and patch, to my composer.json, I still can't require or update this module with composer due conflicting versions. I really want to avoid duplicating /contrib code into my project's /custom codebase. My current workaround is:

  • forking that module to my own, private git repo
  • applying patch there
  • creating a new composer.json in my private git, and changing the package vendor to my custom_private_vendor
  • adding my private git as VCS repo in the D9 project's composer.json
  • and then composer require custom_private_vendor/contrib_module

This fulfills my goal of not duplicating the contrib module in my project's custom codebase, but every time I do this I feel the urge to wash my dirty hands.

Is there something more elegant like composer require drupal/contrib_module --apply-patch-first or can I somehow target drupal.org's git with a specific patch included?

7
  • What's the nature of the composer conflict? Is it due to the contrib module's composer.json?
    – Mrweiner
    Commented Sep 17, 2020 at 17:46
  • An un-updated v8 contrib module from the official drupal repo will always require drupal/core:^8.something. The project is set up with drupal/core:^9.0.6
    – Hudri
    Commented Sep 17, 2020 at 17:49
  • 3
    I haven't jumped into D9 yet so not yet familiar with how the reqs work, but the reason I ask is that if the issue is due to the contrib module's composer.json then there is no way to handle the issue with a patch. See github.com/cweagans/….
    – Mrweiner
    Commented Sep 17, 2020 at 17:52
  • What @Mrweiner said - I spent a few hours trying to get around it some weeks back, without success
    – Clive
    Commented Sep 17, 2020 at 18:36
  • 1
    That's what I found too @Hudri - it's the core_version_requirement in the module's .info.yml which informs the packager of the core dependency. If that's not available, it's presumed to be just 8 (or it's derived from the core key instead perhaps)
    – Clive
    Commented Sep 17, 2020 at 19:09

3 Answers 3

18

Drupal 10

As reported by @rocketeerbkw, the official lenient endpoint in packagist currently doesn't support Drupal 10.

https://github.com/mglaman/composer-drupal-lenient does.

Instructions for use are in the repo.


Drupal 9

The official advice is now to use a specially made lenient endpoint as described in Using Drupal's Lenient Composer Endpoint.


Issue forks

Official advice found at: Use issue forks to make compatibility fixes work with Composer

Copied here for convenience:

It's impossible to install an incompatible module with composer and apply a compatibility patch afterwards. However, since issue forks are branches it's possible to install the module using that branch. In order to do this we need to do 3 things.

Under the repositories section where the composer source is listed we need to add an exclude key for our module that we're trying to install using the issue fork. In my example I'm trying to install a issue for the Homebox module.

{
    "type": "composer",
    "url": "https://packages.drupal.org/8",
    "exclude": [
        "drupal/homebox"
    ]
}

Next up we need to add the specific git URL to our repositories section. You can find this URL under the "show commands" section of the issue fork.

{
    "type": "git",
    "url": "[email protected]:issue/homebox-3146462.git"
}

Our complete repositories key looks something like this now:

"repositories": [
    {
        "type": "composer",
        "url": "https://packages.drupal.org/8",
        "exclude": [
            "drupal/homebox"
        ]
    },
    {
        "type": "git",
        "url": "[email protected]:issue/homebox-3146462.git"
    }
],

Now we can use the composer install command to require the module. Important here is that you need to specify the branch name prefixed with "dev-". So for the homebox example the command would look like this:

composer require 'drupal/homebox:dev-3146462-drupal-9-compatibility'

It's possible that for the first time when you execute this you're prompted to allow the ECDSA key fingerprint for git.drupal.org. Just type yes and composer will continue.


Commit reference

You've got the right idea but you don't need to fork Drupal's repository. You can set up composer to read Drupal's git repo instead of using packagist for the naughty modules like this:

{
    "type": "package",
    "package": {
        "name": "drupal/cache_control_override",
        "type": "drupal-module",
        "version": "1.0.0",
        "source": {
            "type": "git",
            "url": "https://git.drupalcode.org/project/cache_control_override.git",
            "reference": "8db91684a427366d8f9c51f60cbac10c2d586d95"
        }
    },
    {
      "type": "composer",
      "url": "https://packages.drupal.org/8"
    }
},

Note the reference is a commit hash, though it looks like you can also use tags. Also note that the custom git type: package repo must be before Drupal's default type: composer repo in your composer file.

And then patch as normal using composer:

"drupal/cache_control_override": {
    "Drupal 9 Compatibility (3132036)": "https://www.drupal.org/files/issues/2020-04-29/Drupal-9-readiness-3132036-2.patch"
},

Thanks @miststudent2011 for pointing out that this doesn't automatically install dependencies which I can confirm. You will need to require those yourself!

(Shamelessly stolen from @acbramley on Drupal Slack because wider dissemination of this knowledge is worthwhile)

13
  • 1
    Where's this "reference": UUID thing coming from? Is it a commit hash?
    – leymannx
    Commented Sep 22, 2020 at 23:22
  • 3
    Just for comepleteness: You must not fork it, but you must still use a custom vendor name when declaring the repo for the module to be patched. You can not the use original drupal/... vendor/package name
    – Hudri
    Commented Oct 6, 2020 at 12:42
  • 2
    @hudri the custom vendor name is only necessary if the additional section under 'repositories' has been added after the packages.drupal.org entry. If you add the custom section to the top, then the original drupal/package vendor+name can be used, as the custom section redefines the metadata for that package entirely (which is why this works, as it ignores the compatibility data for the package that had been coming from that packages.drupal.org endpoint). Commented Feb 5, 2021 at 12:05
  • 2
    Just to add , this method is not downloading required dependencies. Tried with this way still no success. For example we can consider brightcove module which has brightcove api dependency. drupal.org/docs/upgrading-drupal/… dependency is not being installed here. Commented Mar 30, 2021 at 7:23
  • 2
    For Drupal 10, the lenient composer endpoint isn't supported. Use the new lenient composer plugin instead github.com/mglaman/composer-drupal-lenient Commented Jan 16, 2023 at 4:28
7

For a wider explanation of why Darvanen's answer is necessary, see https://www.computerminds.co.uk/articles/apply-drupal-9-compatibility-patches-composer (disclaimer: I wrote this). But do note that using a different vendor namespace (like drupal_git) shouldn't be necessary if the section is added to your composer.json file's 'repositories' above the one for packages.drupal.org .

Ultimately, composer processes the dependency & compatibility metadata for packages, and so decides to reject the package - before composer gives the cweagans/composer-patches plugin chance to patch it. This method overrides the metadata so the package isn't rejected before patching.

3
  • Thanks James, I did notice my own implementation didn't require the altered vendor namespace but I couldn't explain it so I deferred to Hudri, oh well.
    – Darvanen
    Commented Feb 4, 2021 at 5:09
  • James, is it possible to use this method with a patch stored locally ?
    – lchabrand
    Commented Jul 27, 2021 at 6:40
  • @Ichabrand - yes, absolutely. Here's an example: github.com/cweagans/composer-patches/issues/… Commented Jul 28, 2021 at 8:30
3

In case anyone comes across this question in the future, the official solution is to use the lenient endpoint as described in Using Drupal's Lenient Composer Endpoint.


Alternatively you can reach the same with Composer aliases. So you ask Composer to install Drupal 9 as if it were installing Drupal 8. This solution is probably not compatible with installing a Drupal 9-only module, but it worked for me when I about 10 modules away from having a Drupal 9 compliant system. The trick is very simple, and the only drawback is that you'll need to keep updating the now fixed version of core.

Replace all:

"drupal/core-composer-scaffold": "^9.1.5",
"drupal/core-recommended": "^9.1.5",

With:

"drupal/core-composer-scaffold": "9.1.5 as 8.9.99",
"drupal/core-recommended": "9.1.5 as 8.9.99",

And the same for drupal/core-dev, if that is used in the require-dev section. This way, a Drupal 8-only module won't block your installation of Drupal 9. You'll still need to apply the D9-readiness patch, as Drupal core will complain if the core_version_requirement is not set correctly.

1
  • Not bad :) Personally I want to know when a module is incompatible so I can help push it along the compatibility path
    – Darvanen
    Commented Aug 27, 2021 at 5:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.