11
  • 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 Sep 17 '20 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 Sep 17 '20 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 Sep 17 '20 at 17:52
  • What @Mrweiner said - I spent a few hours trying to get around it some weeks back, without success – Clive Sep 17 '20 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 Sep 17 '20 at 19:09
13

Update

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": "git@git.drupal.org: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": "git@git.drupal.org: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.


Previous Answer

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)

12
  • 1
    Where's this "reference": UUID thing coming from? Is it a commit hash? – leymannx Sep 22 '20 at 23:22
  • 1
    Yes that's a commit hash, you'll need to update it to have composer install the next version, but it's still better than forking. See getcomposer.org/doc/05-repositories.md#package-2 – Darvanen Sep 24 '20 at 0:20
  • 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 Oct 6 '20 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). – James Williams Feb 5 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. – miststudent2011 Mar 30 at 7:23
6

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 Feb 4 at 5:09
  • James, is it possible to use this method with a patch stored locally ? – lchabrand Jul 27 at 6:40
  • @Ichabrand - yes, absolutely. Here's an example: github.com/cweagans/composer-patches/issues/… – James Williams Jul 28 at 8:30
2

Instead of having to maintain a set of package repositories for each module that is not yet ready, my preferred solution is to ask composer to install Drupal 9 for me 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.

The solution is simply to 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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