Producer: Validate and Release PHP Library Packages
tl;dr: Producer will look over your Composer-based library package just before you are ready to tag it for release, make sure it appears ready-to-go, and then do the release for you through Github, Gitlab, or Bitbucket. Producer works with both Git and Mercurial.
I. History
Back when I was working on Solar, we needed a process to package up each release of the entire framework and make sure I hadn’t forgotten anything. Thanks to the magic of the Internet Archive, you can see it here. You can read more about the 10 year old (!!!) process here; the script is of course PEAR-centric, since PEAR was the main packaging system available in PHP at that time.
After Solar was done, we began extracting its individual components as 30 or so separate packages in Aura. As before, I needed a process to make sure each package release was actually ready-to-go, so that earlier PEAR-centric release script evolved into a collection of Composer-centric commands. These release and management tools are specifically for Aura, with its particular conventions and expectations in mind, and have served well for 3 major versions of the project over the last 5+ years.
But now I have started some non-Aura projects: Relay, Radar, Arbiter, Bookdown, and most recently Atlas. These projects do not have the benefit of the automated release process, with all of its checks and validation, that Aura does.
With that in mind, then, I have extracted a substantial amount of the Aura package release process into a new project, Producer, so that I can use it with any non-Aura library package. That means you can use it with your library package, too.
II. Why Use Producer?
When you think your Git or Mercurial library package repository is ready for a tagged version release, Producer help to validate that it is actually in a high-quality releasable state. Then, if Producer thinks everything looks good, it will release your library package through its remote origin API (i.e., through Github, Gitlab, or Bitbucket).
(Note that Producer is not for regular daily development work. It is specifically for the day you want to release the package. At that time, it can be easy to forget steps in a release process; Producer manages those steps for you.)
III. Validating A Package For Release
Most of the things Producer checks for are there because I forgot to check them myself at some point in the past, and it was embarassing for one reason or another.
For example, you don’t want to make a release from a local copy that has not been updated to match the remote copy, or when the local copy has some modified or uncommitted files. So the very first thing Producer does is to pull down changes from the remote origin, push up local changes to the remote, and then check the local status to see if there are uncommitted files. If the local status check fails, Producer won’t release the package.
After it’s sure the local copy is in a clean state, Producer will run composer validate
to make sure it has no obvious errors. Obviously, if composer.json
is not valid, the package is not in a releasable state.
Next, Producer looks to see if you have a particular set of non-empty informational files in place. These are administrative, but necessary: README
, LICENSE
, CONTRIBUTING
, and CHANGES
(not CHANGELOG
yet; more on that later). The files may or may not have .md
extensions. These files ought to be present in any packaged release, so Producer will fail if they are not present, or if they are empty.
Of course, Producer can’t tell if their contents are sensible or not, though it can tell if the LICENSE
notes the current year. If it does not, Producer will tell you to update the copyright year in the LICENSE
. You don’t want to release a package with an outdated copyright year!
After that, Producer will run your test suite with PHPUnit. Producer expects that you have a phpunit.xml.dist
file at the root of your package, so if that’s missing, the release will fail. Likewise, if the tests fail, Producer will not release the package.
As part of the test-running, Producer will issue composer update
to make sure all the require-dev packages are in place. After the tests pass, Producer will check the local copy status yet again, to make sure the tests have cleaned up after themselves properly. This also has the benefit of checking that your “ignore” files are set up properly; at the very least, composer.lock
and vendor/
should be ignored, so their presence in the status check will cause Producer to stop its release process.
We want to have well-documented code, so Producer runs PHPDocumentor to check all the docblocks in the package src/
directory. (Yes, this presumes that you have a src/
directory in your library package.) If any PHP docblocks are missing or malformed, Producer will stop the release. Similarly, if the @package
tags are missing or incorrect, Producer will tell you which files and stop the release. (In this case, “correct” means “the same as the Composer package name”.)
As the next-to-last step in the validation process, Producer examines your CHANGES
file commit timestamp. If the CHANGES
file is not part of the very last commit, Producer will balk, and tell you to update your CHANGES
so that all changes have been mentioned in the release notes. (Producer uses CHANGES
because that’s what I use in Aura; at some point in the future, this may become CHANGELOG
, but for now just the release-specific change listing seems enough.)
Finally, Producer will go to your remote origin API and retrieve a list of open issues for the repository. This is not technically a validation step, only a reminder in case there issues you have forgotten to address. If there are open issues, Producer will not stop the release process.
IV. Releasing A Package
The above validations can be run on their own using the producer validate
command; they are useful as a pre-flight or pre-check to the actual release process. When the validate
command finishes successfully, you can move on to the release
command; the release process is exactly the same as the validation process, with the added step of actually releasing the package when validation passes.
At this point, Producer has already looked at your .git
or .hg
configuration to determine the remote origin API; this can be Github, Gitlab, or Bitbucket. It then prepares and sends a release through that API, using the CHANGES
file for the release notes.
Afterwards, it will sync the local copy with the remote origin to pull down any newly-created tags.
That’s it; you’re done! Producer has now run a series of “final checks” on your repository and released it with a new version number.
V. Questions
When I announced Producer over the weekend, it got posted to Reddit by somone other than me (for once ;-). I hope I have answered the “why is Producer useful?” question with this blog post. Two others remain:
-
Q: “Why does Producer run
composer update
as part of validation? It should only look at the current state of the repo, not modify the repo.”A: Perhaps “validation” is not the right word to use. It’s intended as a pre-flight or preparatory step towards releasing, to make sure that the package will actually install what it
require
s through Composer. In addition, for my own projects at least, the tests use the Composer autoloader for thesrc/
files, socomposer update
is a necessary preliminary to running the tests. -
Q: “Why require PHPDocumentor and PHPUnit as part of Producer? What if I have those already installed somewhere else?”
A: For myself, global installs of these kinds of ecosystem-level tools seem reasonable, but that may be a function of the fact that I mostly manage library packages; having 30+ installs of PHPUnit and PHPDocumentor is just not to my liking. Having said that, I can see how some folks would have different requirements, so I’ll see if I can modify that requirement in a future version of Producer.
Finally, if you have questions/comments/critique, please raise them as issues over at Github. Thanks, and I hope Producer is as useful to you as its earlier versions in Aura have been to me!
Read the Reddit discussion about this post here.