ci: split integration tests into parallel LLVM and Haskell jobs#993
ci: split integration tests into parallel LLVM and Haskell jobs#993
Conversation
- Phase 1: Add `test-integration-llvm` and `test-integration-haskell` Makefile targets that run the respective test subsets in parallel CI jobs. - Phase 2: Fix redundant llvm-kompile calls in test_exec_smir by replacing function-scoped `tmp_path` with session-scoped fixtures (`kompile_cache_dir`, `exec_smir_kompile_dirs`) so KompileDigest caching hits for repeated (smir_json, symbolic) combinations within a test session. A file-lock guards against concurrent pytest-xdist workers racing on the same dir. - Phase 3: Add a shared `build` CI job that runs `make stable-mir-json` + `make build` once and commits the result as a Docker image; downstream `integration-tests-llvm` and `integration-tests-haskell` jobs start containers from that image, avoiding a redundant full rebuild per job. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous approach used `docker commit` to save a built image and share it across jobs. This fails because self-hosted runners are separate machines and local Docker images are not shared between them. Switch to having each test job independently run `with-docker` + build, matching the pattern used by other jobs in this workflow. The tests themselves still run in parallel across two separate jobs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Build once in a dedicated job, commit the container image with all kompile artifacts to GHCR, then pull it in the LLVM and Haskell test jobs. This avoids rebuilding stable-mir-json and kdist definitions twice. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5cba7069be
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| docker commit mir-semantics-build-${GITHUB_SHA} ${IMAGE} | ||
| echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin | ||
| docker push ${IMAGE} |
There was a problem hiding this comment.
Avoid pushing images that contain checkout credentials
This job checks out with actions/checkout@v4 using secrets.JENKINS_GITHUB_PAT and then commits/pushes the running container, which already has the copied workspace under /home/github-user/workspace; in v4, checkout persists auth credentials for git commands, so the committed layer can include those credentials (for example via repo git config) and expose them to anyone who can pull ghcr.io/.../ci:<sha>. Avoid committing that workspace as-is (or set persist-credentials: false and scrub .git before docker commit).
Useful? React with 👍 / 👎.
| with open(lock_file, 'x'): | ||
| target.mkdir(parents=True, exist_ok=True) | ||
| exec_smir_kompile_dirs[key] = target | ||
| lock_file.unlink(missing_ok=True) |
There was a problem hiding this comment.
Keep the lock held until kompilation has finished
The lock file is removed immediately after creating the target directory, but the expensive work (KMIR.from_kompiled_kore(...)) happens later in the test, so concurrent xdist workers that hit the same (smir_json, symbolic) key can still enter kompilation at the same time and write into the same target_dir, causing flaky or corrupted integration outputs. The critical section needs to include the actual kompile step, not just directory creation.
Useful? React with 👍 / 👎.
| while lock_file.exists() and secs < 300: | ||
| time.sleep(1) | ||
| secs += 1 | ||
| exec_smir_kompile_dirs[key] = target |
There was a problem hiding this comment.
Raise on lock timeout instead of using a possibly partial dir
When another worker holds the lock longer than 300 seconds, this code still records and returns target even if lock_file still exists, so callers may proceed against a partially built kompile directory and fail nondeterministically. If the timeout is reached, this should error out (or continue waiting) rather than pretending the cache entry is ready.
Useful? React with 👍 / 👎.
Change Proof
Behavior Delta
Before: One
integration-testsCI job ran all integration tests serially in a single Docker container, rebuildingstable-mir-json+kdistdefinitions each time. Everytest_exec_smirparametrization triggered an independentllvm-kompiledue to function-scopedtmp_path.After:
build→integration-tests-llvm|integration-tests-haskell(parallel).buildjob compiles once, commits the container to GHCR (ghcr.io/.../ci:<sha>). Test jobs pull the pre-built image — no duplicatemake stable-mir-json build.test_exec_smirshares kompile output across parametrizations via session-scoped fixtures +KompileDigestcache, eliminating redundantllvm-kompilecalls for the same(smir_json, symbolic)pair.Invariants / Non-goals
make test-integrationstill runs all 341 tests locally (unchanged target).-kexpressions partition tests with 0 overlap, 0 missing (115 LLVM + 226 Haskell = 341).stable-mir-json-integration-tests,test-kmir-image,nixjobs are unchanged.Validation
-kLLVM expression-kHaskell expressionmake checkmake test-integration-llvmlocalmake test-integration-haskelllocalorigin/masterRisk / Blast Radius / Rollback
packages:writepermission denied on PR workflowsdocker pushstep — clear error message. Fallback: revert to per-job independent builds (commit2e30d107).-kexpression drift when new tests are addedopen(lock_file, "x")) with 5-min timeout.Rollback: Revert this PR. No persistent state changes outside CI workflow.
Review Focus
permissions: packages: writeat workflow level + job level) — does the org allow this for PR workflows?-kexpression completeness — verified programmatically (0 missing), but reviewers should confirm the convention is clear for future test additions.conftest.pyfile-lock mechanism — simpleopen(lock_file, "x")+ poll loop. Adequate for pytest-xdist on a single machine; not designed for distributed execution.Architecture Trace
Context (C4-L1)
CI pipeline for the mir-semantics project. Tests run on self-hosted GitHub Actions runners inside Docker containers.
Container (C4-L2)
graph LR B[build job<br/>self-hosted runner] -->|docker commit + push| GHCR[ghcr.io/.../ci:SHA] GHCR -->|docker pull| L[integration-tests-llvm<br/>self-hosted runner] GHCR -->|docker pull| H[integration-tests-haskell<br/>self-hosted runner] B -.->|needs| CQ[code-quality-checks<br/>ubuntu-latest] L -.->|needs| B H -.->|needs| BComponent (C4-L3)
graph TD subgraph "test_exec_smir parametrizations" T1["(smir_A, llvm)"] --> CD1["kompile_cache_dir / hash-A-concrete"] T2["(smir_A, haskell)"] --> CD2["kompile_cache_dir / hash-A-symbolic"] T3["(smir_B, llvm)"] --> CD3["kompile_cache_dir / hash-B-concrete"] end subgraph "KompileDigest cache" CD1 -->|"digest match → skip"| SKIP1[no llvm-kompile] CD1 -->|"digest miss → build"| BUILD1[llvm-kompile] endCode Trace (C4-L4)
.github/workflows/test.ymlintegration-testswithbuild+integration-tests-llvm+integration-tests-haskell. Add GHCR push/pull.Makefiletest-integration-llvmandtest-integration-haskelltargets with-kfilters.kmir/src/tests/integration/conftest.pykompile_cache_dir,exec_smir_kompile_dirsfixtures,get_exec_smir_target_dir()with file-lock.kmir/src/tests/integration/test_integration.pytest_exec_smir: replacetmp_pathwith shared kompile cache fixtures.Decision Record
Decision: Use GHCR to share built Docker images across CI jobs instead of per-job independent rebuilds.
Alternatives considered:
make stable-mir-json buildacross 2 jobs.docker save+ GitHub Actions artifacts — no registry needed but Docker images are large (multi-GB), slow upload/download.Trade-off: GHCR approach requires
packages:writepermission (may need org-level approval) but eliminates all duplicate build work and keeps jobs independently visible.🤖 Generated with Claude Code