mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-05 07:37:50 +00:00
Merge 471a5726e6 into cfc651dcd5
This commit is contained in:
commit
4a4e772679
5 changed files with 120 additions and 14 deletions
9
.github/AGENTS.md
vendored
Normal file
9
.github/AGENTS.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Checkout history
|
||||
|
||||
Use shallow checkouts by default. `actions/checkout` defaults to one commit, so omitting `fetch-depth` is fine. For comparisons, fetch only the required commits with `--no-tags --depth=1` and preserve the existing baseline semantics. Fetching two shallow endpoints does not make `git merge-base` work across missing ancestry
|
||||
|
||||
Use deeper checkout, `fetch-depth: 0`, or `--unshallow` only when the consuming command needs history. For new or changed exceptions, state the consumer and why a targeted fetch cannot preserve its behavior beside that checkout or fetch. Keep bounded retries and timeouts on network operations, and never skip a required check when its baseline is unavailable
|
||||
|
||||
Current exceptions are the depth-two parent diff in `test-linting.yml`, Linear's commit-history scan in `linear-release.yml`, and the historical GitGuardian repository scan in `test-linting.yml`. Do not remove release history or reduce secret-scanning coverage just to make checkout shallow
|
||||
|
||||
Mateo requested this default on 2026-10-27 after a full-history unit checkout timed out before tests started
|
||||
2
.github/workflows/test-linting.yml
vendored
2
.github/workflows/test-linting.yml
vendored
|
|
@ -543,7 +543,7 @@ jobs:
|
|||
run: uv run --no-sync pytest -q --noconftest -p no:cacheprovider -c /dev/null tests/code_coverage_tests/test_workflow_job_name_collisions.py
|
||||
|
||||
- name: test_unit_passed_gate
|
||||
run: uv run --no-sync pytest -q --noconftest -p no:cacheprovider -c /dev/null tests/code_coverage_tests/test_unit_passed_gate.py
|
||||
run: uv run --no-sync pytest -q --noconftest -p no:cacheprovider -c /dev/null tests/code_coverage_tests/test_unit_passed_gate.py tests/code_coverage_tests/test_schema_compatibility_cli.py
|
||||
|
||||
- name: test_e2e_idp_stack
|
||||
run: uv run --no-sync pytest -q --noconftest -p no:cacheprovider -c /dev/null tests/code_coverage_tests/test_e2e_idp_stack.py
|
||||
|
|
|
|||
29
.github/workflows/test-unit.yml
vendored
29
.github/workflows/test-unit.yml
vendored
|
|
@ -956,13 +956,37 @@ jobs:
|
|||
timeout-minutes: ${{ matrix.shard == 'db-and-spend' && 10 || 3 }}
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: ${{ matrix.shard == 'db-and-spend' && '0' || '1' }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Detect relevant changes
|
||||
id: changes
|
||||
timeout-minutes: 2
|
||||
uses: ./.github/actions/detect-changes
|
||||
|
||||
- name: Fetch schema comparison baseline
|
||||
if: matrix.shard == 'db-and-spend' && steps.changes.outputs.decision != 'skip'
|
||||
timeout-minutes: 3
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
|
||||
CHECKED_OUT_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
for attempt in 1 2 3; do
|
||||
if baseline="$(gh api "repos/${REPO}/compare/${DEFAULT_BRANCH}...${CHECKED_OUT_SHA}?per_page=1" --jq '.merge_base_commit.sha')" \
|
||||
&& [[ "$baseline" =~ ^[0-9a-f]{40}$ ]] \
|
||||
&& git fetch --no-tags --depth=1 origin "$baseline"; then
|
||||
printf 'SCHEMA_BASE_COMMIT=%s\n' "$baseline" >> "$GITHUB_ENV"
|
||||
exit 0
|
||||
fi
|
||||
if [ "$attempt" -lt 3 ]; then
|
||||
echo "Schema baseline fetch failed, retrying attempt $((attempt + 1))/3"
|
||||
sleep "$((attempt * 5))"
|
||||
fi
|
||||
done
|
||||
echo "::error::Could not resolve and fetch the schema baseline after 3 attempts"
|
||||
exit 1
|
||||
|
||||
- name: Set up Python
|
||||
if: steps.changes.outputs.decision != 'skip'
|
||||
timeout-minutes: 3
|
||||
|
|
@ -995,7 +1019,6 @@ jobs:
|
|||
env:
|
||||
RUST_BRIDGE_ARTIFACT: ${{ needs.rust-bridge.outputs.artifact }}
|
||||
UNIT_SHARD: ${{ matrix.shard }}
|
||||
SCHEMA_BASE_REF: origin/${{ github.event.repository.default_branch }}
|
||||
run: |
|
||||
diff -u model_prices_and_context_window.json litellm/model_prices_and_context_window_backup.json
|
||||
if [ -z "$RUST_BRIDGE_ARTIFACT" ]; then
|
||||
|
|
@ -1008,7 +1031,7 @@ jobs:
|
|||
fi
|
||||
uv run --no-sync python -c 'import os, sys; print(sys.version); assert f"{sys.version_info.major}.{sys.version_info.minor}" == os.environ["UV_PYTHON"]'
|
||||
if [ "$UNIT_SHARD" = "db-and-spend" ]; then
|
||||
uv run --no-sync python scripts/check_schema_compatibility.py --base-ref "$SCHEMA_BASE_REF"
|
||||
uv run --no-sync python scripts/check_schema_compatibility.py --base-commit "$SCHEMA_BASE_COMMIT"
|
||||
fi
|
||||
|
||||
- name: Cache Prisma binaries
|
||||
|
|
|
|||
|
|
@ -7,14 +7,20 @@ import sys
|
|||
from collections.abc import Iterator, Mapping
|
||||
from pathlib import Path
|
||||
from types import MappingProxyType
|
||||
from typing import Final
|
||||
from typing import Final, TypeAlias
|
||||
|
||||
from pydantic import TypeAdapter
|
||||
from pydantic import BaseModel, ConfigDict, TypeAdapter
|
||||
|
||||
Schema = Mapping[str, Mapping[str, str]]
|
||||
Schema: TypeAlias = Mapping[str, Mapping[str, str]]
|
||||
MODELS: Final = re.compile(r"^[ \t]*model\s+(\w+)\s*\{(.*?)^[ \t]*\}", re.MULTILINE | re.DOTALL)
|
||||
|
||||
|
||||
class _Options(BaseModel):
|
||||
model_config = ConfigDict(frozen=True)
|
||||
base_ref: str | None
|
||||
base_commit: str | None
|
||||
|
||||
|
||||
def parse_model_fields(schema: str) -> Schema:
|
||||
def fields(body: str) -> Mapping[str, str]:
|
||||
parts: Final = tuple(line.split() for line in body.splitlines())
|
||||
|
|
@ -54,12 +60,20 @@ def check_breaking_changes(old_schema: Schema, new_schema: Schema) -> tuple[str,
|
|||
|
||||
def main() -> int:
|
||||
parser: Final = argparse.ArgumentParser()
|
||||
parser.add_argument("--base-ref", required=True)
|
||||
options: Final = parser.parse_args()
|
||||
base_ref: Final = TypeAdapter(str).validate_python(options.base_ref)
|
||||
base: Final = subprocess.run(
|
||||
("git", "merge-base", "HEAD", base_ref), capture_output=True, text=True, check=True
|
||||
).stdout.strip()
|
||||
baseline: Final = parser.add_mutually_exclusive_group(required=True)
|
||||
baseline.add_argument("--base-ref")
|
||||
baseline.add_argument("--base-commit")
|
||||
options: Final = _Options.model_validate(vars(parser.parse_args()))
|
||||
base: Final = (
|
||||
options.base_commit
|
||||
if options.base_commit is not None
|
||||
else subprocess.run(
|
||||
("git", "merge-base", "HEAD", TypeAdapter(str).validate_python(options.base_ref)),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
).stdout.strip()
|
||||
)
|
||||
previous: Final = subprocess.run(
|
||||
("git", "show", f"{base}:schema.prisma"), capture_output=True, text=True, check=True
|
||||
).stdout
|
||||
|
|
@ -69,7 +83,7 @@ def main() -> int:
|
|||
if changes:
|
||||
sys.stderr.write("\n".join(changes) + "\n")
|
||||
return 1
|
||||
sys.stdout.write(f"Schema compatibility passed against merge base {base}\n")
|
||||
sys.stdout.write(f"Schema compatibility passed against baseline {base}\n")
|
||||
return 0
|
||||
|
||||
|
||||
|
|
|
|||
60
tests/code_coverage_tests/test_schema_compatibility_cli.py
Normal file
60
tests/code_coverage_tests/test_schema_compatibility_cli.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
|
||||
CHECKER: Final = Path(__file__).resolve().parents[2] / "scripts/check_schema_compatibility.py"
|
||||
SCHEMA: Final = "model Item {\n id String @id\n label String?\n}\n"
|
||||
|
||||
|
||||
def _git(root: Path, *args: str) -> str:
|
||||
return subprocess.run(
|
||||
("git", "-C", str(root), *args), capture_output=True, text=True, check=True, timeout=30
|
||||
).stdout.strip()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("baseline_option", ("--base-ref", "--base-commit"))
|
||||
@pytest.mark.parametrize(("schema", "expected"), ((SCHEMA, 0), ("model Item {\n id String @id\n}\n", 1)))
|
||||
def test_schema_check_preserves_break_detection_with_or_without_history(
|
||||
tmp_path: Path, schema: str, expected: int, baseline_option: str
|
||||
) -> None:
|
||||
source: Final = tmp_path / "source"
|
||||
source.mkdir()
|
||||
_git(source, "init", "--initial-branch=main")
|
||||
_git(source, "config", "user.name", "Schema test")
|
||||
_git(source, "config", "user.email", "schema-test@example.invalid")
|
||||
_git(source, "config", "commit.gpgsign", "false")
|
||||
(source / "schema.prisma").write_text(SCHEMA)
|
||||
_git(source, "add", "schema.prisma")
|
||||
_git(source, "commit", "-m", "baseline")
|
||||
baseline: Final = _git(source, "rev-parse", "HEAD")
|
||||
(source / "schema.prisma").write_text(schema)
|
||||
_git(source, "add", "schema.prisma")
|
||||
_git(source, "commit", "--allow-empty", "-m", "candidate")
|
||||
checkout: Final = tmp_path / "checkout"
|
||||
_git(tmp_path, "clone", "--depth=1", source.as_uri(), str(checkout))
|
||||
_git(checkout, "fetch", "--no-tags", "--depth=1", "origin", baseline)
|
||||
if baseline_option == "--base-ref":
|
||||
_git(checkout, "fetch", "--unshallow", "origin", "main")
|
||||
|
||||
result: Final = subprocess.run(
|
||||
(sys.executable, "-I", str(CHECKER), baseline_option, baseline),
|
||||
cwd=checkout,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
assert result.returncode == expected, result.stdout + result.stderr
|
||||
assert _git(checkout, "rev-parse", "--is-shallow-repository") == (
|
||||
"true" if baseline_option == "--base-commit" else "false"
|
||||
)
|
||||
expected_output: Final = (
|
||||
f"Schema compatibility passed against baseline {baseline}"
|
||||
if expected == 0
|
||||
else "Breaking: Field Item.label was removed"
|
||||
)
|
||||
assert expected_output in result.stdout + result.stderr
|
||||
Loading…
Add table
Reference in a new issue