PHPQA is a centralized quality assurance system for PHP projects that provides:
- Reusable Castor tasks for all QA operations
- Reusable GitHub Actions workflows
- Automatic download from GitHub (no path dependencies)
- Minimal configuration per project
- Support for libraries, bundles, and applications
Use the migration script to automatically set up everything:
cd ~/Projects/phpqa
# For a library or bundle
./scripts/migrate-project.sh /path/to/your/project library
# For an application
./scripts/migrate-project.sh /path/to/your/app applicationThis creates:
- ✅
castor.phpwith GitHub auto-download (~40 lines) - ✅
.phpqa-config.phpconfigured for your project type - ✅
.github/workflows/ci.ymlwith reusable workflow - ✅
.gitignoreentry for.castor-cache/
Then test it:
cd /path/to/your/project
castor list # Downloads PHPQA tasks (first time only)
castor qa:all # Run all QA checks- Copy an example castor.php:
cp ~/Projects/phpqa/examples/castor-simple.php your-project/castor.php- Optional: Add configuration:
cp ~/Projects/phpqa/examples/.phpqa-config-library.php your-project/.phpqa-config.php- Add to .gitignore:
echo "/.castor-cache/" >> your-project/.gitignore- Test:
cd your-project
castor list # Downloads PHPQA tasks automatically
castor qa:lint # Quick testAfter setup, your project will have:
your-project/
├── .castor-cache/ # Cache directory (gitignored)
│ ├── phpqa.php # Downloaded from GitHub
│ └── phpqa.version # Cached version marker
├── .phpqa-config.php # Configuration (optional)
├── castor.php # ~40 lines with auto-download
├── .gitignore # Contains: .castor-cache/
└── .github/
└── workflows/
└── ci.yml # Reusable workflow configuration
$ castor list
Downloading PHPQA tasks from GitHub...
✓ PHPQA tasks downloaded successfully!
Available commands:
qa:phpunit Run PHPUnit tests with coverage
qa:phpstan Run PHPStan
qa:ecs Run Easy Coding Standard
...$ castor list
Available commands:
qa:phpunit Run PHPUnit tests with coverage
...The downloaded tasks are cached in .castor-cache/ and reused.
# Force re-download of latest version
rm -rf .castor-cache/
castor list# Testing
castor qa:phpunit # Run PHPUnit with coverage
castor qa:infect # Mutation testing with Infection
# Static Analysis
castor qa:phpstan # Run PHPStan
castor qa:phpstan-baseline # Generate PHPStan baseline
# Code Style
castor qa:ecs # Check coding standards
castor qa:ecs-fix # Fix coding standards automatically
# Refactoring
castor qa:rector # Check Rector rules
castor qa:rector-fix # Apply Rector refactorings
# Architecture & Quality
castor qa:deptrac # Validate architecture layers
castor qa:lint # Check PHP syntax
castor qa:validate # Validate composer.json
castor qa:check-licenses # Check dependency licenses
# JavaScript
castor qa:js # Run JavaScript tests (if enabled)
# Combined
castor qa:prepare-pr # Prepare code for PR (fix + analyze)
castor qa:all # Run all QA checks
# Utilities
castor qa:install # Install composer dependencies
castor qa:update-image # Update PHPQA Docker image
castor qa:exec [command] # Execute custom QA commandFor application projects:
castor app:console [command] # Run Symfony console commandsCreate this file in your project root to customize behavior:
<?php
return [
// Project type: library, bundle, or application
'type' => 'library',
// PHP version for Docker (default: current PHP version)
'php_version' => '8.4',
// Source directories to analyze
'source_dirs' => ['src', 'tests'],
// Enable/disable specific features
'check_licenses' => true,
'infection_enabled' => true,
'deptrac_enabled' => true,
'js_enabled' => false,
'docker_enabled' => true,
// Symfony console path (for applications)
'console_path' => 'bin/console',
// Allowed licenses
'allowed_licenses' => [
'Apache-2.0',
'BSD-2-Clause',
'BSD-3-Clause',
'ISC',
'MIT',
'MPL-2.0',
'OSL-3.0',
],
];Note: This file is optional. If not present, sensible defaults are used.
For a Library/Bundle:
<?php
return [
'type' => 'library',
'check_licenses' => true,
'infection_enabled' => true,
'deptrac_enabled' => true,
];For an Application:
<?php
return [
'type' => 'application',
'check_licenses' => false,
'infection_enabled' => false,
'js_enabled' => true,
'console_path' => 'bin/console',
];Create .github/workflows/ci.yml:
For a Library:
name: PHP CI
on:
push:
branches: ['*.x']
tags: ['*']
pull_request: ~
workflow_dispatch: ~
jobs:
ci:
uses: Spomky-Labs/phpqa/.github/workflows/reusable-ci.yml@main
with:
project_type: 'library'
php_versions: '["8.2", "8.3", "8.4"]'
experimental_php_versions: '["8.5"]'
enable_infection: true
enable_deptrac: true
enable_license_check: trueFor an Application:
name: PHP CI
on:
push:
branches: ['main', 'develop']
tags: ['*']
pull_request: ~
jobs:
ci:
uses: Spomky-Labs/phpqa/.github/workflows/reusable-ci.yml@main
with:
project_type: 'application'
php_versions: '["8.4"]'
enable_lowest_deps: false
enable_infection: false
enable_license_check: false
enable_js_tests: true| Parameter | Default | Description |
|---|---|---|
project_type |
'library' |
Project type (library/bundle/application) |
php_versions |
'["8.2","8.3","8.4"]' |
PHP versions to test |
experimental_php_versions |
'["8.5"]' |
Experimental PHP versions |
default_php_version |
'8.4' |
PHP version for QA checks |
enable_lowest_deps |
true |
Test with lowest dependencies |
enable_infection |
true |
Enable mutation testing |
enable_deptrac |
true |
Enable architecture checks |
enable_license_check |
true |
Enable license validation |
enable_js_tests |
false |
Enable JavaScript tests |
# Before committing
castor qa:prepare-pr
# Quick checks
castor qa:lint
castor qa:phpstan
# Run tests
castor qa:phpunit# Auto-fix code style
castor qa:ecs-fix
# Apply refactorings
castor qa:rector-fix
# Re-run checks
castor qa:all# One command to prepare everything
castor qa:prepare-pr
# This runs:
# - ecs-fix (auto-fix code style)
# - rector-fix (apply refactorings)
# - phpstan-baseline (update baseline)
# - deptrac (check architecture)
# - lint (syntax check)# Run all checks locally (like CI)
castor qa:allYou can use different PHPQA versions by changing the $targetVersion in your castor.php:
// Latest version (default)
$targetVersion = 'main';
// Specific tagged version
$targetVersion = 'v1.0.0';
// Development branch
$targetVersion = 'develop';After changing the version, delete the cache to download the new version:
rm -rf .castor-cache/
castor listYou can add your own tasks after the PHPQA import in castor.php:
<?php
use function Castor\import;
use function Castor\io;
// PHPQA auto-download code...
import($phpqaFile);
// Your custom tasks below:
use Castor\Attribute\AsTask;
use function Castor\run;
#[AsTask(description: 'My custom task')]
function my_task(): void
{
io()->title('Running my custom task');
run(['echo', 'Hello from my task!']);
}For applications, add Docker management tasks:
#[AsTask(description: 'Start Docker containers')]
function start(): void
{
run(['docker', 'compose', 'up', '-d']);
}
#[AsTask(description: 'Stop Docker containers')]
function stop(): void
{
run(['docker', 'compose', 'down']);
}See examples/castor-application.php for a complete example.
Solution 1: Check internet connection
curl https://raw.githubusercontent.com/Spomky-Labs/phpqa/main/.castor/phpqa.phpSolution 2: Use cached version
If you've downloaded before, the cache will be used automatically even without internet.
Solution 3: Manual download
mkdir -p .castor-cache
curl -o .castor-cache/phpqa.php \
https://raw.githubusercontent.com/Spomky-Labs/phpqa/main/.castor/phpqa.phpCheck cache files exist and have correct permissions:
ls -la .castor-cache/
stat .castor-cache/phpqa.php# Delete entire cache
rm -rf .castor-cache/
# Or just the version marker
rm .castor-cache/phpqa.version
# Then run castor again
castor listInstall Castor:
# Via Composer
composer global require castor/castor
# Or download binary from
# https://github.com/jolicode/castor/releasesComplete examples are available in the examples/ directory:
castor-simple.php- Minimal setup (just PHPQA tasks)castor-library.php- For PHP libraries/bundlescastor-application.php- For applications with Docker tasks.phpqa-config-library.php- Library configuration example.phpqa-config-application.php- Application configuration exampleci-library.yml- GitHub Actions for librariesci-application.yml- GitHub Actions for applications
When migrating an existing project:
- Run
./scripts/migrate-project.sh /path/to/project type - Verify
.phpqa-config.phpwas created - Verify
castor.phpcontains GitHub download code - Verify
.castor-cache/is in.gitignore - Test:
castor list - Test:
castor qa:lint - Test:
castor qa:phpstan - Test:
castor qa:all - Review
castor.php.backupfor custom tasks - Copy any custom tasks to new
castor.php - Review
.github/workflows/ci.yml - Commit changes
- Push and verify CI passes
- Delete
castor.php.backuponce validated
- Read INTEGRATION.md for detailed integration guide
- Read ARCHITECTURE.md for technical details
- Check examples/ for ready-to-use templates
- See SUMMARY.md for complete overview
You now have:
- ✅ PHPQA tasks automatically downloaded from GitHub
- ✅ Minimal configuration in your project
- ✅ All QA commands available via Castor
- ✅ Reusable GitHub Actions workflow
- ✅ Works anywhere, no path dependencies
Start using it:
castor qa:allHappy coding! 🚀