# CI CI and release jobs do not install PHP. They run inside the shared images maintained in [Unsupervised/ci-php](https://git.unsupervised.ca/Unsupervised/ci-php): ``` git.unsupervised.ca/unsupervised/ci-php:8.1 git.unsupervised.ca/unsupervised/ci-php:8.2 git.unsupervised.ca/unsupervised/ci-php:8.3 git.unsupervised.ca/unsupervised/ci-php:8.5 ``` The `Unsupervised` org is public, so they pull anonymously — no registry credentials in any job here. What the images contain, how they are published, and how to add a PHP version are documented in that repository's README. ## Which job runs where | Job | Runs in | |---|---| | Coding Standards (PHPCS) | `ci-php:8.3` | | Static Analysis (PHPStan) | `ci-php:8.3` | | Tests | `ci-php:${{ matrix.php }}` | | Build Plugin Zip | `ci-php:8.3` | | No Debug Code | runner image — no PHP, and it uses GNU `grep --include` | | Open next-version bump PR (release.yml) | runner image — no PHP | PHPCS and PHPStan are separate jobs so a coding-standards failure still lets the static analysis result through. They run in parallel. ## Composer `composer.lock` is committed, so every job installs the same dependency set and two builds of the same tag ship the same vendor tree. `bin/build-zip.sh` stages the lock into its build directory for the same reason, then removes it before writing the zip. The Composer download cache lives at `/composer/cache` — `COMPOSER_HOME` is `/composer` in the image — and is keyed on `composer.lock`. ## Adding a PHP version to the test matrix The image has to exist first. Add the version to the `php` matrix in `ci-php`'s `.gitea/workflows/publish.yml` and merge, then add it to the `test` matrix in `.gitea/workflows/ci.yml` here.