name: CI # Quality gate: runs on every push and pull request. # Tests run via the committed PHAR (tools/.bin/phpunit.phar). Class loading uses # the committed Composer PSR-4 autoloader (src/vendor/) first, with the legacy # src/autoload.php scanner as an end-of-queue fallback. The deploy path ships # vendor/ as-is and never runs `composer install`. on: push: branches: ['**'] pull_request: permissions: contents: read jobs: lint: name: PHP Syntax Check runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' coverage: none - name: Check syntax run: bash tools/php_syntax_check.sh phpstan: name: PHPStan (static analysis) runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 - name: Setup PHP uses: shivammathur/setup-php@v2 with: # Matches phpVersion (80300) the analysis targets. php-version: '8.3' coverage: none # Downloads the pinned PHPStan PHAR (no Composer) and analyses against the # committed baseline — fails only on NEW issues introduced by the change. - name: Run PHPStan run: make phpstan composer-audit: name: Composer Security Audit runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' coverage: none tools: composer:v2 # Reads src/composer.lock and checks the dependency graph against the # Packagist advisory database. Does NOT run `composer install` (vendor/ # is committed). A no-op while every dependency is path-mapped/vendored, # but gates real `require` packages the moment any are added. - name: Composer audit run: composer audit --no-interaction --working-dir=src test: name: PHPUnit runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' coverage: pcov - name: Run unit tests run: php tools/.bin/phpunit.phar -c tests/phpunit.xml.dist - name: Coverage report run: | php tools/.bin/phpunit.phar -c tests/phpunit.xml.dist \ --coverage-text \ --coverage-clover coverage.xml continue-on-error: true - name: Upload coverage artifact if: always() uses: actions/upload-artifact@v7 with: name: coverage path: coverage.xml if-no-files-found: ignore