Patching Modules using Composer Patches Plugin

For those who haven't done the composer thing long here is some documentation I wrote up for the Promet Source regarding patching modules using Composer using the Composer Patches Plugin.

https://packagist.org/packages/netresearch/composer-patches-plugin

https://github.com/netresearch/composer-patches-plugin

 

The readme on this one wasn't super clear to me so I thought I would take a stab at explaining it in my own words.

The way this plugin works is it takes a package of the "Patches" type and applys the specified patches you add to your "extra.patches" object to the appropriate package and release. Lets take a look at an example

 

Say for example I want to patch the admin_menu module. My composer.json may originally look like this:

{
  "name": "generalredneck/drupal-test-compose",
  "description": "Test Drupal Composer Site",
  "minimum-stability": "alpha",
  "type": "project",
  "repositories": [
    {
      "type": "composer",
      "url": "http://packagist.drupal-composer.org"
    }  
  ],
  "require": {
    "ckeditor/ckeditor": "dev-full/stable",
    "drupal/drupal-library-installer-plugin": "~0.1",
    "drupal/tangler": "~0.1.8",
    "drupal/views": "7.*",
    "drupal/wysiwyg": "7.2.x-dev",
    "drupal/admin_menu": "7.3.0-rc5",   
    "winmillwill/settings_compile": "~2.1.1"
  },
  "require-dev": {
    "drupal/devel": "7.*",
    "drupal/diff": "~7.3.2",
  },
  "extra": {
    "drupal-libraries": {
      "library-directory": "www/sites/all/libraries",
      "libraries": [
        {
          "name": "ckeditor",
          "package": "ckeditor/ckeditor"
        }
      ]
    }
  },
  "scripts": {
    "post-install-cmd": [
      "Drupal\\Tangler\\ScriptHandler::postUpdate",
      "vendor/bin/settings_compile cnf/config.yml www/sites/default/settings.php"
    ],
    "post-update-cmd": [
      "Drupal\\Tangler\\ScriptHandler::postUpdate"
    ]
  }
}

 

To patch admin_menu, we would add the following package to our "repositories" section

    {
      "type": "package",
      "package": {
        "name": "generalredneck/drupal-test-compose-patches",
        "version": "1.0.0",
        "type": "patches",
        "require": {
          "netresearch/composer-patches-plugin": "~1.0",
          "drupal/admin_menu": "7.3.0-rc5"
        },
        "extra": {
          "patches": {
            "drupal/admin_menu": {
              "7.3.0-rc5": [
                {
                  "title": "Admin Menu - Flush Caches Change",
                  "url": "https://www.drupal.org/files/issues/admin-menu-flush-caches-change-2378687-2.patch"
                }
              ]
            }
          }
        }
      }
    }

Note the "extra" section above. You have and object, who's key's are the packages you want to patch. Then the keys of that object are labeled after the releases. It is possible to patch something like a branch using 7.3.x-dev or dev-7.x-3.x, but this is undesirable as the patch could eventually break as commits are added to the branch.

The next then you will want to do is add the following to the require section of your project's composer settings. It allows you to increase the version of the package as you add patches and include that into your project still.

"generalredneck/drupal-test-compose-patches": "~1.0"

Note I also make this package "Require" the module I want to patch. This is just good practice, and keeps a running tab of all the modules you patched. Additionally it serves a secondary purpose, allowing you to have no need of adding the module to the require property below in the project's composer settings. So essentially by adding the line above, you said, your project requires also "netresearch/composer-patches-plugin": "~1.0", and "drupal/admin_menu": "7.3.0-rc5".

Note there are exceptions to this rule. If your minimum stability is something like Alpha, and you are trying to require a development release in your patches package, you will get an error that states "no satisfiable dependencies could be found." Because of this, you will have to specifically tell your project you want to include that development version, just like you do when a dev package can normally satisfy dependencies. For example:

  {
      "type": "package",
      "package": {
        "name": "generalredneck/drupal-test-compose-patches",
        "version": "1.0.0",
        "type": "patches",
        "require": {
          "netresearch/composer-patches-plugin": "~1.0",
          "drupal/admin_menu": "7.3.x-dev"
        },
        "extra": {
          "patches": {
            "drupal/admin_menu": {
              "7.3.x-dev": [
                {
                  "title": "Admin Menu - Flush Caches Change",
                  "url": "https://www.drupal.org/files/issues/admin-menu-flush-caches-change-2378687-2.patch"
                }
              ]
            }
          }
        }
      }
    }

Would require you to specify the following in your project's require statement if you had a minimum-stability of alpha or above:

"generalredneck/drupal-test-compose-patches": "~1.0",
"drupal/admin_menu": "7.3.x-dev"

Finally, your complete composer file may look like this with patching a non-dev release:

{
  "name": "generalredneck/drupal-test-compose",
  "description": "Test Drupal Composer Site",
  "minimum-stability": "alpha",
  "type": "project",
  "repositories": [
    {
      "type": "composer",
      "url": "http://packagist.drupal-composer.org"
    },
    {
     "type": "package",
      "package": {
        "name": "generalredneck/drupal-test-compose-patches",
        "version": "1.0.0",
        "type": "patches",
        "require": {
          "netresearch/composer-patches-plugin": "~1.0",
          "drupal/admin_menu": "7.3.0-rc5"
        },
        "extra": {
          "patches": {
            "drupal/admin_menu": {
              "7.3.0-rc5": [
                {
                  "title": "Admin Menu - Flush Caches Change",
                  "url": "https://www.drupal.org/files/issues/admin-menu-flush-caches-change-2378687-2.patch"
                }
              ]
            }
          }
        }
      }
    }
 ],
  "require": {
    "ckeditor/ckeditor": "dev-full/stable",
    "drupal/drupal-library-installer-plugin": "~0.1",
    "drupal/tangler": "~0.1.8",
    "drupal/views": "7.*",
    "drupal/wysiwyg": "7.2.x-dev",
    "generalredneck/drupal-test-compose-patches": "~1.0",
    "winmillwill/settings_compile": "~2.1.1"
  },
  "require-dev": {
    "drupal/devel": "7.*",
    "drupal/diff": "~7.3.2",
  },
  "extra": {
    "drupal-libraries": {
      "library-directory": "www/sites/all/libraries",
      "libraries": [
        {
          "name": "ckeditor",
          "package": "ckeditor/ckeditor"
        }
      ]
    }
  },
  "scripts": {
    "post-install-cmd": [
      "Drupal\\Tangler\\ScriptHandler::postUpdate",
      "vendor/bin/settings_compile cnf/config.yml www/sites/default/settings.php"
    ],
    "post-update-cmd": [
      "Drupal\\Tangler\\ScriptHandler::postUpdate"
    ]
  }
}

note that if you have an existing package, make sure you increment your package version as it's not obvious that caching happens on the package based on the version number for those not familiar with composer. So yes, please, if you are editing a package and adding new requirements to that package, increase it's version number.

A new issue come up recently with the newer versions of the composer patches plugin. Check out a the Issue Queue. There are 2 there... one for upgrading up to 1.2 and one for after you've upgraded. Turns out there is a hidden parameter in your patches that allow you to send arguments to the patch command. 

"args": "-F 0"

Is really handy for those patches that apply over and over and over again.