In the previous post, we looked at Why is First Instant Feedback Crucial to Developers?.
We know why now we look at how. How exactly migrate all jobs from Travis to GitHub Actions, reduce stress from long feedback loops and live a more healthy life as a programmer.
Yes, in code samples :)
In this post, we'll look at examples of migration. I'll share my good and bad times with GitHub Action for my last 3 weeks using it on 5 open-source repositories with over 25 packages.
From ~15 minutes to just 3 minutes.
I mean, that's a crazy improvement of 80 %. You can read about in the previous post, so let's move on.
Github Actions just make everything so easy...
— Tomas Votruba (@VotrubaT) January 22, 2020
We merged 177 PR in @rectorphp in the last month.
Instant feedback is killer feature for you devs. Don't let them wait...https://t.co/hP9Epe2CZW pic.twitter.com/0Md9iIisXm
Cocaine, Facebook, Twitter, and Instagram work the same way. A short feedback loop of dopamine.
The significant advantage of GitHub is that at the end of your addiction is not an endless loop in the brain, but higher productivity of your project.
We'll jump right into the most common case - unit tests.
In Travis CI, we had to:
# .travis.yml
os: linux
language: php
php:
- '7.2'
- '7.3'
- '7.4'
before_install:
# turn off XDebug
- phpenv config-rm xdebug.ini
install:
- composer install --no-progress
jobs:
include:
-
stage: test
name: "Unit Tests"
script:
- vendor/bin/phpunit --testsuite main
In GitHub Action the same process look like this:
# .github/workflows/code_checks.yaml
name: Code_Checks
on:
pull_request: null
push:
branches:
- main
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php: ['7.2', '7.3', '7.4']
name: PHP ${{ matrix.php }} tests
steps:
# basically git clone
- uses: actions/checkout@v2
# use PHP of specific version
- uses: shivammathur/setup-php@v1
with:
php-version: ${{ matrix.php }}
coverage: none # disable xdebug, pcov
# if we 2 steps like this, we can better see if composer failed or tests
- run: composer install --no-progress
- run: vendor/bin/phpunit
That's pretty huge for single and confusing to read at the same time, right?
All that clutter just for vendor/bin/phpunit
to pass.
What is this?
- uses: actions/checkout@v2
Github Actions allow references to external recipes. It's usually just a set of actions, packages into a couple of lines in our workflow. You can see it on Github, e.g. actions/checkout. It's the recommended way to re-use code because there is no other way.
In reality: "Do you want to re-use 5 lines of install and setup YAML code? Create a repository on Github, write 100 lines in JavaScript, and you're ready to go!"
Saying that we'll either have to create custom workflow repository or get used to these lines being repeated over and over:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v1
with:
php-version: '7.3'
coverage: none # xdebug is used by default
- run: composer install --no-progress
After a bit of experimenting, I got used to it for now. Also, Github Actions don't have anything close to YAML Anchors or re-use of previous job configuration like we have in Travis, e.g., share install
for every job:
# .travis.yml
install:
- composer install --no-progress
Do you want YAML Anchors in Github Actions? Let them know.
Now that we have the worst feature of Github Actions behind us, let's look at the excellent stuff.
On the other hand, external workflows can solve a lot for us. Mainly for us, who don't want to dev-ops experts forever CI there is.
How do you enable code coverage by PHPUnit? Change single line:
jobs:
test_coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v1
with:
php-version: '7.3'
- coverage: none
+ coverage: pcov
- run: vendor/bin/phpunit --coverage-clover coverage.xml build/logs/clover.xml
What is the most common use case for CI? Run single line in this specific PHP version → e.g., run coding standards on PHP 7.2.
In Travis CI:
language: php
install:
- composer install --no-progress
jobs:
include:
-
name: ECS
php: 7.2
script:
- composer check-cs
In Github Actions:
# .github/workflows/code_checks.yaml
jobs:
ecs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: shivammathur/setup-php@v1
with:
php-version: 7.2
coverage: none # disable xdebug, pcov
- run: composer install --no-progress
- run: composer check-cs
Some organizations don't have access to Github Actions because of some open-sources/private accounts. This sucks a lot. I tried to have GitHub Actions on KnpLabs/DoctrineBehaviors, but it's not possible unless the whole KnpLabs switches to some paid accounts. I spoke with support over a dozen emails, and it's wont fix.
How to work around this? If we create a new organization that is open-source only, it will work. Or we can just move the repository to an existing open-source only one.
In Travis, you could add a badge for the whole build on a specific branch. It was nice that it skipped allowed failure.
In GitHub Actions, it's different. The badge covers 1 specific workflow. This workflow should contain all the relevant jobs.
Actually, on GitHub repository, there is only one badge for all:
Travis CI allow only 3 concurrent jobs. This forces us to group similar checks like coding standard, static analysis, and Rector to one big job. If it failed, we had to look inside to find out which of these 3 areas is it.
GitHub Actions allows you to run... wait for it 20 jobs.
Thanks to that, we can have one job for each of:
bin/console lint:yaml
bin/console lint:twig
bin/console lint:container
When bin/console lint:twig
fails, we know right in the pull-request it's something in our templates. That's good quality, precise feedback.
GitHub Actions are tough to work with local git. I migrated Symplify/MonorepoBuilder and Symplfiy/ChangelogLinker to Github Actions, and it's only troubling.
Another weakness is the inability to get the current tag. That's right. Getting something as simple as an existing tag is rocket science.
That's why we had to revert rector.phar
build and publish to Travis CI.
The monorepo split is the most massive performance operation on the whole CI. Also, GitHub actions have different git settings that break it — saying that it makes sense to have 20 parallel jobs on GitHub Actions and the heaviest on Travis. We kept monorepo split on Travis as the only job and it's now faster than ever.
I think that's due to the service being pretty new to the market. I hope these issues will be seen as primitive soon. For the rest of the features, I love GitHub Action and think you'll too after having feedback under 3 minutes after the last commit :).
Happy coding!
Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors.
I'd really appreciate it!