Skip to content

Latest commit

 

History

History
383 lines (294 loc) · 10.3 KB

File metadata and controls

383 lines (294 loc) · 10.3 KB

PHPQA Centralized System - Summary

🎯 Overview

A centralized quality assurance system for PHP projects that:

  • Downloads PHPQA tasks automatically from GitHub
  • Uses reusable Castor tasks across all projects
  • Provides reusable GitHub Actions workflows
  • Requires minimal configuration per project
  • Works anywhere, no path dependencies

✨ What Was Created

Core System

  1. .castor/phpqa.php - All reusable QA tasks (PHPUnit, PHPStan, ECS, Rector, etc.)
  2. .github/workflows/reusable-ci.yml - Reusable GitHub Actions workflow
  3. scripts/migrate-project.sh - Automatic project migration script
  4. examples/ - Ready-to-use templates for different project types

Documentation

  • GETTING-STARTED.md - Quick start guide
  • INTEGRATION.md - Detailed integration guide
  • ARCHITECTURE.md - Technical architecture documentation
  • CHANGELOG.md - Change history
  • SUMMARY.md - This file

🚀 Key Feature: GitHub Auto-Download

Instead of using relative paths, projects now download PHPQA tasks from GitHub:

// castor.php (~40 lines total)
<?php
use function Castor\import;
use function Castor\io;

$phpqaFile = __DIR__ . '/.castor-cache/phpqa.php';
$phpqaUrl = 'https://raw.githubusercontent.com/Spomky-Labs/phpqa/main/.castor/phpqa.php';

$cacheDir = __DIR__ . '/.castor-cache';
if (!is_dir($cacheDir) && !mkdir($cacheDir, 0755, true) && !is_dir($cacheDir)) {
    throw new \RuntimeException(sprintf('Directory "%s" was not created', $cacheDir));
}

if (!file_exists($phpqaFile)) {
    io()->note('Downloading PHPQA tasks...');
    file_put_contents($phpqaFile, file_get_contents($phpqaUrl));
}

import($phpqaFile);

Benefits:

  • ✅ No path dependencies
  • ✅ Works anywhere
  • ✅ Local cache (.castor-cache/)
  • ✅ Works offline after first download
  • ✅ Easy updates (delete cache to refresh)

📁 Project Structure

your-project/
├── .castor-cache/          # Cache (gitignored)
│   ├── phpqa.php          # Downloaded from GitHub
│   └── phpqa.version      # Cached version
├── .phpqa-config.php      # Configuration (optional)
├── castor.php             # ~40 lines with GitHub download
├── .gitignore             # Contains: .castor-cache/
└── .github/
    └── workflows/
        └── ci.yml         # Reusable workflow

🎯 Quick Start

Automatic Migration (Recommended)

cd ~/Projects/phpqa

# For a library/bundle
./scripts/migrate-project.sh ~/Projects/your-project library

# For an application
./scripts/migrate-project.sh ~/Projects/your-app application

This creates:

  • castor.php with GitHub auto-download
  • .phpqa-config.php configured for project type
  • .github/workflows/ci.yml ready to use
  • .gitignore with .castor-cache/

Manual Setup

# Copy an example
cp examples/castor-simple.php your-project/castor.php

# Optional: add configuration
cp examples/.phpqa-config-library.php your-project/.phpqa-config.php

# Run
cd your-project
castor qa:all

📋 Available Commands

All commands in qa: namespace:

castor qa:phpunit           # Tests with coverage
castor qa:phpstan           # Static analysis
castor qa:phpstan-baseline  # Generate PHPStan baseline
castor qa:ecs               # Check coding standards
castor qa:ecs-fix           # Fix coding standards
castor qa:rector            # Check refactoring
castor qa:rector-fix        # Apply refactoring
castor qa:deptrac           # Validate architecture
castor qa:lint              # Check PHP syntax
castor qa:infect            # Mutation testing
castor qa:validate          # Validate composer.json
castor qa:check-licenses    # Check license compatibility
castor qa:js                # JavaScript tests
castor qa:prepare-pr        # Prepare code for PR
castor qa:all               # Run all checks
castor qa:install           # Install dependencies
castor qa:update-image      # Update PHPQA Docker image

For applications:

castor app:console [command]  # Run Symfony console commands

📊 Before/After Comparison

Before (Duplicated)

webauthn-framework/
├── castor.php              # 409 lines
└── .github/workflows/ci.yml # 245 lines

jwt-framework/
├── castor.php              # 322 lines
└── .github/workflows/ci.yml # 240 lines

cbor-bundle/
├── castor.php              # 252 lines
└── .github/workflows/ci.yml # 240 lines

Total: ~1700 lines duplicated

After (Centralized)

phpqa/
├── .castor/phpqa.php           # 370 lines
└── .github/workflows/reusable-ci.yml  # 290 lines

each-project/
├── .phpqa-config.php           # 10 lines (optional)
├── castor.php                  # 40 lines (auto-download)
└── .github/workflows/ci.yml    # 15 lines (parameters)

Per project: ~50 lines (vs ~650 before)
Reduction: 92% less code per project

🔧 Configuration

Optional .phpqa-config.php

<?php
return [
    'type' => 'library',  // library, bundle, application
    'php_version' => '8.4',
    'source_dirs' => ['src', 'tests'],
    'check_licenses' => true,
    'infection_enabled' => true,
    'deptrac_enabled' => true,
    'js_enabled' => false,
    'docker_enabled' => true,
    'console_path' => 'bin/console',
];

GitHub Actions Parameters

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: true
      enable_js_tests: false

🌐 Versioning

Use different versions/branches:

// Latest version (default)
$targetVersion = 'main';

// Specific tagged version
$targetVersion = 'v1.0.0';

// Development branch
$targetVersion = 'develop';

Change $targetVersion in castor.php and delete .castor-cache/ to switch versions.

📦 Examples

Ready-to-use templates in examples/:

  • castor-simple.php - Minimal version
  • castor-library.php - For libraries/bundles
  • castor-application.php - For applications with Docker tasks
  • .phpqa-config-library.php - Library configuration
  • .phpqa-config-application.php - Application configuration
  • ci-library.yml - GitHub Actions for libraries
  • ci-application.yml - GitHub Actions for applications

🐛 Error Handling

The system is robust:

if ($content !== false) {
    // Download successful
    file_put_contents($phpqaFile, $content);
} elseif (!file_exists($phpqaFile)) {
    // No cache and no internet → error
    io()->error('Failed to download');
    exit(1);
} else {
    // Use existing cache
    io()->warning('Using cached version');
}

Result:

  • ✅ With internet → downloads latest version
  • ✅ Without internet → uses cache
  • ❌ Fails only if: no internet AND no cache

✅ Benefits

Centralization

  • Single source of truth for QA tasks
  • Updates benefit all projects immediately
  • Guaranteed consistency

Simplicity

  • Minimal configuration per project
  • Optional configuration with smart defaults
  • No code duplication

Flexibility

  • Support for different project types
  • Customizable per project
  • Project-specific tasks still possible

Portability

  • Works anywhere, no path dependencies
  • No need to clone phpqa repository
  • Works on any machine

Performance

  • Local cache after first download
  • Parallel GitHub Actions jobs
  • Docker image reuse

📚 Documentation

  • GETTING-STARTED.md - Quick start and common workflows
  • INTEGRATION.md - Detailed integration guide
  • ARCHITECTURE.md - Technical architecture and design
  • CHANGELOG.md - Version history
  • examples/README.md - Examples documentation

🎯 Migration Checklist

For each project:

  • Run migration script
  • Verify created files
  • Test castor list
  • Test castor qa:lint
  • Test castor qa:phpstan
  • Test castor qa:all
  • Copy custom tasks if needed
  • Customize .phpqa-config.php if needed
  • Adjust GitHub Actions workflow if needed
  • Commit and push
  • Verify CI passes on GitHub
  • Delete castor.php.backup once validated

🚀 Next Steps

  1. Test with a pilot project (e.g., a simple bundle)
  2. Validate everything works
  3. Migrate other projects
  4. Enjoy the centralized system!

🎉 Results

You now have:

✅ A centralized QA system for all your PHP projects ✅ Simplified maintenance (single place to update) ✅ Guaranteed consistency across projects ✅ Automatic download from GitHub ✅ Local caching for performance ✅ Works anywhere, no dependencies ✅ Comprehensive documentation

Time saved: 80-90% reduction in QA configuration maintenance

🔧 Docker Image Improvements (Dec 2024)

Issues Fixed

Issue 1: Cache Extraction Permissions

  • Problem: tar failed with "Cannot utime: Operation not permitted" when GitHub Actions tried to restore caches
  • Root Cause: /tools directory owned by root, but container runs as user 1001
  • Fix: Added proper ownership in Dockerfile:116-117

Issue 2: Symfony Panther/BrowserKit Incompatibility

  • Problem: Fatal error with Panther and BrowserKit 8.0 causing persistent build failures
  • Root Cause: Panther had ongoing compatibility issues with newer Symfony components
  • Fix: Removed Panther entirely from the Docker image (Dockerfile:82)
    • Removed symfony/panther dependency
    • Removed Panther environment configuration
    • Removed GeckoDriver (only needed for Panther)
  • Note: Projects can still install Panther locally as needed

Testing Infrastructure

New automated tests prevent regressions:

  1. tests/test-image.sh - Validates published images (10 comprehensive tests)
  2. tests/test-local-build.sh - Tests local builds before publishing
  3. GitHub Actions CI - Automatic testing after each image build
  4. tests/README.md - Complete testing documentation

Test Coverage:

  • Essential tools verification (tar, git, composer, etc.)
  • PHP version validation
  • Directory permissions (1001:1001)
  • Cache write permissions
  • Tar functionality with timestamp operations
  • PHP extensions availability

Running Tests

# Test published image
./tests/test-image.sh 8.4

# Test local build
./tests/test-local-build.sh 8.4

# Test all versions
for v in 8.2 8.3 8.4; do ./tests/test-image.sh $v; done