Menu
«

Continuous Integration (CI)

To help keep code quality and style consistent across projects we use a few developer tools that are installed locally per project and run by Github Actions on each Git push. You may check the Atlantis repo for a working example.

Composer scripts

Add the following to the composer.json "scripts" property:

"eslint": "node_modules/.bin/eslint --ext .js resources/js/ --max-warnings=0",
"stylelint": "node_modules/.bin/stylelint resources/sass/**/*.scss",
"larastan": "vendor/bin/phpstan analyse",
"phpmd": "vendor/bin/phpmd app/ text phpmd.xml",
"phpcs": "vendor/bin/php-cs-fixer fix",
"phpunit": "php artisan test --parallel --stop-on-failure",
"test": [
    "@eslint",
    "@stylelint",
    "@larastan",
    "@phpunit"
]

Setup Github Actions

We use Github Actions on all new projects as our CI/CD pipeline. Github Actions is cheaper and faster than all other services and has a really powerful set of features.

To add Github Actions to a project, create a .github/workflows/tests.yml file in the root of your project. This is a typical example of a tests.yml file:

name: CI

on: [push]

jobs:
  tests:
    name: Run PHP tests
    runs-on: ubuntu-latest
    if: "!contains(github.event.head_commit.message, '--skip-ci')"

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Install PHP 8.3
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'
          extensions:
          coverage: none

      - name: Setup Github token for private repos
        run: composer config -g github-oauth.github.com ${{ secrets.GH_ACCESS_TOKEN }}

      - name: Cache composer dependencies
        uses: actions/cache@v4
        with:
          path: vendor
          key: composer-${{ hashFiles('composer.lock') }}

      - name: Install composer dependencies
        run: composer install -n --prefer-dist --no-scripts --no-progress

      - name: Setup locales
        run: sudo locale-gen sv_SE.UTF-8

      - name: Prepare Laravel
        run: |
          cp .env.example .env
          php artisan key:generate

      - name: Cache npm dependencies
        uses: actions/cache@v4
        with:
          path: node_modules
          key: npm-${{ hashFiles('package-lock.json') }}

      - name: Run npm
        run: npm ci

      - name: Create database
        run: |
          sudo /etc/init.d/mysql start
          mysql -u root -proot -e 'CREATE DATABASE app;'

      - name: Run tests
        run: composer test
        env:
          DB_DATABASE: app
          DB_USERNAME: root
          DB_PASSWORD: root

      - name: Upload logs on failure
        uses: actions/upload-artifact@master
        if: failure()
        with:
          name: Logs
          path: ./storage/logs
          
      - name: Deploy prod if master
        if: success() && github.ref == 'refs/heads/master' && !contains(github.event.head_commit.message, '--skip-deploy')
        run: |
          curl --silent --show-error --fail -X POST ${{ secrets.DEPLOY_PROD_URL }}
          curl --silent --show-error --fail -X POST ${{ secrets.DEPLOY_STAGING_URL }}

Be sure to validate the file with an online YAML validator before pushing it to Github for the first time. The GH_ACCESS_TOKEN variable is an Organization secret personal access token (on the adaptivemachine account) which gives composer read access to our private repos. This is possible since the adaptivemachine user is added to a Read team which is added on all our private repos.

Every project is different and has different needs, but this is a good starting point. Check out our other repos for various examples.