In one of my previous articles I’ve written about how to create an automated pipeline for continuous integration and continuous delivery using travis. Lately GitHub actions are quite popular, I am also experimenting with them. I started by reading the articles written by the guys from Spatie, you can find them here and here. While setting up the actions I encountered some issues with the mysql service, I’ll dive into it later. Let’s set up the same pipeline as last time. Run the tests for every push and deploy the application if the tests are successful.
TL;DR;
For those who don’t have time to read the whole article, here is the final version of the yaml configuration:
name: Build
on: [push, pull_request]
jobs:
laravel-tests:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: tracy_test
ports:
- 3307:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v1
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.ci', '.env');"
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
- name: Generate key
run: php artisan key:generate
- name: Set up Passport
run: php artisan passport:keys
- name: Execute tests (Unit and Feature tests) via PHPUnit
run: vendor/bin/phpunit
deploy:
if: github.ref == 'refs/heads/master'
needs: [laravel-tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Deploy
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
eval "$(ssh-agent -s)"
ssh-add - <<< "${DEPLOY_KEY}"
mkdir ~/.ssh
echo -e "HostName example.com\n\tStrictHostKeyChecking no\n\t"User deploy >> ~/.ssh/config
composer install
vendor/bin/dep deploy
Create the workflow
First we need to create a workflow by creating a .yaml file in the .github/workflows directory, for example: .github/workflows/laravel.yml. In this file we’re going to define the runner environment, the jobs and the steps to run.
We are defining the workflow to run on push and pull request events:
on: [push, pull_request]
We’ll have 2 jobs to run laravel-tests and deploy.
Run the tests
Let’s take a look what steps are necessary for running the tests.
Checkout the code
- uses: actions/checkout@v1
Create the .env file. For this step we assume you have and .env.ci file in your project (it should be committed to the repository!)
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.ci', '.env');"
Install dependencies with composer
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist
Generate the application key
- name: Generate key
run: php artisan key:generate
Create passport keys. This step is optional, only necessary if your project is using passport
- name: Set up Passport
run: php artisan passport:keys
And the last step, run the tests
- name: Execute tests (Unit and Feature tests) via PHPUnit
run: vendor/bin/phpunit
For testing you can use sqlite database which is very quick but does not have all the features as other databases such as MySQL. For my use case I am using the mysql service because the project uses spatial data types.
When I first time set up the mysql service, according to the articles I’ve read and according to the documentation, I got the following error when running the tests: SQLSTATE[HY000] [1049] Unknown database. After some experimenting, I realized that the GitHub runners come with preinstalled software (you can find the list here). They also have mysql preinstalled, but when you define the mysql service, it starts a mysql docker container.
I came up with two solutions:
- Create the test database in the preinstalled mysql server:
- name: Create database
run: mysql -uroot -proot -e 'create database tracy_test;'
- Use a different port for the docker service, and define the database in the service definition
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: tracy_test
ports:
- 3307:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
Please note the ports section it cannot run on the same port as the built in mysql service, so it is using 3307 for the mysql. In this case you’d need to set up the .env.ci accordingly:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3307
DB_DATABASE=tracy_test
DB_USERNAME=root
DB_PASSWORD=root
If you have other solution(s) for the mysql service problem, please let me know in comments.
Deploy
I am big fan of deployer, although there are plenty of other solutions for deployment like AWS, Docker etc. For my personal/small scale projects deployer just works well. I won’t go into the details of the server side setup, I did it in a previous article, if you are interested please check it here.
We need to allow the login from GitHub actions to our server. Generate a private/public key pair, add the public key to the authorized_keys of your deploy user on the server. Add the private key as a secret to your repository, you can find it under Settings/Secrets :
We only want to deploy form the master branch, and only if all the test have passed.
deploy:
if: github.ref == 'refs/heads/master'
needs: [laravel-tests]
The needs key ensures that the deploy only runs when the tests passed.
Add the DEPLOY_KEY to the env variables
- name: Deploy
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
Set up the ssh agent to use your key for login
run: |
eval "$(ssh-agent -s)"
ssh-add - <<< "${DEPLOY_KEY}"
mkdir ~/.ssh
echo -e "HostName example.com\n\tStrictHostKeyChecking no\n\t"User deploy >> ~/.ssh/config
Run composer install and deploy the project:
composer install
vendor/bin/dep deploy
If everything goes well the tests run and the project gets deployed automatically after each push on the master branch.
So far the GitHub actions seem to work well, probably I’ll use it for CI/CD related tasks for all my projects in the future.
If you have any suggestions or problem setting this up, please feel free to share them in comments.
The post Using Github actions and Deployer for creating CI/CD for Laravel appeared first on Daniel Werner.
Top comments (0)