Composer Patches

Background

The cweagans/composer-patches composer plugin enables adding patches for your composer dependencies.

There have been reports that the Drupal Association is reporting large hosting costs associated with developers hotlinking patch files in their composer patches configuration. Beyond this, hotlinking patch files is not a good idea because it adds an additional dependency when building your project. If the D.A. servers are down, so is your ability to build your site.

At least it should be

Make sure you have "composer-exit-on-patch-failure": true, in the "extra" section of your composer.json file. This will stop composer install from completing if the patching fails. Without this turned on, it can be easy to not notice that a patch failed, and leave you without whatever fix you needed for the site.

Our Practice

In short:

  • Download patch files to the patches folder with a consistent filename to ensure easy maintenance.

  • Add patches to the composer.json file with metadata to make other developers' or our future selves' lives easier.

Patch Files

Patch files should be downloaded to a patches folder in your project root. They should be given a consistent filename consisting of the following information:

  • module_name - the machine name of the module

  • issue_number - the issue number for the issue where the patch is being discussed

  • comment_number - The comment number where the patch file was updated, or the most recent relevant comment number on the issue discussion. This will make it easier to go back and see what has changed when you need to go check on the patch.

Your patch file should follow the format: {{module_name}}-{{issue_number}}-{{comment_number}}.patch

How to get a patch file for a drupal.org ticket.

With the introduction of GitLab, this information is in flux. Patches on the ticket are being slowly replaced with Merge requests, and in the future .patch files may not be the best way to keep Drupal module bug fixes applied. This may be a good source for updated information.

Often patch files are uploaded to the ticket. This is useful because the patch corresponds to a specific moment in time in the issue discussion, and makes it easy to track which version of the fix you are working with.

If an up-to-date .patch file exists on the ticket, download that. Alternatively, if there is a merge request on the ticket, there should be a link labeled “plain diff” at the bottom of the issue summary. Right-click that, and save it to the patches directory with an appropriate

{{module_name}}-{{issue-number}}-{{most_recent_comment_number_on_the_issue}}.patch filename.

You can also get a patch from a GitLab merge request page by appending .patch to the URL.

Composer.json

Adding the patch to your composer.json project should be done in a similarly rigorous way as you did with your patch naming.

In composer.json we want to capture the following information:

  • Short Description

  • Jira Ticket ID

  • Issue/Comment URL

  • path to patch

Your composer.json patch entry will take the following form:

"{{package 1}}": { "{{short description} - {{jira-issue}} - {{issue/comment url}}": "{{patch path}}" }, "{{package 2}}": { "{{short description} - {{jira-issue}} - {{issue/comment url}}": "{{patch path}}" }

To give an example that lines up with the patches directory above:

"patches": { "drupal/unique_field_ajax": { "Stop the module from breaking VBO - s511-987 - https://www.drupal.org/project/unique_field_ajax/issues/3298235#comment-14614385": "patches/unique_field_ajax-3298235-4.patch" }, "drupal/views_bulk_edit": { "Copyright field gives required error even when not trying to change that field - s511-2011 - https://www.drupal.org/project/views_bulk_edit/issues/3024419#comment-14548770": "patches/views_bulk_edit-3024419-30.patch" } },

Edge Cases

Multiple Patches with Conflicts

If you’re applying more than one patch that has conflicts with the other patches you’re applying, you can have Composer install your own fork of a module with all your own patches applied. This doesn’t happen often, but it can happen…

  1. Fork the module on either GitLab or GitHub

  2. Create a new branch with all of your patches applied with the conflicts resolved. Name the branch something inspiring, like sfusd-1234--fancy-patches

  3. Reference the branch directly through composer…

{     "repositories": [         {             "type": "vcs",             "url": "https://github.com/kalamuna/stringoverrides "         }     ],     "require": {         "drupal/stringoverrides": "dev-sfusd-1234--fancy-patches"     } }
  1. The above will make Composer install the “allofmypatches” branch of stringoverrides, from Kalamuna’s own fork on GitHub.