ebb835d541 raised phpunit/phpunit from ^11.0 to ^13.3. PHPUnit 13 requires
PHP >=8.4.1 and ubuntu-latest ships 8.3.6, so composer install could not
resolve and test-unit-php failed on every CI run:
- phpunit/phpunit[13.3.0, ..., 13.3.2] require php >=8.4.1
-> your php version (8.3.6) does not satisfy that requirement.
Nothing in this repository installs a particular PHP. ensure_php_toolchain
takes whatever the distro php package is, so the vendor tree was resolved
against an ambient interpreter that no file named. A dependency floor above
that interpreter is then only discovered by the resolver, on the machine that
happens to have the oldest PHP.
Declare the floor and resolve against it. config.platform.php binds composer
everywhere, including Dependabot; require states the same for readers; the
phpunit constraint follows it. Packagist floors: 11 -> >=8.2, 12 -> >=8.3,
13 -> >=8.4.1.
Verified in the dev container: the pinned resolution downgrades phpunit
13.3.2 -> 12.5.34 and the suite passes unchanged, 26 tests, 56 assertions.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adopts infinito-nexus/core#568. The composer.json hunk is byte-identical to that PR; vendor/ and composer.lock are gitignored, so it is the only file the PR touches.
The docstring in utils/install/php.py names the constraint verbatim and would have gone stale, which dependabot cannot see.
Verified rather than assumed: phpunit 13.3.2 requires php >=8.4.1 where 11.x asked for >=8.2, and the project container runs 8.4.24. A partial update fails because the lock pins the transitive packages, so resolving needs -W, which carries fourteen packages along including php-code-coverage 11.0.12 to 14.3.2. The suite then runs green under the new major: 26 tests, 56 assertions, no deprecation and no warning, with phpunit.xml setting failOnWarning and failOnRisky.
Open: ensure_php_toolchain takes whatever php the distro ships and states no minimum, so a matrix row on php below 8.4.1 breaks at composer install rather than at a named check.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Without a zip extension or an unzip/7z binary Composer silently drops to
--prefer-source and mirror-clones every dependency, which exceeds its
300 s process timeout on phpunit.git. That took the Arch workspace job
from a 2m16s test-unit to a 16m08s failure. Debian never saw it because
apt pulls php-zip and unzip in as Composer dependencies; pacman does not.
Arch ships no zip extension and no php-zip package, so the extractor has
to be the unzip binary rather than the extension. Its mapping already
covers all five package managers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ensure_php_toolchain installed the php and composer binaries and stopped
there. A distro ships the interpreter and its extensions as separate
packages, and ensure_command_present returns early once shutil.which
finds php - which it always does since the image bakes the interpreter -
so the extensions were never provisioned on any path.
composer then refused to resolve the vendor tree with
"phpunit/phpunit requires ext-dom * -> it is missing from your system"
and test-unit-php failed in every workspace job. The loaded ini list in
those logs shows 20-mbstring.ini present and no 20-dom.ini, 20-xml.ini
or 20-xmlwriter.ini, i.e. php-xml missing.
Extensions are now probed against php -m and installed from a per-manager
mapping, then re-probed so a package that does not deliver the extension
raises instead of leaving composer to fail later. The loop sits in
ensure_php_toolchain because both entry points pass through it: the image
build via utils.install.interpreters and the test run via
scripts/install/php.sh, so a prebuilt image is repaired at test time.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The unit suites had to install their toolchain on every run. The image
now carries the interpreters, so the make prerequisite finds them present.
The Composer vendor tree deliberately stays out of the image build: the
package cache is reached through the compose extra_hosts mapping, which
only exists for a running container, so a build-time composer install
would bypass the cache and talk to packagist directly. Fetching it from
the test target keeps it on the cached path.
test-unit-php and test-unit-ruby exited 0 whenever the interpreter or the
vendor tree was missing, so both suites were silently absent from every
gate. They now provision their toolchain through install-php/install-ruby
and fail loudly when that is impossible.
The three ensure_*_present helpers collapse into ensure_command_present
in system_pkg, and the ruby runner rejects an empty suite because
minitest reports success when nothing was required.