mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 10:58:28 +00:00
Test cache against latest release in CI (#2714)
Detect cache incompatibility issues like #2711 by testing against the last version of uv continuously
This commit is contained in:
parent
e1878c8359
commit
b36f5d8d48
2 changed files with 185 additions and 0 deletions
49
.github/workflows/ci.yml
vendored
49
.github/workflows/ci.yml
vendored
|
@ -225,6 +225,55 @@ jobs:
|
|||
path: ./target/debug/uv.exe
|
||||
retention-days: 1
|
||||
|
||||
cache-test-ubuntu:
|
||||
needs: build-binary-linux
|
||||
name: "check cache | ubuntu"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
|
||||
- name: "Download binary"
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: uv-linux-${{ github.sha }}
|
||||
|
||||
- name: "Prepare binary"
|
||||
run: chmod +x ./uv
|
||||
|
||||
- name: "Download binary for last version"
|
||||
run: curl -LsSf "https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-unknown-linux-gnu.tar.gz" | tar -xvz
|
||||
|
||||
- name: "Check cache compatibility"
|
||||
run: python scripts/check_cache_compat.py --uv-current ./uv --uv-previous ./uv-x86_64-unknown-linux-gnu/uv
|
||||
|
||||
cache-test-macos-aarch64:
|
||||
needs: build-binary-macos-aarch64
|
||||
name: "check cache | macos aarch64"
|
||||
runs-on: macos-14
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: "Install Python"
|
||||
run: brew install python@3.8
|
||||
|
||||
- name: "Download binary"
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: uv-macos-aarch64-${{ github.sha }}
|
||||
|
||||
- name: "Prepare binary"
|
||||
run: chmod +x ./uv
|
||||
|
||||
- name: "Download binary for last version"
|
||||
run: curl -LsSf "https://github.com/astral-sh/uv/releases/latest/download/uv-aarch64-apple-darwin.tar.gz" | tar -xvz
|
||||
|
||||
- name: "Check cache compatibility"
|
||||
run: python scripts/check_cache_compat.py --uv-current ./uv --uv-previous ./uv-aarch64-apple-darwin/uv
|
||||
|
||||
system-test-debian:
|
||||
needs: build-binary-linux
|
||||
name: "check system | python on debian"
|
||||
|
|
136
scripts/check_cache_compat.py
Executable file
136
scripts/check_cache_compat.py
Executable file
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Install packages on multiple versions of uv to check for cache compatibility errors.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
DEFAULT_TEST_PACKAGES = [
|
||||
# anyio is used throughout our test suite as a minimal dependency
|
||||
"anyio",
|
||||
# flask is another standard test dependency for us, but bigger than anyio
|
||||
"flask",
|
||||
]
|
||||
|
||||
if sys.platform == "linux":
|
||||
DEFAULT_TEST_PACKAGES += [
|
||||
# homeassistant has a lot of dependencies and should be built from source
|
||||
# this requires additional dependencies on macOS so we gate it to Linux
|
||||
"homeassistant",
|
||||
]
|
||||
|
||||
|
||||
def install_package(*, uv: str, package: str, flags: list[str]):
|
||||
"""Install a package"""
|
||||
|
||||
logging.info(f"Installing the package {package!r} with {uv!r}.")
|
||||
subprocess.run(
|
||||
[uv, "pip", "install", package, "--cache-dir", os.path.join(temp_dir, "cache")]
|
||||
+ flags,
|
||||
cwd=temp_dir,
|
||||
check=True,
|
||||
)
|
||||
|
||||
logging.info(f"Checking that `{package}` is available.")
|
||||
code = subprocess.run([uv, "pip", "show", package], cwd=temp_dir)
|
||||
if code.returncode != 0:
|
||||
raise Exception(f"Could not show {package}.")
|
||||
|
||||
|
||||
def clean_cache(*, uv: str):
|
||||
subprocess.run(
|
||||
[uv, "cache", "clean", "--cache-dir", os.path.join(temp_dir, "cache")],
|
||||
cwd=temp_dir,
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
def check_cache_with_package(
|
||||
*,
|
||||
uv_current: str,
|
||||
uv_previous: str,
|
||||
package: str,
|
||||
):
|
||||
# The coverage here is rough and not particularly targetted — we're just performing various
|
||||
# operations in the hope of catching cache load issues. As cache problems are discovered in
|
||||
# the future, we should expand coverage with targetted cases.
|
||||
|
||||
# First, install with the previous uv to populate the cache
|
||||
install_package(uv=uv_previous, package=package, flags=[])
|
||||
|
||||
# Audit with the current uv, this shouldn't hit the cache but is fast
|
||||
install_package(uv=uv_current, package=package, flags=[])
|
||||
|
||||
# Reinstall with the current uv
|
||||
install_package(uv=uv_current, package=package, flags=["--reinstall"])
|
||||
|
||||
# Reinstall with the current uv and refresh a single entry
|
||||
install_package(
|
||||
uv=uv_current,
|
||||
package=package,
|
||||
flags=["--reinstall-package", package, "--refresh-package", package],
|
||||
)
|
||||
|
||||
# Reinstall with the current uv post refresh
|
||||
install_package(uv=uv_current, package=package, flags=["--reinstall"])
|
||||
|
||||
# Reinstall with the current uv post refresh
|
||||
install_package(uv=uv_previous, package=package, flags=["--reinstall"])
|
||||
|
||||
# Clear the cache
|
||||
clean_cache(uv=uv_previous)
|
||||
|
||||
# Install with the previous uv to populate the cache
|
||||
# Use `--no-binary` to force a local build of the wheel
|
||||
install_package(uv=uv_previous, package=package, flags=["--no-binary", package])
|
||||
|
||||
# Reinstall with the current uv
|
||||
install_package(uv=uv_current, package=package, flags=["--reinstall"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
||||
|
||||
parser = argparse.ArgumentParser(description="Check a Python interpreter.")
|
||||
parser.add_argument(
|
||||
"-c", "--uv-current", help="Path to a current uv binary.", required=True
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p", "--uv-previous", help="Path to a previous uv binary.", required=True
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--test-package",
|
||||
action="append",
|
||||
type=str,
|
||||
help="A package to test. May be provided multiple times.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
uv_current = os.path.abspath(args.uv_current)
|
||||
uv_previous = os.path.abspath(args.uv_previous)
|
||||
test_packages = args.test_package or DEFAULT_TEST_PACKAGES
|
||||
|
||||
# Create a temporary directory.
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
logging.info("Creating a virtual environment.")
|
||||
code = subprocess.run(
|
||||
[uv_current, "venv"],
|
||||
cwd=temp_dir,
|
||||
)
|
||||
|
||||
for package in test_packages:
|
||||
logging.info(f"Testing with {package!r}.")
|
||||
check_cache_with_package(
|
||||
uv_current=uv_current,
|
||||
uv_previous=uv_previous,
|
||||
package=package,
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue