Skip to main content

GitHub Actions

php-ci is designed to run as the container for a GitHub Actions job. Because the PHP toolchain is already inside the image, you skip the shivammathur/setup-php step entirely — checkout, composer install, test.

Minimal workflow

Create .github/workflows/ci.yml:

name: CI
on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
container:
image: himanshuramavat/php-ci:8.3
steps:
- uses: actions/checkout@v4
- run: composer install --no-interaction --no-progress --prefer-dist
- run: ./vendor/bin/phpunit

Test matrix

Validate across every supported PHP line by templating the image tag from the matrix value:

name: CI
on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['8.1', '8.2', '8.3', '8.4']
container:
image: himanshuramavat/php-ci:${{ matrix.php }}
name: PHP ${{ matrix.php }}
steps:
- uses: actions/checkout@v4
- run: composer update --no-interaction --no-progress --prefer-dist
- run: ./vendor/bin/phpunit

Cache Composer dependencies

Speed up installs by caching Composer's global cache directory between runs:

jobs:
test:
runs-on: ubuntu-latest
container:
image: himanshuramavat/php-ci:8.3
steps:
- uses: actions/checkout@v4
- name: Cache Composer packages
uses: actions/cache@v4
with:
path: /tmp/composer-cache
key: composer-${{ hashFiles('**/composer.lock') }}
restore-keys: composer-
- run: composer install --no-interaction --no-progress --prefer-dist
env:
COMPOSER_CACHE_DIR: /tmp/composer-cache
- run: ./vendor/bin/phpunit

With a database service

jobs:
test:
runs-on: ubuntu-latest
container:
image: himanshuramavat/php-ci:8.3
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: secret
POSTGRES_DB: app_test
options: >-
--health-cmd pg_isready --health-interval 10s
--health-timeout 5s --health-retries 5
env:
DB_HOST: postgres
DB_DATABASE: app_test
DB_USERNAME: postgres
DB_PASSWORD: secret
steps:
- uses: actions/checkout@v4
- run: composer install --no-interaction --no-progress
- run: ./vendor/bin/phpunit
Service hostnames

When a job runs inside a container, service containers are reachable by their service name (postgres, mysql) rather than 127.0.0.1. Set your DB_HOST accordingly.

Using the GitHub Container Registry

The image is mirrored to GHCR, which avoids Docker Hub rate limits for GitHub runners. Reference it the same way:

container:
image: ghcr.io/himanshuramavat/php-ci:8.3

Full project example

A deploy-ready CI file combining lint, analyse and test:

name: CI
on: [push, pull_request]

jobs:
quality:
runs-on: ubuntu-latest
container:
image: himanshuramavat/php-ci:8.3
steps:
- uses: actions/checkout@v4
- run: composer install --no-interaction --no-progress --prefer-dist
- name: Coding standard
run: ./vendor/bin/phpcs --standard=PSR12 src
- name: Static analysis
run: ./vendor/bin/phpstan analyse src --level=6
- name: Tests
run: ./vendor/bin/phpunit --coverage-text