Add test environment template cloning and CI tuning - #5904
Merged
Conversation
beckermr
reviewed
Feb 4, 2026
beckermr
requested changes
Feb 4, 2026
beckermr
left a comment
Contributor
There was a problem hiding this comment.
I have a few questions and confusions on my part.
This was referenced Feb 4, 2026
- Reduce test matrix: skip Python 3.11, use reduced matrix for PRs - Exclude benchmark tests from regular CI (run in dedicated job) - Add cache restore-keys for better cache hit rates - Reduce flaky test reruns from 3 to 1 - Switch macOS to faster ARM runners (macos-latest) - Update SDK download for ARM architecture support
Add test_env_template config option that allows create_env to clone from a pre-existing template environment instead of creating from scratch. This provides ~38% speedup for test builds where the template contains all required packages. Cross-platform support: - macOS (APFS): uses cp -c for copy-on-write (~1.8s) - Linux: uses cp --reflink=auto for reflinks on btrfs/xfs - Windows: uses shutil.copytree (~2.5s) Also adds warm_package_cache pytest fixture that creates a session-scoped template environment with Python, pip, setuptools, and expat.
- Update package versions in test recipes to versions available on osx-arm64: - xz: 5.2.3 → 5.4.2 (30_top_level_finalized) - openssl: 1.0.2 → 3.0 (transitive_subpackage) - python: 3.6 → 3.10 (transitive_subpackage) - libpng: 1.6.34 → 1.6.37 (always_include_files_glob) - Update test_top_level_finalized assertion to match new xz version - Fix test_add_pip_as_python_dependency_from_condarc_file[False] by disabling template environment cloning for that test (template includes pip which defeats the test's purpose) - Skip R-related tests on osx-arm64 since r-base is not available in defaults channel for that platform
- Use `conda create --clone` instead of platform-specific copy methods for proper prefix replacement in scripts and metadata files - Use MatchSpec for proper spec parsing instead of manual string splitting - Fix test_transitive_subpackage_dependency: update assertion for openssl 3.0 - Fix test_top_level_finalized: update xz version to 5.6 (available in channels) - Update news file and docstrings to reflect the conda clone approach
jezdez
force-pushed
the
ci-speed-improvements
branch
from
April 28, 2026 12:23
60137c9 to
b3ecfc6
Compare
_clone_template_env previously matched specs by package name only, so any test relying on a variant pin to force a specific version of a package also present in the template silently received the template's version instead. test_top_level_finalized (xz pinned to 5.6) and test_transitive_subpackage_dependency (openssl pinned to 3.0) both fail this way: the session-scoped template env has python/pip/setuptools/expat installed, which pulls xz and openssl as transitive deps at whichever version defaults ships (currently 5.8.2 and 3.5.x). The clone then overwrites the variant-pinned host env. Switch the template check to MatchSpec.match() per spec so version/build constraints are honored. When any spec has a constraint the template can't satisfy, fall back to the normal solve.
Three bugs in the warm_package_cache / test_env_template optimization
were causing widespread test failures across Linux, Windows, and macOS:
1. _clone_template_env was reducing PackageRecord inputs to just the
package name, so MatchSpec("xz") happily matched the template's
xz 5.8.2 even when the caller's variant pinned xz 5.6. Now build an
exact MatchSpec(name, version, build) from each PackageRecord and
refuse to clone unless every requested record matches exactly AND
the template contains no extra records the caller did not ask for.
Also short-circuit when config.disable_pip is set and the template
contains pip/setuptools/wheel, since cloning would silently
reintroduce them.
2. test_disable_pip needs to opt out of the template explicitly (in
addition to the new disable_pip guard, as belt-and-suspenders) just
like test_add_pip_as_python_dependency_from_condarc_file already
does.
3. The warm_package_cache fixture is scope="session" but pytest-xdist
gives each worker its own session, so all N workers were racing to
create the template against the shared ~/conda_pkgs_dir, producing
LockError and InvalidArchiveError on macOS/Windows. Move the
template under the shared xdist base dir and guard creation with a
filelock so only the leader worker invokes conda create; the rest
wait and reuse the published template.
Replace the hand-rolled name->record dict and MatchSpec(name=, version=,
build=) construction with the helpers conda already exposes:
- PrefixData(template).get(name, None) for the by-name lookup, instead of
iterating records and building our own dict.
- PackageRecord.spec ("name=version=build") fed straight into MatchSpec()
for the exact-match case, so we don't over-constrain on channel/subdir
the way to_match_spec() would.
Behavior is identical; this is just smaller and uses the public API.
test_transitive_subpackage_dependency reliably failed in every parallel CI job (linux 3.10/3.13/3.14, linux 3.10 with conda 25.11, windows 3.10/3.14) on this branch even though it kept passing on main. The only difference is the recipe pin we changed to `openssl: 3.0 / python: 3.10`, which made the finalized host of the `foo` output fail to contain a record starting with `openssl 3.0`. The change was originally justified as "osx-arm64 compatibility", but the test is `skipif context.subdir == "osx-arm64"`, so the osx-arm64 rationale never applied. Revert to the values the test was previously asserting on, which the main branch's parallel CI confirms still work end-to-end. The other recipe-version updates in this PR (xz, libpng) stay; only this one was breaking parallel runs.
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.
Description
Two things: a
create_envclone optimization that skips the solver when a pre-built template environment matches, and some CI workflow cleanup.The bigger matrix/runner changes (Python 3.14, macOS ARM,
linux-benchmarksjob) already landed onmainvia #5941 and #5944 while this sat in review, so the workflow diff is smaller than it used to be.Template cloning (
conda_build/environ.py,conda_build/config.py)New
test_env_templateconfig setting. When pointed at a valid prefix,create_envrunsconda create --cloneinstead of solving from scratch. Falls back to the normal solve when:name=version=buildforPackageRecordinputs,MatchSpec.match()for string specs)config.disable_pipis set and the template contains pip/setuptools/wheelUses
PrefixData.get()andPackageRecord.specdirectly, nothing hand-rolled.warm_package_cachefixture (tests/conftest.py)Session-scoped, autouse fixture that builds a shared template env (python+pip+setuptools+expat) and feeds it into
testing_config. Guarded byfilelock.FileLockso pytest-xdist workers don't race on~/conda_pkgs_dir.Workflow tuning (
.github/workflows/tests.yml)and not benchmarkinPYTEST_MARKER).restore-keysfallbacks on all cache steps.Test recipe fixes
30_top_level_finalized(old version gone from defaults), assertion updatedalways_include_files_globtest_disable_pipandtest_add_pip_as_python_dependency_from_condarc_filesettest_env_template = Noneso the template doesn't defeat themChecklist - did you ...
newsdirectory (using the template) for the next release's release notes?CI impact
Job counts (test matrix only):