feat(testsuite): phpup test subcommand + ci-cell / ci make targets (PR 3/6)#58
Merged
Conversation
….yaml internal/testsuite.Load parses the YAML into typed Fixture structs. Filter(os, arch, php) returns matching fixtures using: - exact PHP-version match - arch normalization (amd64/x86_64 and arm64/aarch64 equivalent) - OS aliasing (jammy <-> ubuntu-22.04, noble <-> ubuntu-24.04) - RunnerOS-unset fixtures match any OS (bulk of the fixtures) Foundation for PR 3 Task 2's phpup test outer subcommand which iterates (os x arch x php) cells and passes filtered fixtures into each container.
phpup test [--registry oci-layout:./out/oci-layout] [--os jammy,noble] [--arch x86_64,aarch64] --php 8.1,8.2,... [--fixtures test/compat/fixtures.yaml] [--repo .] [--parallel 1] [--cache ./.cache/phpup-test] Expands the (os x arch x php) cartesian product, and for each cell with matching fixtures spawns a single bare-ubuntu:<os> container via internal/build.DockerRun with: - the oci-layout directory mounted read-only at /registry, - the self phpup binary mounted at /usr/local/bin/phpup, - the repo's test/compat dir mounted at /test-compat, - PHPUP_REGISTRY=oci-layout:/registry in the env. Inside the container, phpup internal test-cell will iterate the filtered fixtures and invoke phpup install + probe.sh per fixture. That runner lives in the next commit (Task 3); for now the subcommand is a stub that errors cleanly so dispatch compiles end-to-end. cmd/phpup/main.go dispatches test and internal at the top of main() alongside the existing build dispatch. internal/build's ubuntuImage / dockerPlatform are exported (renamed UbuntuImage / DockerPlatform) so the testsuite package can reuse them without duplicating the OS/arch mappings.
Replaces the PR 3 Task 2 stub. Runs INSIDE the bare-ubuntu container
spawned by phpup test:
phpup internal test-cell --os jammy --arch x86_64 --php 8.4 \
--fixtures /test-compat/fixtures.yaml \
--probe /test-compat/probe.sh \
--registry oci-layout:/registry
For each fixture matching the (os, arch, php) cell:
1. Snapshot os.Environ() + PATH + per-fixture ini keys to tempdir.
2. Run `phpup install` as a child process with fixture-derived
env (INPUT_PHP-VERSION, INPUT_EXTENSIONS, INPUT_INI-VALUES,
INPUT_COVERAGE, INPUT_INI-FILE, PHPUP_REGISTRY).
3. Invoke test/compat/probe.sh (via bash, so exec bit isn't
required across mount boundaries) to snapshot post-install
env as JSON.
4. Assert invariants: php_version prefix matches, requested
extensions loaded (case-insensitive), requested ini values
match, excluded extensions (":opcache" etc.) NOT loaded.
InstallFunc is swappable via SetInstaller() same pattern as
internal/build.SetRunner — unit tests substitute a fake and a
synthetic probe script to exercise orchestration without real PHP.
…i.sh Makefile gains two targets wrapping `phpup test`: - `make ci-cell OS=... ARCH=... PHP=...` — run one cell - `make ci` — iterate jammy+noble x x86_64+aarch64 x PHP 8.1-8.5 test/smoke/local-ci.sh is now a thin forwarding shim that calls `make ci-cell` for the requested arch+php on both jammy and noble. The 270-line docker + oras orchestration it used to do now lives in internal/testsuite + phpup test (Go). The shim is deliberately tolerant of unknown args during the deprecation window so in-tree callers that may have extra flags don't break outright; a NOTE message points to the replacement. Part of PR 3 of the local+CI unification rollout. Fully cutting over compat-harness.yml to phpup test is PR 4's scope.
…orks phpup test mounted os.Executable() as /usr/local/bin/phpup inside the bare-ubuntu container. On a macOS host (darwin/arm64) that binary fails the container's linux exec format; on a linux/amd64 host running an aarch64 cell it fails the same way. Fix: add --self-binary <path> flag that overrides the default os.Executable(). Makefile's ci-cell target picks bin/phpup-linux-amd64 or bin/phpup-linux-arm64 based on ARCH and threads the absolute path via --self-binary. Two new make targets cross-compile via GOOS=linux GOARCH=<arch> go build. Caught by make check's local-ci smoke failing with "exec /usr/local/bin/phpup: exec format error".
…ARCH
Two corrections landing together:
1. test/smoke/local-ci.sh reverted to its pre-PR-3 shell-orchestrated
body (GHCR pull via oras + bash docker loops). The deprecation
shim that forwarded to `make ci-cell` / phpup test was premature:
phpup install inside a bare ubuntu:22.04 container without
pre-populated bundles hits sudo/apt + missing-lockfile-entry
failures that are genuine PR 4 scope. A NOTE at the top of the
script points users at the future path. Script re-enters full
service so `make check` stays green.
2. internal/testsuite.composeInstallEnv now injects RUNNER_OS=Linux
and RUNNER_ARCH={X64|ARM64} mapped from the cell's arch. Without
them, plan.FromEnv builds malformed lockfile keys like
`php:8.4:://nts` and resolve fails. Unit test covers both arches.
make ci-cell + make ci remain in place as opt-in future paths;
PR 4's unified ci.yml will swap local-ci.sh over when bundles
are reliably pre-populated in the workflow.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR 3 of 6 in the local+CI unification rollout (spec).
Adds a new
phpup testouter subcommand +phpup internal test-cellinner runner that together consolidate the per-fixture test loop that today lives split betweentest/smoke/local-ci.sh(local dev) andcompat-harness.yml's shell steps (CI). Fixtures continue to live intest/compat/fixtures.yaml;test/compat/probe.shis reused unchanged.Changes
internal/testsuite/fixtures.go— typedFixture/FixtureSetstructs,Load(path),Filter(os, arch, php)selector with arch aliasing (amd64↔x86_64, arm64↔aarch64) and OS aliasing (jammy↔ubuntu-22.04, noble↔ubuntu-24.04). Realtest/compat/fixtures.yamlparses to 70 fixtures.internal/testsuite/runner.go— outer orchestrator. Expands--os,--arch,--phpinto the (os×arch×php) cartesian product; for each cell with matching fixtures, spawns a bare-ubuntu:<os>container viainternal/build.DockerRunwith (a) the oci-layout mounted at/registry, (b) a Linux-architecturephpupbinary mounted at/usr/local/bin/phpup, (c)test/compat/mounted at/test-compat. Aggregates per-cell outcomes; exits non-zero on any failure.internal/testsuite/testcell.go— inner runner. For each matching fixture: snapshots env + PATH + ini-keys, runsphpup installas a child process (via swappableInstallFunc— same pattern asinternal/build.SetRunner), invokesprobe.sh, parses the JSON, asserts invariants (php_version prefix, requested extensions loaded case-insensitively, excluded extensions absent, ini values match).--self-binaryflag — lets callers specify a linux-architecture binary for the in-container mount. Defaults toos.Executable()(correct when host arch == cell arch). Fixes the macOS-cross-architecture case that surfaced in the finalmake check.bin/phpup-linux-amd64/bin/phpup-linux-arm64cross-compile targets;make ci-cell OS=… ARCH=… PHP=…wrapsphpup testfor one cell;make ciiterates jammy+noble × x86_64+aarch64 × PHP 8.1-8.5.test/smoke/local-ci.sh— unchanged body (PR 3's original intent was a deprecation shim, but the new path needs pre-populated bundles + sudo/apt in the base container that PR 4's unifiedci.ymlwill wire; see scope note below). A NOTE comment prefix points readers at the replacement.cmd/phpup/main.godispatchEarly
os.Args[1] == "test"andos.Args[1] == "internal"routes added alongside PR 2'sbuilddispatch.phpup --version,phpup install,phpup build php|extunchanged.Test plan
go test ./internal/testsuite/... -v -count=1— 32 tests, all pass, coverage 84.8%.go build ./...— all 6cmd/binaries compile. Cross-compiledbin/phpup-linux-{amd64,arm64}verified as ELF aarch64 / x86-64.make checkgreen end-to-end including docker-backedlocal-cismoke on jammy + noble × amd64 + arm64 × hard4 extensions.phpup testerrors on missing--php;phpup internal test-cellwith 7.99 (no match) prints "no matching fixtures" and exits 0.Explicitly deferred to PR 4
The ambitious scope of
test/smoke/local-ci.shbecoming a deprecation shim forwarding tophpup testgot pulled back during final verification. Root cause:phpup installinside a bareubuntu:22.04container without pre-populatedout/oci-layout/bundles hits three cascading gaps — missing bundles in the layout, missingsudo/apttooling in bare-ubuntu, and theRUNNER_OS/RUNNER_ARCHenv wiring I did fix here. Items 1 and 2 are genuine PR 4 scope (the unifiedci.ymlpre-populates the layout viaphpup buildand/or uses a container base that includes the needed tooling). So:make ci-cellandmake ciare landed as opt-in future paths. They work end-to-end against a pre-populatedout/oci-layout/— which PR 4'sci.ymlwill produce.test/smoke/local-ci.shretains its self-contained shell-orchestrated body (GHCR pull via oras + bash loops) somake check/make local-cistay green. A NOTE comment points at the replacement.compat-harness.ymluntouched — still running on the old shell-orchestrated path in parallel. Full cutover is PR 4's scope per the spec.Notes
//nolint:gosecsites onexec.CommandContextintestcell.go(G204 false positives — self-binary + fixed argv). Rationale comments inline match the pattern Task 3 of PR 2 established.internal/build.ubuntuImageanddockerPlatformexported (PascalCase rename) so the testsuite package reuses them without duplicating the OS/arch mapping tables.