Follow-up to #178. Setup PHP still installs PHP on every job, and on these arm64 runners the 8.3 path goes through apt/ondrej — a ~145s floor against ~35s for 8.1/8.2, with a tail that has twice crossed into hard failure. The .deb caching added in ci.yml softens it but does not remove the apt step, and PHP 8.5 has the same shape of problem.
Proposal
Stop installing PHP at job time. Build a small CI image per PHP version, push it to the Gitea container registry, and run the jobs with container: so PHP, Composer and the CLI tools are already in place when the job starts.
.gitea/ci/Dockerfile — php:<version>-cli-alpine plus bash, git, nodejs, jq, zip/unzip, GNU coreutils, the intl and zip extensions, and Composer 2.
.gitea/workflows/ci-images.yml — matrix build over the PHP versions CI uses, pushing git.unsupervised.ca/unsupervised/ci-php:<version>. Runs on workflow_dispatch and when the Dockerfile changes.
ci.yml and release.yml switch to container: and drop the Keep downloaded .debs / Cache apt packages blocks.
nodejs and bash are in the image because act_runner executes JavaScript actions (actions/checkout, actions/cache, actions/upload-artifact) inside the job container, not on the host.
Why not php-actions/composer
It only runs Composer, inside its own throwaway container — it never puts PHP on the runner, so composer cs / composer lint / composer test / composer build would each need a separate Docker-in-Docker action. Its php-build.bash also does an unconditional docker login docker.pkg.github.com under set -e, which a Gitea token cannot satisfy, and it caches its built image on GitHub Packages, so on Gitea it would rebuild from scratch every job.
Sequencing
Two changes, in order, because the workflows cannot reference images that do not exist yet:
Add the Dockerfile and the image-build workflow; merge; let it publish the images.
Switch ci.yml and release.yml over to container:.
Done when
git.unsupervised.ca/unsupervised/ci-php:{8.1,8.2,8.3,8.5} exist and pull anonymously.
No workflow references shivammathur/setup-php.
A full CI run is green with no apt work in any job.
Follow-up to #178. `Setup PHP` still installs PHP on every job, and on these arm64 runners the 8.3 path goes through apt/ondrej — a ~145s floor against ~35s for 8.1/8.2, with a tail that has twice crossed into hard failure. The `.deb` caching added in ci.yml softens it but does not remove the apt step, and PHP 8.5 has the same shape of problem.
## Proposal
Stop installing PHP at job time. Build a small CI image per PHP version, push it to the Gitea container registry, and run the jobs with `container:` so PHP, Composer and the CLI tools are already in place when the job starts.
- `.gitea/ci/Dockerfile` — `php:<version>-cli-alpine` plus `bash`, `git`, `nodejs`, `jq`, `zip`/`unzip`, GNU coreutils, the `intl` and `zip` extensions, and Composer 2.
- `.gitea/workflows/ci-images.yml` — matrix build over the PHP versions CI uses, pushing `git.unsupervised.ca/unsupervised/ci-php:<version>`. Runs on `workflow_dispatch` and when the Dockerfile changes.
- `ci.yml` and `release.yml` switch to `container:` and drop the `Keep downloaded .debs` / `Cache apt packages` blocks.
`nodejs` and `bash` are in the image because act_runner executes JavaScript actions (`actions/checkout`, `actions/cache`, `actions/upload-artifact`) inside the job container, not on the host.
## Why not php-actions/composer
It only runs Composer, inside its own throwaway container — it never puts PHP on the runner, so `composer cs` / `composer lint` / `composer test` / `composer build` would each need a separate Docker-in-Docker action. Its `php-build.bash` also does an unconditional `docker login docker.pkg.github.com` under `set -e`, which a Gitea token cannot satisfy, and it caches its built image on GitHub Packages, so on Gitea it would rebuild from scratch every job.
## Sequencing
Two changes, in order, because the workflows cannot reference images that do not exist yet:
1. Add the Dockerfile and the image-build workflow; merge; let it publish the images.
2. Switch `ci.yml` and `release.yml` over to `container:`.
## Done when
- `git.unsupervised.ca/unsupervised/ci-php:{8.1,8.2,8.3,8.5}` exist and pull anonymously.
- No workflow references `shivammathur/setup-php`.
- A full CI run is green with no apt work in any job.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Follow-up to #178.
Setup PHPstill installs PHP on every job, and on these arm64 runners the 8.3 path goes through apt/ondrej — a ~145s floor against ~35s for 8.1/8.2, with a tail that has twice crossed into hard failure. The.debcaching added in ci.yml softens it but does not remove the apt step, and PHP 8.5 has the same shape of problem.Proposal
Stop installing PHP at job time. Build a small CI image per PHP version, push it to the Gitea container registry, and run the jobs with
container:so PHP, Composer and the CLI tools are already in place when the job starts..gitea/ci/Dockerfile—php:<version>-cli-alpineplusbash,git,nodejs,jq,zip/unzip, GNU coreutils, theintlandzipextensions, and Composer 2..gitea/workflows/ci-images.yml— matrix build over the PHP versions CI uses, pushinggit.unsupervised.ca/unsupervised/ci-php:<version>. Runs onworkflow_dispatchand when the Dockerfile changes.ci.ymlandrelease.ymlswitch tocontainer:and drop theKeep downloaded .debs/Cache apt packagesblocks.nodejsandbashare in the image because act_runner executes JavaScript actions (actions/checkout,actions/cache,actions/upload-artifact) inside the job container, not on the host.Why not php-actions/composer
It only runs Composer, inside its own throwaway container — it never puts PHP on the runner, so
composer cs/composer lint/composer test/composer buildwould each need a separate Docker-in-Docker action. Itsphp-build.bashalso does an unconditionaldocker login docker.pkg.github.comunderset -e, which a Gitea token cannot satisfy, and it caches its built image on GitHub Packages, so on Gitea it would rebuild from scratch every job.Sequencing
Two changes, in order, because the workflows cannot reference images that do not exist yet:
ci.ymlandrelease.ymlover tocontainer:.Done when
git.unsupervised.ca/unsupervised/ci-php:{8.1,8.2,8.3,8.5}exist and pull anonymously.shivammathur/setup-php.