How GRRR uses GitHub Actions
Over the last 6 months, GRRR migrated from Travis CI to GitHub Actions, and we happily shed light on how we arrange the workflows.
Understanding GitHub Actions vs Travis CI
It took considerable time to recognize the fundamental distinction between these platforms. While Travis CI concentrates on Continuous Integration, GitHub Actions responds to ecosystem events. GitHub Actions is a system to respond to events from the GitHub ecosystem. One such event is CI—triggered by push or pull_request actions—but numerous additional events exist.
The Workflows
For applications featuring unit tests alongside staging and production environments, GRRR creates four workflows:
- ci.yml: executes unit tests on every push
- deploy-staging.yml: deploys the
mainbranch to staging - deploy-production.yml: deploys tags to production
- deploy.yml: a reusable workflow preventing duplicate code in deployment workflows
ci.yml
The CI workflow incorporates multiple tools ensuring code functionality and security quality. Common tools include phpunit, jest, composer validate, php artisan migrate:rollback, phpstan, and prettier. Each tool typically receives its own job, facilitating easy identification of failed checks in the GitHub UI.
name: CI
on:
push:
branches:
- "**"
tags-ignore:
- "*-release"
jobs:
php-tests:
name: PHP tests
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
- run: composer install --prefer-dist --no-interaction --ansi
- name: Run PHPUnit
run: vendor/bin/phpunit tests/
static-analysis:
name: Static analysis
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
- run: composer install --prefer-dist --no-interaction --ansi
- name: Run PHPStan
run: vendor/bin/phpstan analyse
prettier:
name: Prettier
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: yarn install
- name: Run Prettier
run: npx prettier --check .
deploy-staging.yml
The staging environment should continuously run the latest main branch code. This workflow launches following a successful CI workflow completion on main.
A particularly valued feature among developers is workflow_dispatch, adding a GitHub UI button enabling manual workflow execution on developer-selected branches. This capability allows temporary non-main branch deployment to staging, facilitating experimental code demonstration to colleagues or prototype presentation to clients.
name: Deploy staging
on:
workflow_run:
workflows: ['CI']
branches: [main]
types:
- completed
workflow_dispatch:
jobs:
deploy:
name: Deploy
uses: organization/repo/.github/workflows/deploy.yml@main
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
with:
environment: staging
version: ${{ github.ref_name }}
secrets:
SSH_KEY: ${{ secrets.SSH_KEY }}
KNOWN_HOSTS: ${{ secrets.KNOWN_HOSTS }}
deploy-production.yml
Releases occur via tag creation: 1.2.3-release (using semver format with -release suffix). Every tag bearing this suffix deploys to production. Unlike deploy-staging, this workflow doesn't depend on CI. The commit the tag references has already undergone CI checks.
name: Deploy production
on:
push:
tags:
- "*-release"
jobs:
deploy:
name: Deploy
uses: organization/repo/.github/workflows/deploy.yml@main
with:
environment: production
version: ${{ github.ref_name }}
secrets:
SSH_KEY: ${{ secrets.SSH_KEY }}
KNOWN_HOSTS: ${{ secrets.KNOWN_HOSTS }}
deploy.yml
A reusable workflow contains on.workflow_call, supporting inputs and secrets properties. Secrets appear verbose because they repeat names—necessary since reusable workflows lack automatic secret access.
name: "Deploy app"
on:
workflow_call:
inputs:
environment:
description: "GitHub and app environment"
required: true
type: string
version:
description: "Tag or branch to deploy"
required: true
type: string
secrets:
SSH_KEY:
description: "SSH public key"
required: true
KNOWN_HOSTS:
description: "SSH known hosts"
required: true
jobs:
deploy-app:
name: Deploy app
environment: ${{ inputs.environment }}
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
ref: ${{ inputs.version }}
- name: Install SSH key
uses: shimataro/ssh-key-action@v2
with:
key: ${{ secrets.SSH_KEY }}
known_hosts: ${{ secrets.KNOWN_HOSTS }}
- uses: shivammathur/setup-php@v2
- name: Install PHP dependencies
run: composer install --prefer-dist --no-interaction --ansi
- name: Deployer
run: vendor/bin/dep deploy "${{ inputs.environment }}" --tag="${{ inputs.version }}" --log="deployer.log"
- name: Upload logs
uses: actions/upload-artifact@v3
if: always()
with:
name: logs
path: deployer.log
Originally published on norday.tech.