Whatever the size of the software project, I believe in, subscribe to, and promote Continuous Integration. Personally, I rely on GitHub Actions as an automated build system. Even this blog here is built with, and eventually deployed into production using GitHub Actions.
Regardless of whether an automated build system can be set up and used for a project or not, I prefer to be able to run build steps locally. This prevents stress-testing the automated build system and taking away resources from other developers. Also, it gives me more confidence before committing and pushing changes upstream.
The first time I heard of an automated build tool was when I was working on a crowd investment project in 2011. Back then a developer set up Capistrano, and I didn’t understand a thing. Then had used Phing for a while. For a couple of years now I have been using
make, after having been introduced to it when working on a project in 2014. While it has its limitations, it’s short and simple, and most of all, it get’s the job done.
Speaking of getting the job done: since I can’t be bothered to set up the basics of a new project from scratch all the time, I have created
ergebnis/php-library-template, a GitHub repository template and also a PHP project which I have submitted to Packagist. Doing so allows me to use
composer to quickly create a new project. Whether you are working alone or for an organization, I encourage you to provide an easy means set up new projects quickly. For that specific template project, I commit and push directly into the existing branches to keep the templates up to date with my ideas of a great template. Thus, running
$ composer create-project ergebnis/php-library-template composer-normalize
quickly creates a new project in the
composer-normalize directory, based on the branch
As a starting point, the template contains a
Makefile similar to the following:
.PHONY: coverage cs infection integration it test it: cs test coverage: vendor vendor/bin/phpunit --configuration=test/Unit/phpunit.xml --coverage-text cs: vendor vendor/bin/php-cs-fixer fix --config=.php_cs --diff --verbose infection: vendor vendor/bin/infection --min-covered-msi=80 --min-msi=80 test: vendor vendor/bin/phpunit --configuration=test/Unit/phpunit.xml vendor/bin/phpunit --configuration=test/Integration/phpunit.xml vendor: composer.json composer.lock composer self-update composer validate composer install
As you can see, I have defined a few phony targets, which may run any number of commands, or depend on so-called prerequisites.
For example, running
$ make test
will first execute the
vendor target, followed by running unit and integration tests. Running
$ make cs
will first execute the
vendor target, followed by running
php-cs-fixer. You get the idea.
I use the following recipe in my Makefiles:
vendor: composer.json composer.lock composer install
This will compare the timestamp of the
vendordirectory with those of
composer.lock, and will only execute the recipe if either of the composer files is newer than the
vendordirectory, or if the vendor directory is missing.
Excellent, this saves even more time!
Finally, I have added an
it target. Running
$ make it
will execute all of the targets I consider important enough to be run before - as I suggested earlier - increase my confidence to commit and push changes upstream.
Now, you might have noticed that while I have a penchant for keeping things sorted, I have intentionally defined
it as the first target. There’s a good reason to it: unless a target has been specified explicitly, the first target defined in the
Makefile will be executed. That is, by making
it the first target, I can run
to execute all of the important targets.
Nonetheless, as I have gotten into the habit of running these many, many (dozends? hundreds?) of times throughout the day, it’s still a bit too much typing, right? Therefore, I have created an alias in my shell configuration:
# Makefile alias m="make"
achieves the same now. I believe that’s the closest thing to making a build in one step, with only two key strokes.
Hope it helps to increase your productivity!
P.S.: Of course, one can use composer scripts to achieve something similar, but while it is more portable, it also has more limitations in regard to naming (can’t use script names for which commands already exist).