mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
fix(ci): pin workflow toolchain dependencies
This commit is contained in:
parent
0bfcc21b71
commit
6cfb705aec
5 changed files with 42 additions and 29 deletions
|
|
@ -112,10 +112,10 @@ commands:
|
|||
node --version
|
||||
npm --version
|
||||
install_rust:
|
||||
description: "Install pinned rustup (1.28.2) and Rust toolchain (1.97.1) with checksum verification. Adds ~/.cargo/bin to PATH. Run this before any `uv sync` or `uv build` of the workspace: the root package builds litellm-rust through maturin, and on an image without cargo maturin fetches an unpinned rustup and a floating toolchain by itself."
|
||||
description: "Install pinned rustup (1.28.2) and Rust toolchain (1.98.0) with checksum verification. Adds ~/.cargo/bin to PATH. Run this before any `uv sync` or `uv build` of the workspace: the root package builds litellm-rust through maturin, and on an image without cargo maturin fetches an unpinned rustup and a floating toolchain by itself."
|
||||
steps:
|
||||
- run:
|
||||
name: Install Rust (rustup 1.28.2, toolchain 1.97.1)
|
||||
name: Install Rust (rustup 1.28.2, toolchain 1.98.0)
|
||||
command: |
|
||||
case "$(uname -m)" in
|
||||
x86_64)
|
||||
|
|
@ -135,7 +135,7 @@ commands:
|
|||
"https://static.rust-lang.org/rustup/archive/1.28.2/${RUSTUP_TRIPLE}/rustup-init"
|
||||
echo "${RUSTUP_SHA256} /tmp/rustup-init" | sha256sum -c -
|
||||
chmod +x /tmp/rustup-init
|
||||
/tmp/rustup-init -y --no-modify-path --profile minimal --default-toolchain 1.97.1
|
||||
/tmp/rustup-init -y --no-modify-path --profile minimal --default-toolchain 1.98.0
|
||||
rm -f /tmp/rustup-init
|
||||
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> "$BASH_ENV"
|
||||
export PATH="$HOME/.cargo/bin:$PATH"
|
||||
|
|
@ -300,7 +300,7 @@ jobs:
|
|||
if ($rustupActual -ne $rustupExpected) {
|
||||
throw "rustup installer hash mismatch: expected $rustupExpected got $rustupActual"
|
||||
}
|
||||
& $rustupInit -y --profile minimal --default-toolchain stable
|
||||
& $rustupInit -y --profile minimal --default-toolchain 1.98.0
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
|
|
|||
14
.github/actions/setup-uv-with-retries/action.yml
vendored
14
.github/actions/setup-uv-with-retries/action.yml
vendored
|
|
@ -1,11 +1,7 @@
|
|||
name: "Set up uv with retries"
|
||||
description: >-
|
||||
Install uv via astral-sh/setup-uv, retrying on transient failures. Even with
|
||||
an exact pinned version, the action resolves the artifact URL by fetching
|
||||
https://raw.githubusercontent.com/astral-sh/versions/main/v1/uv.ndjson in a
|
||||
single request with no retry, timeout, or fallback, so one connection-level
|
||||
network error ("fetch failed") fails the whole job before any test runs.
|
||||
Retrying the full step covers the manifest fetch and the binary download.
|
||||
Install uv via astral-sh/setup-uv, retrying the full setup step so manifest
|
||||
resolution and binary downloads get fresh attempts after transient failures.
|
||||
|
||||
inputs:
|
||||
version:
|
||||
|
|
@ -18,7 +14,7 @@ runs:
|
|||
- name: Set up uv (attempt 1)
|
||||
id: attempt-1
|
||||
continue-on-error: true
|
||||
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
||||
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
|
|
@ -31,7 +27,7 @@ runs:
|
|||
id: attempt-2
|
||||
if: steps.attempt-1.outcome == 'failure'
|
||||
continue-on-error: true
|
||||
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
||||
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
|
|
@ -42,6 +38,6 @@ runs:
|
|||
|
||||
- name: Set up uv (attempt 3)
|
||||
if: steps.attempt-2.outcome == 'failure'
|
||||
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
||||
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
||||
with:
|
||||
version: ${{ inputs.version }}
|
||||
|
|
|
|||
12
.github/workflows/test-rust.yml
vendored
12
.github/workflows/test-rust.yml
vendored
|
|
@ -6,6 +6,7 @@ on:
|
|||
- "litellm-rust/**"
|
||||
- ".cargo/**"
|
||||
- "pyproject.toml"
|
||||
- "rust-toolchain.toml"
|
||||
- ".github/scripts/smoke_test_native_wheel.py"
|
||||
- ".github/scripts/verify_linux_native_wheel.py"
|
||||
- ".github/workflows/test-rust.yml"
|
||||
|
|
@ -19,6 +20,7 @@ on:
|
|||
- "litellm-rust/**"
|
||||
- ".cargo/**"
|
||||
- "pyproject.toml"
|
||||
- "rust-toolchain.toml"
|
||||
- ".github/scripts/smoke_test_native_wheel.py"
|
||||
- ".github/scripts/verify_linux_native_wheel.py"
|
||||
- ".github/workflows/test-rust.yml"
|
||||
|
|
@ -48,9 +50,7 @@ jobs:
|
|||
persist-credentials: false
|
||||
|
||||
- name: Set up Rust
|
||||
run: |
|
||||
rustup toolchain install stable --profile minimal --component clippy,rustfmt
|
||||
rustup default stable
|
||||
run: rustup toolchain install
|
||||
|
||||
- name: Cache Cargo registry and target
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
||||
|
|
@ -59,7 +59,7 @@ jobs:
|
|||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
litellm-rust/target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('litellm-rust/Cargo.lock') }}
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('rust-toolchain.toml', 'litellm-rust/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-
|
||||
|
||||
|
|
@ -104,9 +104,7 @@ jobs:
|
|||
version: "0.10.9"
|
||||
|
||||
- name: Set up Rust
|
||||
run: |
|
||||
rustup toolchain install stable --profile minimal
|
||||
rustup default stable
|
||||
run: rustup toolchain install
|
||||
|
||||
- name: Build release wheel
|
||||
run: uv build --wheel --out-dir dist
|
||||
|
|
|
|||
4
rust-toolchain.toml
Normal file
4
rust-toolchain.toml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "1.98.0"
|
||||
profile = "minimal"
|
||||
components = ["rustfmt", "clippy"]
|
||||
|
|
@ -17,28 +17,27 @@ Two invariants are pinned here:
|
|||
Windows job, so the check accepts either. A new job that syncs without one
|
||||
falls back to the unpinned path, which is exactly the regression a static
|
||||
check catches at PR time and a green CI run does not.
|
||||
2. `install_rust` itself pins what it downloads: an explicit rustup version in
|
||||
the URL, a verified SHA-256, and an exact toolchain version rather than a
|
||||
channel name.
|
||||
|
||||
The Windows job predates `install_rust` and provisions its toolchain inline, so
|
||||
invariant 2 is scoped to `install_rust`; invariant 1 covers both.
|
||||
2. Both installers pin what they download: an explicit rustup version, a
|
||||
verified SHA-256, and the exact toolchain in `rust-toolchain.toml`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
CONFIG = REPO_ROOT / ".circleci" / "config.yml"
|
||||
TOOLCHAIN: Final = REPO_ROOT / "rust-toolchain.toml"
|
||||
|
||||
BUILDS_WORKSPACE = re.compile(r"\buv\s+(?:sync|build)\b")
|
||||
RUSTUP_ARCHIVE_URL = re.compile(r"https://static\.rust-lang\.org/rustup/archive/\d+\.\d+\.\d+/")
|
||||
EXACT_TOOLCHAIN = re.compile(r"--default-toolchain\s+\"?\d+\.\d+\.\d+\"?")
|
||||
EXACT_TOOLCHAIN = re.compile(r"--default-toolchain\s+\"?(\d+\.\d+\.\d+)\"?")
|
||||
TOOLCHAIN_CHANNEL: Final = re.compile(r'^channel = "(\d+\.\d+\.\d+)"$', re.MULTILINE)
|
||||
|
||||
|
||||
def _config() -> dict[str, object]:
|
||||
|
|
@ -57,6 +56,12 @@ def _step_text(step: object) -> str:
|
|||
return ""
|
||||
|
||||
|
||||
def _pinned_toolchain() -> str:
|
||||
match: Final = TOOLCHAIN_CHANNEL.search(TOOLCHAIN.read_text())
|
||||
assert match is not None, "rust-toolchain.toml must pin an exact channel"
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def _without_comments(text: str) -> str:
|
||||
return "\n".join(line for line in text.splitlines() if not line.lstrip().startswith("#"))
|
||||
|
||||
|
|
@ -142,7 +147,17 @@ def test_install_rust_verifies_the_installer_checksum(install_rust_command: str)
|
|||
|
||||
|
||||
def test_install_rust_pins_an_exact_toolchain_version(install_rust_command: str) -> None:
|
||||
assert EXACT_TOOLCHAIN.search(install_rust_command), (
|
||||
"install_rust must pin an exact toolchain version (e.g. 1.97.1); a channel name like "
|
||||
match: Final = EXACT_TOOLCHAIN.search(install_rust_command)
|
||||
assert match is not None, (
|
||||
"install_rust must pin an exact toolchain version (e.g. 1.98.0); a channel name like "
|
||||
"stable/beta/nightly makes the compiler drift with whatever upstream published that day"
|
||||
)
|
||||
assert match.group(1) == _pinned_toolchain()
|
||||
|
||||
|
||||
def test_windows_installer_matches_the_repo_toolchain() -> None:
|
||||
windows_steps: Final = _step_lists()["job using_litellm_on_windows"]
|
||||
windows_command: Final = "\n".join(_step_text(step) for step in windows_steps)
|
||||
match: Final = EXACT_TOOLCHAIN.search(windows_command)
|
||||
assert match is not None
|
||||
assert match.group(1) == _pinned_toolchain()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue