For one of my projects, I decided to combine learning Cypress and putting together a CI pipeline, adding in some realism by finding an existing project online, the fantastic Laragram by Luis Panta.
End result
name: CI
on:
pull_request:
branches: [master, development]
jobs:
build-and-run-tests:
runs-on: ubuntu-16.04
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: forge
MYSQL_DATABASE: forge
DB_HOST: 127.0.0.1
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Lint
uses: overtrue/phplint@master
- name: Copy ENV Laravel Configuration for CI
run: php -r "file_exists('.env') || copy('.env.ci', '.env');"
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '12.x'
- name: Install Dependencies (PHP vendors)
run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist && npm ci
- name: Generate key
run: php artisan key:generate
- name: Build site
run: npm run dev
- name: Execute unit tests via PHPUnit
run: vendor/bin/phpunit
env:
MYSQL_DATABASE: forge
DB_USERNAME: root
DB_PASSWORD: forge
DB_PORT: ${{ job.services.mysql.ports[3306] }}
- name: Migrate MySQL DB
env:
DB_CONNECTION: mysql
DB_DATABASE: forge
DB_PORT: 3306
DB_USER: root
DB_PASSWORD: forge
run: php artisan migrate:fresh --seed
- name: Cypress run
uses: cypress-io/github-action@v1
with:
browser: chrome
install: false
start: npm start
wait-on: http://localhost:8000
config-file: cypress.json
spec: cypress/integration/laragram/laragram.spec.js
- uses: actions/upload-artifact@master
# there might be no screenshots created when:
# - there are no test failures
# so only upload screenshots if previous step has failed
if: failure()
with:
name: screenshots
path: cypress/screenshots
# video should always be generated
- uses: actions/upload-artifact@master
with:
name: videos
path: cypress/videos
Journey
As part of this, I decided that most of the env characteristics would be immutable. I could not change them. However, I did create a .env.ci file. I also thought that the test environment should echo the production environment as much as possible.
CI/CD is new to me, so I decided I would start small. I would use the agile principle below, and write with verbosity.
- Make it work, then try and break it
- Make it right
- Make it fast
I had a couple of ideas in mind for the tests I would add to it
- check the code style is consistent
- run all the unit tests
- create UI tests for the core user journeys so I would run a linter, unit tests, and Cypress.
My first goal was to create a custom Docker image by imitating the setup on my local environment. So I looked at the Readme's setup instructions and the .env files to get an idea of where to start.
Then once I got it working, I would try some things to see if I added anything unnecessary, then add Continuous Deployment. Right now, I'm at 'got it working', time to delete any unnecessary cruft. This was a fascinating process.
Extra learning exercise
I built my own version of cypress-io/github-action@v1, and ran it on my local environment, because I couldn't work out why my build wasn't working and I wanted to rule it out. It turned out I migrated my database incorrectly, but here's the code that imitates cypress-io/github-action@v1 anyway for our education cases.
"npm run server:test": "start-server-and-test start 8000 test:ci"
which calls
"test:ci": "npx cypress run --spec cypress/integration/laragram/laragram.spec.js --env CYPRESS_BASE_URL=http://l27.0.0.1:8000 --browser chrome"
this does the same thing as
- name: Cypress run
uses: cypress-io/github-action@v1
with:
browser: chrome
install: false
start: npm start
wait-on: http://localhost:8000
config-file: cypress.json
spec: cypress/integration/laragram/laragram.spec.js
Starting and using a MySQL DB with Laravel on Github Actions
services:
mysql:
image: mysql:5.7
env:
MYSQL_ROOT_PASSWORD: forge
MYSQL_DATABASE: forge
DB_HOST: 127.0.0.1
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
- name: Migrate MySQL DB
env:
DB_CONNECTION: mysql
DB_DATABASE: {DATABASE}
DB_PORT: 3306
DB_USER: {USER}
DB_PASSWORD: {PASSWORD}
run: php artisan migrate:fresh --seed
PS: A green build doesn't always indicate success.
Top comments (0)