Composer Patches advanced usage
Following on from my recent article about How To Patch Drupal, this article will explore some more useful commands and additional functionality.
Avoid auto-generated patches
The contents of patches auto-generated by Pull/Merge Requests urls can change if further commits are pushed. This can pose functionality risks or even a security risk; a malicious user could add a commit that introduces vulnerabilities.
There are a few ways to avoid this. If you download a patch file you can add it to your codebase and specify the local path to it. I have also seen cases where devs have uploaded a patch file to the drupal.org issue, but I'm not sure whether this is to be encouraged. See the Patches lock file section below for details of how version 2 of Composer Patches provides the ability to lock the patch file version.
The eagle-eyed amongst you will have noticed that this warning was also included in the previous article, but the security implications of this mean that it cannot be stressed enough.
Add patches command
The Define Patches section of the previous article explained how to edit the composer.json file to specify a patch, but if you prefer to avoid manually editing files then here is an example of the command that will make the necessary addition:
composer config extra.patches.drupal/core --json --merge '{"description of patch": "https://www.example.com/file.patch"}'
In this example the patch applies to drupal/core, the label will be "description of patch" and the patch location is https://www.example.com/file.patch. You will also note that two flags are included; --json is required otherwise the entry will be treated as text, --merge is required to specify that this entry should be merged with any existing data, without it the entry would replace any existing data.
For a useful 'cheat sheet' you may want to bookmark the entry for this command in my Reference section: https://jofitz.co.uk/reference/composer/config. Also you can find the official Composer documentation here: https://getcomposer.org/doc/03-cli.md#modifying-extra-values.
Composer Patches v2
The second major version of Cameron Eagans' valuable Composer Patches package is in its second beta release (at time of writing) and introduces some very useful new functionality. Here are my highlights:
Patches lock file
Here is a brief example of a patches.lock.json file containing details of a single patch:
{
"_hash": "264ddb3fe435f43e5ba33599887bece19b3f6b459dc7d10e06d2c72d580915ac",
"patches": {
"drupal/smart_trim": [
{
"package": "drupal/smart_trim",
"description": "3367506: Properly handle <!--break--> HTML comment",
"url": "https://git.drupalcode.org/project/smart_trim/-/merge_requests/112.diff",
"sha256": "0c9978be992ef28b229d31bd2f8fb503d589ed63c1b224f153c40508978c0421",
"depth": 1,
"extra": {
"provenance": "root"
}
}
]
}
}
The patches.lock.json file works in a similar way to composer.lock. Most notably it will include a sha256 for each patch, calculated as part of installation, that will uniquely identify it. This solves the problem of using auto-generated patches because a new patch will only be requested if the sha256 changes. When an updated version of the patch is required then the command is:
composer patches-repatch
For details of this command read the official documentation here: https://docs.cweagans.net/composer-patches/usage/commands#composer-patches-repatch
Patches file
Details of patches can be moved from the extra.patches section of the composer.json into a separate patches.json file. The advantage is that there is no need to update composer.lock every time a patch changes. For more details read the official documentation here: https://docs.cweagans.net/composer-patches/usage/defining-patches/#patches-file
Patches expanded format
The Compact Format is what is used in version 1 of Composer Patches, specifically an object with descriptions as keys and patch urls for values. The Expanded Format extends on this by allowing other fields to be specified. Here is an example of the Expanded Format:
{
[...],
"extra": {
"patches": {
"drupal/smart_trim": [
{
"description": "Properly handle <!--break--> HTML comment",
"url": "https://git.drupalcode.org/project/smart_trim/-/merge_requests/112.diff",
"extra": {
"issue-tracker-url": "https://www.drupal.org/i/3367506#comment-16101292"
}
}
]
}
}
}Each entry still requires a "description" and "url" and for me the most useful addition is an "extra" field. As you can see in the example above, I use this for storing a link to the issue on drupal.org meaning that the issue number no longer needs to be included in the description.
Read the official documentation for details of other fields: https://docs.cweagans.net/composer-patches/usage/defining-patches/#expanded-format