CI for Laravel

The Build Specification

Chipper CI prefers (but does't require) that you include a .chipperci.yml file in the root of your repository. That file will control the build environment the project uses.

  1. It can set the environment - the PHP and Node versions
  2. It can set the services - extra software used, such as databases, caches, and Docker
  3. It can set the pipeline - the commands that are run to build, test, and deploy your application
  4. It allows you to have branches with difference code environments
    • For example, if you have a branch to test out a newer version of PHP
  5. It lets you easily copy build definitions across multiple projects

If you don't have a .chipperci.yml file in your repository, you can define the build environment, services, and pipeline within the project settings at app.chipperci.com.


Here's every option you can currently use in the .chipperci.yml file:

# Assume version 1
version: 1

# Choose between PHP and NodeJS majar versions
environment:
  php: 8.4                          # 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5
  node: 24                          # 6, 8, 10, 12, 14, 16, 18, 20, 22, 24

services:
  # Choose only one of these databases
  - mysql: 5.7                      # 5.6, 5.7, 8
  - mariadb: 10.3                   # 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 10.1, 10.1, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8
  - postgres: 13                    # 10, 11, 12, 13, 14, 15, 16, 17
  - postgis/postgis: 16-3.4         # 10-3.0, 11-3.0, 12-3.0, 13-3.0, 14-3.0, 14-3.4, 15-3.3, 15-3.4, 16-3.4
  - pgvector/pgvector: pg17         # pg13, pg14, pg15, pg16, pg17

  # Add redis, just like this, with the trailing colon
  # This always equates to the "redis:latest" Docker image
  - redis:

  # Paid accounts can add in Docker support,
  #  useful for running Vapor deployments.
  # Ensure you have the trailing colon.
  - docker:

  # Include the Chrome browser for use 
  #  in Dusk browser tests
  - dusk:

# Decide what events trigger a build
on:
  # "push" is a regular, old commit.
  # This will build on push to any branch
  # Note that `.*` is a regex!
  push:
    branches: .*

  # This will build on PR open, re-open, and update
  # (Updates are when commits are pushed to a PR)
  pull_request:
    # "branches" filters by SOURCE branch (the feature branch being merged)
    # Example: only build PRs coming FROM feature/* or bug/* branches
    branches:
      - feature/.*
      - bug/.*

    # "target" filters by DESTINATION branch (the branch being merged INTO)
    # Example: only build PRs targeting main or release/* branches
    target:
      - main
      - release/.*

    # When both "branches" and "target" are specified, BOTH must match (AND logic)
    # Example above: PRs from feature/* branches INTO main or release/*

  # This will build on the (re)creation of any
  # tag that starts with `v`
  tags:
    - v.*

# The pipeline commands can be just about anything.
# Note the use of the pipe character to allow you to
#  have multi-line commands
pipeline:
  - name: Setup
    cmd: |
      cp -v .env.example .env
      composer install --no-interaction --prefer-dist --optimize-autoloader
      php artisan key:generate

  - name: Compile Dev Assets
    cmd: |
      npm ci --no-audit
      npm run build

  - name: Run Tests
    cmd: phpunit

Best Practices

Use the pipeline to call scripts you commit to your repository. If I forget to write more here, yell at me at support@chipperci.com.

Notes on Triggers (on:)

There's a few points to clarify on the events that trigger a build.

  1. For backwards-compatibility, omitting the on: section will build every build (rather than no builds at all)
  2. If you don't use a .chipperci.yml file (what are you even doing?!), then build decisions are configured in project settings under Build Restrictions
  3. Don't use * for wildcards, but instead the Regular Expression .* (more info below)

Branches (and tags) can be defined as a single value or a list of branches/tags:

# These are valid:
on:
  push:
    branches: .*

  pull_request:
    branches: feature/.*

  tags: .*

# And these are valid:
on:
  push:
    branches:
      - main
      - develop
      - feature/.*

  pull_request:
    branches:
      - feature/.*
      - bug/.*

  tags: 
    - .*

Combine push, pull_request, and tags any way you'd like.

Pull Request Target Branches

For pull requests, you can filter by both the source branch (where the code is coming from) and the target branch (where the code is going to):

on:
  pull_request:
    # "branches" = SOURCE branch (the feature branch being merged)
    # Matches the branch name of the PR head
    branches:
      - feature/.*
      - hotfix/.*

    # "target" = DESTINATION branch (the branch being merged INTO)
    # Matches the base branch the PR is targeting
    target:
      - main
      - release/.*

Examples:

PR branches target Builds?
feature/loginmain feature/.* main ✅ Yes (both match)
feature/logindevelop feature/.* main ❌ No (target doesn't match)
hotfix/urgentmain feature/.* main ❌ No (source doesn't match)
feature/thingmain (not set) main ✅ Yes (only target filter)

Key points:

  • Use branches alone to filter by source branch (existing behavior)
  • Use target alone to filter by destination branch
  • Use both together for precise control (AND logic - both must match)
  • Omit both to build all PRs

Regular Expressions

Branches and tags are treated as regular expressions, and are run through preg_match_all() in format /^your-regex$/.

Use phpliveregex to test your expressions.

As a quick example, branch feature/.* would be tested with:

$regex = '/^feature\/.*$/'; // Regex generated from `feature/.*`
$actualBranchName = 'feature/my-new-feature';

if (preg_match_all($regex, $actualBranchname) > 0) {
    // Perform build
}

Useful Links