How to do continuous integration (CI) with a Laravel Nova project that also does database testing
Automated testing and continuous integration are huge topics. I find even experienced programmers sometimes completely miss the point and skip both. To me, this is a selfish act and extremely presumptuous - do you really think you're client deserves that you will be forever the only programmer on their project?
I use Laravel Nova in many of my projects. I also use GitHub Actions and for my private clients of course I have private repos. So far I've battled to get Laravel Nova working nicely in GitHub Action's in continuous integration environment. Totally, finally, I got this right.
The components that has to play together are CI and GitHub Actions and authentication and MySQL.
Part of the problem is that the Laravel Nova has extremely scant information on how to do actual authentication and if authentication to nova.laravel.com fails in the pipeline your tests will never run.
The current documentation refers to "CodeShip" and I clearly remember how they've hyperlinked to other CI tools in the past. Their comment about storing auth.json
in source control is apt but also misguided because they don't give clear instructions on how to use it with something as common as GitHub Actions.
Moving on swiftly I only got this working by creating an auth.json
file in the root of my project. The command given in the Laravel Nova documentation, namely this one:
composer config http-basic.nova.laravel.com ${NOVA_USERNAME} ${NOVA_LICENSE_KEY}
does not help. Instead, this is what I had to do:
cat auth.json
{
"http-basic": {
"nova.laravel.com": {
"username": "user@example.com",
"password": "nova-license-key"
}
}
}
Once you have the licensing problem sorted out you can move over to what the YAML file must look like. I used Spatie's Package Skeleton for Laravel as a base and then found MySQL specific information in this file made by Shivam Mathur.
The end result of my working run-tests.yml is this:
name: tests
on:
push:
pull_request:
jobs:
tests:
runs-on: ubuntu-22.04
strategy:
fail-fast: true
matrix:
php: ['8.1']
laravel: [9]
name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
env:
DB_DATABASE: laravel
DB_USERNAME: root
DB_PASSWORD: password
NOVA_USERNAME: ${{ secrets.NOVA_USERNAME }}
NOVA_LICENSE_KEY: ${{ secrets.NOVA_LICENSE_KEY }}
# See https://github.com/shivammathur/setup-php/blob/master/examples/laravel-mysql.yml
# Docs: https://docs.github.com/en/actions/using-containerized-services
# Had to include DB_PORT for last test
services:
mysql:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: false
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: laravel
ports:
- 3306/tcp
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, bcmath
ini-values: error_reporting=E_ALL
tools: composer:v2
coverage: none
- name: Install dependencies
run: |
composer require "illuminate/contracts=^${{ matrix.laravel }}" --no-update
composer update --prefer-dist --no-interaction --no-progress
- name: Prepare Laravel Application
run: |
cp .env.ci .env
php artisan key:generate
- name: Execute tests
run: vendor/bin/phpunit --verbose
env:
DB_PORT: ${{ job.services.mysql.ports['3306'] }}
The caveats and extras I had to put in apart from what's in the Spatie boilerplate is this:
A services section to load a MySQL container. It's still abundantly unclear to me if I really need this, but anyhow, this one works. It certainly slows down the test but at least it's working.
A "Prepare Lavel Application" section to copy a .env.ci file over .env
Key generation
DB_PORT in the "Execute tests" section.
You'll also notice a NOVA_USERNAME and NOVA_LICENSE_KEY sections. This was a feeble attempt to implement variables based secrets in GitHub actions but it has no effect and the auth.json is still required.
Conclusion
CI is a power tool when used with automated testing and Laravel. Getting it working is a slog and a lot of small caveats to get right but worth the effort.