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