Do you want to run your tests on each PHP version you support? PHP 7.3, 7.4 and 8.0?
Instead of 3 workflows with copy-paste steps, you can define just one with a matrix for PHP versions.
But PHP is released every year. The version constraints are already defined in composer.json
.
Hmm, how could we use this knowledge to provide a list of PHP version for a dynamic matrix?
Do you know memory locks? An "if this then that" code smell. E.g., you always have to put keys into your left pocket, after you lock your office door.
If we have tests, we want them run on all PHP versions we support. To be sure, no PHP 8 features are running on PHP 7.4.
When new PHP version once a year, then we have to:
update composer.json
update test workflow
This is utterly useless operation = double the work and double the maintenance—no gain, except the fear of control.
Could you guess how much time it took to send both commits? 2 minutes? 10 minutes?
Almost 2 hours. I had to send a new commit based on feedback in code-review. That's a hidden cost of memory lock code smell. Hidden cost in attention, work and slow feedback loop.
composer.json
What PHP version should be tested? The information is already in composer.json
:
{
"require": {
"php": "^7.2|^8.0"
}
}
You're right. It's this list:
So why should we duplicate this information in the GitHub Actions workflow config?
We can do better with dynamic matrix.
Symplify 9 is coming with a brand new package called EasyCI. This package helps you with CI maintenance, like in our case above:
composer require symplify/easy-ci --dev
vendor/bin/easy-ci php-json
# "[7.2, 7.3, 7.4, 8.0]"
Now we have a problem, the command to provide JSON data and GitHub Actions. Let's put them together.
There are 2 steps in our unit tests workflow:
jobs:
# first step
provide_php_versions_json:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- uses: shivammathur/[email protected]
with:
# this is the only place we have to use PHP to avoid the lock to bash scripting
php-version: 8.0
- run: composer install --no-progress --ansi
# to see the provided output, just to be sure
- run: vendor/bin/easy-ci php-versions-json
# here we create the json, we need the "id:" so we can use it in "outputs" bellow
-
id: output_data
run: echo "::set-output name=matrix::$(vendor/bin/easy-ci php-versions-json)"
# here, we save the result of this 1st phase to the "outputs"
outputs:
matrix: ${{ steps.output_data.outputs.matrix }}
# continue from above
unit_tests:
needs: provide_php_versions_json
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ${{ fromJson(needs.provide_php_versions_json.outputs.matrix) }}
# continue with tests
steps:
# ...
- run: vendor/bin/phpunit
This workflow is not just a theory. It's tested for last week on Symplify repository and it works :).
Here is full .github/workflows/unit_tests.yaml
worfklow to explore.
Happy coding!