Skip to content

Add test environment template cloning and CI tuning - #5904

Merged
beckermr merged 10 commits into
mainfrom
ci-speed-improvements
May 5, 2026
Merged

Add test environment template cloning and CI tuning#5904
beckermr merged 10 commits into
mainfrom
ci-speed-improvements

Conversation

@jezdez

@jezdez jezdez commented Jan 27, 2026

Copy link
Copy Markdown
Member

Description

Two things: a create_env clone 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-benchmarks job) already landed on main via #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_template config setting. When pointed at a valid prefix, create_env runs conda create --clone instead of solving from scratch. Falls back to the normal solve when:

  • any requested spec doesn't match a template record (exact name=version=build for PackageRecord inputs, MatchSpec.match() for string specs)
  • the template has packages the caller didn't ask for
  • config.disable_pip is set and the template contains pip/setuptools/wheel

Uses PrefixData.get() and PackageRecord.spec directly, nothing hand-rolled.

warm_package_cache fixture (tests/conftest.py)

Session-scoped, autouse fixture that builds a shared template env (python+pip+setuptools+expat) and feeds it into testing_config. Guarded by filelock.FileLock so pytest-xdist workers don't race on ~/conda_pkgs_dir.

Workflow tuning (.github/workflows/tests.yml)

  • Drop Python 3.11 from Linux (3.10/3.12 cover the boundary). PRs run 3.10 + 3.13; main/schedule adds 3.12.
  • Exclude benchmark tests from regular jobs (and not benchmark in PYTEST_MARKER).
  • Add restore-keys fallbacks on all cache steps.
  • Reduce flaky reruns from 3 to 1 on Linux.

Test recipe fixes

  • xz 5.2.3 -> 5.6 in 30_top_level_finalized (old version gone from defaults), assertion updated
  • libpng 1.6.34 -> 1.6.37 in always_include_files_glob
  • test_disable_pip and test_add_pip_as_python_dependency_from_condarc_file set test_env_template = None so the template doesn't defeat them

Checklist - did you ...

  • Add a file to the news directory (using the template) for the next release's release notes?
  • Add / update necessary tests?
  • Add / update outdated documentation?

CI impact

Job counts (test matrix only):

Platform before after (main) after (PRs)
Linux 12 + 1 bench 8 + 1 bench 6 + 1 bench
Windows 4 4 4
macOS 4 4 4

@jezdez
jezdez requested a review from a team as a code owner January 27, 2026 11:09
@github-project-automation github-project-automation Bot moved this to 🆕 New in 🔎 Review Jan 27, 2026
@conda-bot conda-bot added the cla-signed [bot] added once the contributor has signed the CLA label Jan 27, 2026
@codspeed-hq

codspeed-hq Bot commented Jan 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 5 untouched benchmarks


Comparing ci-speed-improvements (5ea2bfe) with main (401d659)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (1b06cd4) during the generation of this report, so 401d659 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@jezdez jezdez mentioned this pull request Feb 2, 2026
3 tasks
Comment thread .github/workflows/tests.yml

@beckermr beckermr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few questions and confusions on my part.

Comment thread conda_build/environ.py Outdated
Comment thread conda_build/environ.py Outdated
jezdez added 5 commits April 28, 2026 14:19
- 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
jezdez force-pushed the ci-speed-improvements branch from 60137c9 to b3ecfc6 Compare April 28, 2026 12:23
jezdez added 5 commits April 28, 2026 15:44
_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.
@jezdez jezdez changed the title ci: improve test CI speed and efficiency Add test environment template cloning and CI tuning May 4, 2026
@jezdez
jezdez requested a review from beckermr May 4, 2026 21:47

@beckermr beckermr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@github-project-automation github-project-automation Bot moved this from 🏗️ In Progress to ✅ Approved in 🔎 Review May 5, 2026
@beckermr
beckermr merged commit 12b588b into main May 5, 2026
45 of 47 checks passed
@beckermr
beckermr deleted the ci-speed-improvements branch May 5, 2026 10:36
@github-project-automation github-project-automation Bot moved this from ✅ Approved to 🏁 Done in 🔎 Review May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed [bot] added once the contributor has signed the CLA

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants