Skip to content

feat: pre-solved environments for mulled tests#1082

Merged
epruesse merged 3 commits intobioconda:masterfrom
nh13:presolved-mulled-tests
Mar 3, 2026
Merged

feat: pre-solved environments for mulled tests#1082
epruesse merged 3 commits intobioconda:masterfrom
nh13:presolved-mulled-tests

Conversation

@nh13
Copy link
Member

@nh13 nh13 commented Feb 20, 2026

Summary

  • Pre-solves the mulled test environment on the host using conda create --dry-run --json, then passes an @EXPLICIT spec file to the container
  • The container installs from the explicit spec (no solver needed), runs create-env post-processing, then executes tests
  • Graceful fallback: if pre-solve fails for any reason, falls back to the original mulled-build build-and-test path
  • Automatically disabled when mulled_upload_target is set (upload needs the Docker image produced by mulled-build)
  • Adds --no-presolved-mulled-test CLI flag for opt-out

Related: #817

Savings

60-180s per mulled test by eliminating a redundant solver run inside the container.

Risks

  • Medium: conda create --dry-run --json output format varies across conda versions. Robust fallback to original path mitigates this.
  • Medium: Bypassing mulled-build means maintaining a parallel test execution path. The create-env --conda=: /usr/local POSTINSTALL step is replicated from the involucro wrapper.
  • Backward compatible: graceful fallback ensures original behavior is preserved on any failure.

Test plan

  • Run existing test suite: pytest test/
  • Integration test: bioconda-utils build recipes/ config.yml --docker --mulled-test on pyfaidx
  • Verify tests pass identically with and without --no-presolved-mulled-test
  • Test fallback: presolved path failed (host/container platform mismatch on macOS) and correctly fell back to mulled-build
  • Verify mulled_upload_target correctly disables pre-solved path (confirmed: goes straight to mulled-build)

nh13 and others added 3 commits February 19, 2026 17:35
When mulled-build runs build-and-test, it creates a new conda environment
from scratch (full solve + download + install). Since the host just built
the package and already knows the dependency graph, we can pre-solve on
the host and pass an @explicit spec file to the container, skipping the
solver entirely.

Changes:
- Add _generate_explicit_spec() that runs conda create --dry-run --json
  and generates an @explicit spec file with exact URLs + checksums
- Add _test_with_explicit_spec() that runs the conda image directly with
  the spec file, replicating the create-env POSTINSTALL step from involucro
- Add presolved parameter to test_package() (default: True) with
  automatic fallback to original mulled-build path on any failure
- Add presolved_mulled_test parameter to build() and build_recipes()
- Disable pre-solved path when mulled_upload_target is set (upload needs
  the Docker image produced by mulled-build)
- Add --no-presolved-mulled-test CLI flag for opt-out

Related: bioconda-utils issue bioconda#817

Saves 60-180s per mulled test by eliminating a redundant solver run.
@epruesse
Copy link
Member

epruesse commented Mar 3, 2026

@nh13 Do you want to complete the test plan?

@nh13
Copy link
Member Author

nh13 commented Mar 3, 2026

Test plan completed. Tested locally with pyfaidx via Docker:

  1. With presolved (default): presolved path attempted, hit platform mismatch (macOS host vs Linux container), fell back to mulled-build, test passed.
  2. With --no-presolved-mulled-test: went straight to mulled-build, test passed.
  3. Fallback: demonstrated in (1), presolved failure was caught and recovered gracefully.
  4. With --mulled-upload-target: presolved path correctly skipped, went straight to mulled-build.

Note: the presolved path itself can't be fully exercised locally on macOS since the host solver resolves for osx-arm64 while the container expects linux-64 packages. In CI (Linux to Linux), the presolved path would be used. The fallback guarantees correctness either way.

Copy link
Member

@epruesse epruesse left a comment

Choose a reason for hiding this comment

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

LGTM

@epruesse epruesse merged commit af1ac9c into bioconda:master Mar 3, 2026
11 checks passed
johanneskoester pushed a commit that referenced this pull request Mar 4, 2026
🤖 I have created a release *beep* *boop*
---


##
[4.1.0](v4.0.0...v4.1.0)
(2026-03-04)


### Features

* eliminate redundant host-side solver run for Docker builds
([#1081](#1081))
([3d4c9e1](3d4c9e1))
* pre-solved environments for mulled tests
([#1082](#1082))
([af1ac9c](af1ac9c))


### Bug Fixes

* add raise_for_status to CircleCI workflow API call
([#1083](#1083))
([2f558ee](2f558ee))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants