When you use software that is open source, you'll sometimes run into issues or small bugs that have already been fixed by the community in a PR or an issue, but have yet to be merged and/or released. If you're impatient and need that fix now, composer patches can be a solution for this problem.
You can start using composer packages by installing the cweagans/composer-patches composer package.
composer require cweagans/composer-patches
Once this is installed, you can configure it inside your composer.json file under the extra
key. But before we can do that, you need a patch to apply!
The easiest way to get a patch is by getting it from a pull request on Github. Github allows you to download a .diff
or .patch
file (both are supported by the composer plugin) by requesting the page of the pull request, followed by the file extension. For example:
https://github.com/spatie/ray/pull/266 can be downloaded as a .diff
by visiting https://github.com/spatie/ray/pull/266.diff
The PR above looks like this:
diff --git a/src/Ray.php b/src/Ray.php index 0c94673..6d1a080 100644 - -- a/src/Ray.php + ++ b/src/Ray.php @@ -94,14 +94,14 @@ public function newScreen(string $name = ''): self return $this->sendRequest($payload); } - public function clearAll() + public function clearAll(): self { $payload = new ClearAllPayload(); return $this->sendRequest($payload); } - public function clearScreen() + public function clearScreen(): self { return $this->newScreen(); } @@ -271,7 +271,7 @@ public function image(string $location): self return $this->sendRequest($payload); } - public function die($status = '') + public function die($status = ''): void { die($status); } @@ -413,7 +413,7 @@ public function pause(): self return $this; } - public function html(string $html = '') + public function html(string $html = ''): self { $payload = new HtmlPayload($html);
Once you have the patch file, you can add it to a folder inside your project and configure the patch to be applied. I use <project-root>/patches
.
Inside the extra
key of your composer.json
you can configure all patches
"extra": { "patches": { "spatie/ray": { "Add missing return types": "patches/github-pr-266.diff", } } },
This tells the composer-patch plugin to patch the spatie/ray
package using the patches/github-pr-266.diff
file. Every time you now run composer install
or composer update
, the plugin will re-fetch the package from packagist, and re-apply your patches to it.
You could also link straight to the diff url which will apply the diff in full without having to download the file. But I prefer having more control over the patch as changes to the PR could result in unexpected patches.
Your composer output will contain something along the following:
Removing package some/package so that it can be re-installed and re-patched. - Removing spatie/ray (v1.18) ... Gathering patches for root package. Gathering patches for dependencies. This might take a minute. ... - Applying patches for spatie/ray patches/github-pr-266.diff (Add missing return types)
If a patch fails, composer will skip the patch and continue by default. If you would like it to fail instead, you can configure it by adding "composer-exit-on-patch-failure": true
to the extra
key in your composer.json
.
Once the PR you need is merged and released, the patch won't do anything anymore and you're free to delete it.
If your patch includes changes to test files, for example when you've downloaded the patch from a PR that includes changes to tests, your patch might not work when using it on a distributed composer package, as those don't include the tests files most of the time.
In this case there's two options:
Remove the changes to tests from your diff
Adjust the preferred-install
of the package you're patching to source
:
{ "config": { "preferred-install": { "spatie/ray": "source" } } }