Skip to content

Coverage: drop docker container, split into two independent builds#76

Merged
gagelarsen merged 10 commits into
masterfrom
fix/ci-templates-upgrade-xmsconan
May 17, 2026
Merged

Coverage: drop docker container, split into two independent builds#76
gagelarsen merged 10 commits into
masterfrom
fix/ci-templates-upgrade-xmsconan

Conversation

@gagelarsen

@gagelarsen gagelarsen commented May 14, 2026

Copy link
Copy Markdown
Member

Summary

Three layered fixes to stabilize the Coverage workflow. xmscore Coverage CI was failing for two reasons that compounded:

  1. Stale xmsconan in the runner image — the conan-gcc13-py3.13 docker image baked xmsconan in, and pip install xmsconan>=X.Y.Z silently no-op'd whenever the image's pinned version already satisfied the floor. So the canary was locked to whatever xmsconan the image happened to carry, not what was on devpi.
  2. The combined pybind=True + testing=True + Debug coverage config was structurally fragile — it existed nowhere else in the build matrix, so any change to testing_sources linkage or pybind ABI silently broke Coverage. Most recent symptom: undefined symbol: CxxTest::charToString at pybind dlopen after commit 1d054c2 moved testing_sources out of the main library. Issues xmsconan_coverage passes flat filter to build.py; pybind/testing criteria silently dropped #62, After #61/#62 fixed, testing=True + pybind=True still matches zero configs (mutually exclusive fan-outs) #64, _find_coverage_package picks non-deterministic Python version when python_versions has >1 entry #65, xmsconan_coverage builds without --coverage because XMS_COVERAGE isn't in the conan buildenv #69, xmsconan_coverage reports Python 0% because it looks for cov-py.* at the wrong path #71 all clustered around this same shape.

1. Coverage goes containerless

The Coverage workflow no longer uses any docker container. It runs directly on ubuntu-latest, sets up Python via actions/setup-python@v5, and pip-installs conan / gcovr / xmsconan on every run. ubuntu-latest currently ships gcc 13.3 which matches the conan profile's compiler.version=13. For libraries that set [ci].xvfb = true, the workflow apt-installs xvfb as a job step instead of pulling a custom X11/GDAL container. This removes the hidden coupling between the runner-image refresh cadence and what xmsconan version the canary actually ran.

2. --upgrade added to remaining CI templates

github-ci.yaml.jinja and gitlab-ci.yml.jinja still use docker images for the build/deploy/lint workflows (manylinux compatibility for wheel repair, locked compiler for ABI stability). Those installs gain --upgrade and quoted constraints so they don't silently lock to a baked-in xmsconan when one happens to be in the image.

3. Coverage split into two independent builds

Replace the single combined pybind=True + testing=True + Debug coverage config with two independent builds:

  • C++ coverage build: testing=True, pybind=False, Debug — drives CxxTest under --coverage. gcovr reads .gcda from this build folder.
  • Python coverage build: pybind=True, testing=False, Debug, pinned to one python_version — drives pytest-cov against the wheel. cov-py.xml/cov-py-summary.json/coverage-html-py are copied out of this build folder.

xmsconan_coverage runs build.py twice (sequentially, one job, shared conan cache), locates each package via _find_coverage_package(kind={"testing"|"pybind"}), runs gcovr against the testing folder, and copies pytest-cov artifacts from the pybind folder. The packager no longer emits a coverage-only carve-out — the matrix is asserted to never produce a pybind=True + testing=True config regardless of XMS_COVERAGE.

Coverage number impact: libraries that previously relied on pybind-driven C++ coverage may see their C++ percentage drop, since only CxxTest-reachable code now contributes to cov-cpp.xml. xmscore is unaffected (cpp_threshold=0); downstream libraries with non-zero cpp_threshold should re-baseline against the testing-only build.

Downstream propagation

xms libraries pick this up by regenerating CI yamls with xmsconan ci once 2.15.2 is on devpi. xmscore in particular needs to regenerate Coverage.yaml so the testing_sources fix from 2.15.1 AND the two-build split reach its CI runner.

What this drops

  • The conan-gcc13-py3.13 runner image for Coverage (was the default).
  • The conan-gcc13-x11-gdal-py3.13 runner image for ci_xvfb=true Coverage (now apt installs xvfb instead).
  • The [ci].docker_image override on the Coverage workflow specifically. It's still honored by build/deploy workflows.
  • The XmsConanPackager _coverage carve-out that flipped testing=True on the Debug+pybind variant when XMS_COVERAGE=1.

If any xms library was relying on libraries pre-baked into those images beyond what apt provides on ubuntu-latest, that library will need to add explicit install steps to its workflow (likely via the existing template extension points).

Documentation updates

  • docs/USAGE.md §5.7 — [coverage].python_version row rewritten to describe the pybind-build pinning.
  • docs/USAGE.md §7.2 — testing option row clarified as mutually exclusive with pybind=True in the standard fan-out.
  • docs/USAGE.md §11 — full two-build flow described (testing build → pybind build → gcovr → threshold gate).
  • XMS_COVERAGE=1 documented as the Debug+pybind gate-relaxation switch (the testing-only Debug variant is part of the standard fan-out and no longer needs the env var).

Release plan

Land as 2.15.2 — version is dynamic via setuptools-scm; tag 2.15.2 on master after merge.

Test plan

  • pytest tests/ -m "not integration" → 536 passed, 1 skipped.
  • flake8 clean on touched files.
  • test_github_coverage_yaml_generated_when_coverage_true — asserts the generated workflow has NO container: directive, has actions/setup-python, and uses pip install --upgrade "xmsconan>=…".
  • test_github_coverage_apt_installs_xvfb_when_requested — inverted from the old "uses the xvfb docker image" assertion; now confirms xvfb is apt-installed instead.
  • test_pybind_and_testing_are_never_combined_in_one_config — asserts the packager never emits the combined config, with or without XMS_COVERAGE.
  • test_build_py_invoked_twice_with_disjoint_filters — asserts run_coverage runs build.py twice with disjoint testing/pybind filters.
  • test_gcovr_runs_against_testing_build_folder_not_pybind — asserts gcovr --root is the testing folder, not the pybind folder.
  • CI Linux Coverage run on this branch produces cov-cpp.xml (testing-only) and cov-py.xml (pybind-only) without the CxxTest::charToString regression.
  • xmscore regenerates Coverage.yaml after 2.15.2 lands on devpi; xmscore's Coverage workflow re-runs green.

🤖 Generated with Claude Code

gagelarsen and others added 2 commits May 14, 2026 16:46
Without ``--upgrade``, ``pip install xmsconan>=X.Y.Z`` is a no-op
whenever the runner image has xmsconan pre-installed at any version
satisfying the floor. The xmscore Coverage workflow runs inside
``ghcr.io/aquaveo/conan-gcc13-py3.13:latest`` which bakes in xmsconan,
so the step was silently locking every Coverage run to whatever the
image happened to carry at build time — not to whatever is on devpi.

That was invisible until 2.15.1: the 2.15.0 testing+pybind regression
(the CxxTest symbol leak from the previous commit) shipped, the
docker image refreshed to 2.15.0, xmscore Coverage ran 2.15.0 from
the image, failed, we shipped 2.15.1 with the fix to devpi, xmscore
Coverage re-ran — and the pre-installed 2.15.0 still won because
``>=2.14.0`` was already satisfied. The fix never reached xmscore CI.

Add ``--upgrade`` and quote the constraint across all nine occurrences
in the CI templates (4 in github-ci, 1 in github-coverage, 4 in
gitlab-ci). Every CI invocation now resolves the latest xmsconan
satisfying the floor — which is the contract the workflow appeared
to express in the first place.

Downstream xms libraries pick this up by regenerating their CI yamls
with ``xmsconan ci`` / ``xmsconan_ci`` once a release containing this
change is on devpi. xmscore's Coverage.yaml in particular needs
regeneration before the 2.15.1 testing_sources fix can take effect.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Coverage workflow's docker image (conan-gcc13-py3.13) was baking
xmsconan into the runner image; ``pip install xmsconan>=X.Y.Z`` then
silently no-op'd because the in-image version already satisfied the
floor. That locked every Coverage run to whatever xmsconan the image
happened to carry — which is how xmscore Coverage kept failing against
in-image 2.15.0 even after 2.15.1's fix was on devpi.

Remove the ``container:`` block from ``github-coverage.yaml.jinja``
entirely (including the previous xvfb branch). The job now runs on
plain ubuntu-latest, sets up Python via actions/setup-python, and
pip-installs conan/gcovr/xmsconan on every run. ubuntu-latest currently
ships gcc 13.3 which matches the conan profile's ``compiler.version=13``.

For libraries that set ``[ci].xvfb = true``, the workflow now does
``sudo apt-get install -y xvfb`` instead of pulling a heavier custom
container. ``xmsconan_coverage`` already wraps test execution in
``xvfb-run`` when xvfb is enabled, so no further changes are needed.

``[ci].docker_image`` is no longer honored by Coverage. It still works
for the build/deploy workflows in ``github-ci.yaml.jinja``. Updated
``docs/USAGE.md`` §11.4 to reflect this.

Test ``test_github_coverage_uses_xvfb_image_when_requested`` is
inverted into ``test_github_coverage_apt_installs_xvfb_when_requested``
and asserts there is no ``container:`` directive AND that
``apt-get install -y xvfb`` appears in the rendered workflow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gagelarsen gagelarsen changed the title Always upgrade xmsconan in generated CI pip installs (2.15.1 was silently bypassed) Drop docker container from Coverage workflow; --upgrade xmsconan in remaining CI templates May 14, 2026
@gagelarsen gagelarsen changed the title Drop docker container from Coverage workflow; --upgrade xmsconan in remaining CI templates Coverage: drop docker container, split into two independent builds May 17, 2026
@gagelarsen gagelarsen merged commit 3e45122 into master May 17, 2026
6 checks passed
@gagelarsen gagelarsen deleted the fix/ci-templates-upgrade-xmsconan branch May 17, 2026 01:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant