mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
detect-backend-changes diffed the event payload's base.sha against the checked-out ref. Those are two different points in time: actions/checkout resolves refs/pull/N/merge, and GitHub recomputes that ref whenever the base branch advances, so the diff picked up whatever landed on staging between the event firing and the job starting. On a recent UI-only pull request three backend commits from staging were attributed to the branch, and every backend shard ran in full Ask the API which files the pull request touches instead. That is the same set the Files changed tab shows, and it is immune to either endpoint moving. The shell body moves into .github/scripts/detect_backend_changes.sh so it can be exercised directly, and the fail-open paths now also cover an API failure, a file list past the API's 3000-entry listing ceiling, and a classifier that prints something unexpected
205 lines
6.8 KiB
YAML
205 lines
6.8 KiB
YAML
name: _Unit Test Base (Reusable)
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
test-path:
|
|
description: "Pytest path(s) to run"
|
|
required: true
|
|
type: string
|
|
workers:
|
|
description: "Number of pytest-xdist workers"
|
|
required: false
|
|
type: number
|
|
default: 2
|
|
reruns:
|
|
description: "Number of reruns for flaky tests"
|
|
required: false
|
|
type: number
|
|
default: 2
|
|
timeout-minutes:
|
|
description: >-
|
|
Timeout for the test step alone. Setup (checkout, dependency install,
|
|
Prisma client generation) gets its own allowance on top, so a slow
|
|
runner or a cold binary download can never cancel passing tests.
|
|
required: false
|
|
type: number
|
|
default: 20
|
|
job-timeout-minutes:
|
|
description: >-
|
|
Backstop for the whole job. Keep it >= `timeout-minutes` plus 35: 30 for
|
|
the per-step ceilings on the setup steps below, and 5 for the runner
|
|
overhead the job clock charges but no step owns (job init, step
|
|
transitions, post-job cleanup). That headroom is what makes the test
|
|
budget a floor rather than a hope, since setup cannot overrun into it
|
|
without failing its own step first. GitHub expressions have no
|
|
arithmetic, so the sum is passed in rather than computed.
|
|
required: false
|
|
type: number
|
|
default: 55
|
|
max-failures:
|
|
description: "Stop after this many failures"
|
|
required: false
|
|
type: number
|
|
default: 10
|
|
dist:
|
|
description: "pytest-xdist distribution mode (loadscope|load|worksteal|loadfile|no)"
|
|
required: false
|
|
type: string
|
|
default: "loadscope"
|
|
artifact-name:
|
|
description: "Unique name for the coverage artifact (must be unique per run)"
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
run:
|
|
name: Run tests
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: ${{ inputs.job-timeout-minutes }}
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
outputs:
|
|
decision: ${{ steps.changes.outputs.decision }}
|
|
|
|
steps:
|
|
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
|
timeout-minutes: 3
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Detect backend-relevant changes
|
|
id: changes
|
|
timeout-minutes: 2
|
|
uses: ./.github/actions/detect-backend-changes
|
|
|
|
- name: Set up Python
|
|
timeout-minutes: 3
|
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
with:
|
|
python-version: "3.12"
|
|
|
|
- name: Set up uv
|
|
timeout-minutes: 3
|
|
uses: ./.github/actions/setup-uv-with-retries
|
|
with:
|
|
version: "0.10.9"
|
|
|
|
- name: Cache uv dependencies
|
|
timeout-minutes: 5
|
|
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
|
|
with:
|
|
path: |
|
|
~/.cache/uv
|
|
.venv
|
|
key: ${{ runner.os }}-uv-${{ hashFiles('uv.lock') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-uv-
|
|
|
|
- name: Install dependencies
|
|
if: steps.changes.outputs.decision != 'skip'
|
|
timeout-minutes: 8
|
|
run: |
|
|
.github/scripts/uv_sync_with_retries.sh --frozen --group ci --group proxy-dev --extra google --extra proxy --extra semantic-router --extra saml
|
|
|
|
- name: Cache Prisma binaries
|
|
if: steps.changes.outputs.decision != 'skip'
|
|
timeout-minutes: 3
|
|
uses: ./.github/actions/cache-prisma-binaries
|
|
|
|
- name: Generate Prisma client
|
|
if: steps.changes.outputs.decision != 'skip'
|
|
timeout-minutes: 3
|
|
run: |
|
|
uv run --no-sync prisma generate --schema litellm/proxy/schema.prisma
|
|
|
|
- name: Run tests
|
|
if: steps.changes.outputs.decision != 'skip'
|
|
timeout-minutes: ${{ inputs.timeout-minutes }}
|
|
env:
|
|
TEST_PATH: ${{ inputs.test-path }}
|
|
MAX_FAILURES: ${{ inputs.max-failures }}
|
|
WORKERS: ${{ inputs.workers }}
|
|
RERUNS: ${{ inputs.reruns }}
|
|
DIST: ${{ inputs.dist }}
|
|
run: |
|
|
if [ "${WORKERS}" = "0" ]; then
|
|
uv run --no-sync pytest ${TEST_PATH:?} \
|
|
--tb=short -vv \
|
|
--maxfail="${MAX_FAILURES}" \
|
|
--reruns "${RERUNS}" \
|
|
--reruns-delay 1 \
|
|
--durations=20 \
|
|
--cov=./litellm \
|
|
--cov-report=xml:coverage.xml \
|
|
--cov-config=pyproject.toml
|
|
else
|
|
uv run --no-sync pytest ${TEST_PATH:?} \
|
|
--tb=short -vv \
|
|
--maxfail="${MAX_FAILURES}" \
|
|
-n "${WORKERS}" \
|
|
--reruns "${RERUNS}" \
|
|
--reruns-delay 1 \
|
|
--dist="${DIST}" \
|
|
--durations=20 \
|
|
--cov=./litellm \
|
|
--cov-report=xml:coverage.xml \
|
|
--cov-config=pyproject.toml
|
|
fi
|
|
|
|
- name: Save coverage report
|
|
if: always() && steps.changes.outputs.decision != 'skip'
|
|
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
with:
|
|
name: coverage-${{ inputs.artifact-name }}-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: coverage.xml
|
|
retention-days: 1
|
|
|
|
upload-coverage:
|
|
name: Upload coverage to Codecov
|
|
needs: run
|
|
if: always() && needs.run.outputs.decision != 'skip'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
pull-requests: write
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Download coverage report
|
|
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
|
|
with:
|
|
pattern: coverage-${{ inputs.artifact-name }}-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: coverage-reports
|
|
merge-multiple: true
|
|
|
|
- name: Upload to Codecov
|
|
id: codecov-upload
|
|
continue-on-error: true
|
|
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
|
|
with:
|
|
use_oidc: true
|
|
directory: coverage-reports
|
|
root_dir: ${{ github.workspace }}
|
|
flags: ${{ inputs.artifact-name }}
|
|
fail_ci_if_error: false
|
|
|
|
- name: Upload to Codecov (retry)
|
|
if: steps.codecov-upload.outcome == 'failure'
|
|
continue-on-error: true
|
|
uses: codecov/codecov-action@75cd11691c0faa626561e295848008c8a7dddffe # v5.5.4
|
|
with:
|
|
use_oidc: true
|
|
directory: coverage-reports
|
|
root_dir: ${{ github.workspace }}
|
|
flags: ${{ inputs.artifact-name }}
|
|
fail_ci_if_error: false
|