How to work around libraries that fall behind
I have come across many challenges when it comes to managing dependencies in software development projects. One of the most common challenges is managing outdated Composer dependencies.
Composer is a popular dependency management tool for PHP that allows developers to declare and manage project dependencies. While Composer makes it easy to install and update dependencies, it can also lead to the accumulation of outdated libraries, which can create security vulnerabilities and cause compatibility issues.
Fortunately, there is a way to manage outdated Composer dependencies by cloning them into a personal repository. This process involves creating a personal repository for outdated libraries and tagging items for release, so Composer can detect which version to use.
Here are the steps to follow when managing outdated Composer dependencies:
1. Clone the outdated dependency into a personal repository
The first step in managing outdated Composer dependencies is to clone the outdated dependency into a personal repository. To do this, clone the third party library to your machine then change the remote to an empty, personal, repository on a version control platform such as GitHub, GitLab or Bitbucket. Forking the repo is another option, but not ideal because you'll have to manage more than necessary.
git clone https://github.com/third-party/library
git remote remove origin
git remote add origin https://github.com/personal/library
2. Create branches for the outdated dependency
The next step is to create branches for the outdated dependency. This involves creating a branch for each version of the dependency that you want to keep. By creating branches, you can make changes to the code and test them without affecting the original code or other projects depending on your repo.
My preferred method is to check out the most stable release of the library and create branch names that match the third-party library's versioning system. For semantic versioning, I typically denote the major and minor numbers while keeping the patch number an 'x' so it's easier to keep projects updated between library patches.
git checkout <outdated-release>
git checkout -b 10.6.x
You can repeat this process for each version of the dependency that you want to keep.
3. Make changes locally
Before our project can depend on our version of the third-party library, we need to update the repository so that all the bugs and Composer constraints are up to date.
The quickest method for me is to temporarily link the new repo as a local repository in my project's Composer file. To use a specific version number you may have to tag the code ahead of time. Otherwise, you should be able to denote the branch the version lives on by replacing ^10.6.4 with something like -dev
"repositories": [
"personal/library": {
"type": "path",
"url": "/Users/john/code/library"
}
]
...
"require": {
"third-party/library": "^10.6.4"
}
Every time you make a change to the library you will need to update Composer in your project.
composer update
4. Tag and publish your changes
Once you have confirmed your library is updated and working with your project, you should tag the last change with the version number. When you make future changes to the library it will less likely affect other projects.
git tag -a 10.6.4
git push --tags
Depending on which git platform you are using, you may have to publish and release an archive of the code for Composer to recognize your changes as "stable".
Alternatively, you can update your project's Composer file to allow less stable code but prefer stable code when it is available.
{
"minimum-stability": "dev",
"prefer-stable": "true"
}
Finally, change your repository information so Composer uses version control instead of the local file system, then run composer update
"repositories": [
"personal/library": {
"type": "vcs",
"url": "git@github.com:personal/library.git"
}
]
...
"require": {
"third-party/library": "^10.6.4"
}
5. Wrapping Up
It is worth noting that while this approach is effective for managing outdated dependencies, but not ideal because you are deviating from the original source of the library. Over time it can lead to a more complicated dependency tree that requires manual updates.
When taking this approach it's a good idea to periodically check the original source for updates and remove unused personal repositories when they are no longer needed.
Conclusion
Managing outdated Composer dependencies is an important part of software development, and cloning them into a personal repository is an effective way to keep them up to date.
Top comments (1)
One thing not commented on too much here is having the dependency on... well, dependencies, and how destructive that can be if they disappear. I'm not talking about them no longer being maintained, but disappearing all together.
A few years ago we built an app that relied fairly heavily on a library for generating barcodes. The barcode support we needed was a little niche, so the options for libraries was fairly limited. Anyway, we built the app, with a dependency on this library and all was well with the world.
The project lay dormant for a period of time and didn't actually go live at any point. A while in the future we needed to add a couple of features and then go ahead an launch. We hit an issue when cloning the repo and running
composer install
...404 Not Found
on a repo URL. The owner of the repository hadn't just abandoned it, but they also deleted it. Everything, gone.This was an app in development, so it wasn't like we could just go and grab the folder from the
vendor
folder in production. It was gone. And we had a heavy dependency on it.Lesson learnt: Anything you rely on heavily, ensure you fork it and keep a copy yourself in a private repo, just in case (licence permitting, of course).
Fortunately we managed to get a copy of the library in question from an old dev machine we had, so not all bad :)