mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
Add CI stabilization skill
Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
This commit is contained in:
parent
4e5152bbff
commit
b0fa4cb607
1 changed files with 246 additions and 0 deletions
246
skills/ci-stabilization/SKILL.md
Normal file
246
skills/ci-stabilization/SKILL.md
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
# Skill: CI/CD Stabilization for LiteLLM
|
||||
|
||||
## When to Use
|
||||
Use this skill when CircleCI tests are failing on the `main` branch and you need to get them all passing. This applies to any CI system but is tailored for LiteLLM's CircleCI setup.
|
||||
|
||||
## Prerequisites
|
||||
- CircleCI API token (for checking pipeline status)
|
||||
- Write access to the repository
|
||||
- Branch name must start with `litellm_` to trigger CircleCI workflows
|
||||
|
||||
## Overview
|
||||
|
||||
The process follows a systematic loop: **Analyze → Fix → Push → Wait → Check → Repeat** until all tests pass.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Reconnaissance
|
||||
|
||||
### Step 1.1: Check Current CI Status
|
||||
```bash
|
||||
# Get the latest pipeline on main
|
||||
curl -s -H "Circle-Token: $CIRCLECI_TOKEN" \
|
||||
"https://circleci.com/api/v2/project/gh/BerriAI/litellm/pipeline?branch=main" | \
|
||||
python3 -c "import sys,json; d=json.load(sys.stdin); print(d['items'][0]['id'])"
|
||||
```
|
||||
|
||||
### Step 1.2: Get All Job Statuses
|
||||
```bash
|
||||
# List all jobs and their status for a workflow
|
||||
curl -s -H "Circle-Token: $CIRCLECI_TOKEN" \
|
||||
"https://circleci.com/api/v2/workflow/$WORKFLOW_ID/job" | \
|
||||
python3 -c "
|
||||
import sys,json
|
||||
data=json.load(sys.stdin)
|
||||
for j in data['items']:
|
||||
if j['status'] == 'failed':
|
||||
print(f\"FAILED: {j['name']:55s} #{j['job_number']}\")
|
||||
"
|
||||
```
|
||||
|
||||
### Step 1.3: Get Failure Details
|
||||
Use the v1.1 API to get step-level output:
|
||||
```bash
|
||||
curl -s "https://circleci.com/api/v1.1/project/github/BerriAI/litellm/$JOB_NUMBER?circle-token=$CIRCLECI_TOKEN" | \
|
||||
python3 -c "
|
||||
import sys,json,subprocess
|
||||
d=json.load(sys.stdin)
|
||||
for step in d.get('steps',[]):
|
||||
for a in step.get('actions',[]):
|
||||
if a.get('failed'):
|
||||
url = a.get('output_url','')
|
||||
print(f'FAILED: {a.get(\"name\",\"\")}')
|
||||
if url:
|
||||
r = subprocess.run(['curl','-s',url], capture_output=True, text=True)
|
||||
data = json.loads(r.stdout)
|
||||
print(data[0]['message'][-3000:])
|
||||
"
|
||||
```
|
||||
|
||||
### Step 1.4: Categorize Failures
|
||||
|
||||
Sort every failure into one of these buckets:
|
||||
|
||||
| Category | Description | Action |
|
||||
|---|---|---|
|
||||
| **Code Bug** | Linting, type errors, wrong assertions | Fix the code |
|
||||
| **Config Bug** | Version mismatch, missing migration, wrong CI params | Fix config |
|
||||
| **Auth Bug** | Tests missing auth mock/override | Add `app.dependency_overrides` |
|
||||
| **Parallel Bug** | Worker crashes, timeouts in `-n 8` | Add `xdist_group`, reduce `-n` |
|
||||
| **External API** | Live API returns errors | Add retries, graceful skip |
|
||||
| **Timing Bug** | Async operations not complete when checked | Add polling/retry |
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Fix Categories (Priority Order)
|
||||
|
||||
### 2.1: Linting & Type Errors
|
||||
These block ALL other jobs. Fix first.
|
||||
|
||||
```bash
|
||||
# Check ruff
|
||||
poetry run ruff check litellm/
|
||||
|
||||
# Common fixes:
|
||||
# - Add `# noqa: PLR0915` for too-many-statements
|
||||
# - Add `# type: ignore[error-code]` for mypy false positives
|
||||
# - Fix actual type annotations
|
||||
```
|
||||
|
||||
### 2.2: Version & Schema Issues
|
||||
```bash
|
||||
# Check proxy-extras version
|
||||
cat litellm-proxy-extras/pyproject.toml | grep version
|
||||
|
||||
# IMPORTANT: Only bump version in source package pyproject.toml
|
||||
# Do NOT bump in requirements.txt (package isn't published yet)
|
||||
|
||||
# Sync schemas
|
||||
cp litellm/proxy/schema.prisma litellm-proxy-extras/litellm_proxy_extras/schema.prisma
|
||||
cp litellm/proxy/schema.prisma schema.prisma
|
||||
|
||||
# Create migrations for schema changes
|
||||
mkdir -p litellm-proxy-extras/litellm_proxy_extras/migrations/YYYYMMDDHHMMSS_description/
|
||||
# Write migration.sql with the SQL diff
|
||||
```
|
||||
|
||||
### 2.3: Security Vulnerabilities
|
||||
```bash
|
||||
# Check npm vulnerabilities
|
||||
cd docs/my-website && npm audit
|
||||
cd ui/litellm-dashboard && npm audit
|
||||
|
||||
# Fix with overrides in package.json or npm audit fix
|
||||
# ALSO check Dockerfile for pinned vulnerable versions
|
||||
grep 'npm install -g' Dockerfile
|
||||
```
|
||||
|
||||
### 2.4: Test Auth Issues
|
||||
Many proxy tests fail with 401 because they don't override FastAPI auth:
|
||||
|
||||
```python
|
||||
# PATTERN: Add this to tests that call proxy endpoints
|
||||
from litellm.proxy._types import LitellmUserRoles, UserAPIKeyAuth
|
||||
import litellm.proxy.proxy_server as ps
|
||||
|
||||
app.dependency_overrides[ps.user_api_key_auth] = lambda: UserAPIKeyAuth(
|
||||
user_role=LitellmUserRoles.PROXY_ADMIN, user_id="test-user"
|
||||
)
|
||||
try:
|
||||
# ... test code ...
|
||||
finally:
|
||||
app.dependency_overrides.pop(ps.user_api_key_auth, None)
|
||||
```
|
||||
|
||||
### 2.5: Parallel Test Isolation
|
||||
Worker crashes (OOM) in parallel pytest:
|
||||
|
||||
```python
|
||||
# Add to heavy test modules/classes
|
||||
import pytest
|
||||
pytestmark = pytest.mark.xdist_group("heavy_group_name")
|
||||
|
||||
# Or reduce parallelism in .circleci/config.yml
|
||||
# Change: -n 8 → -n 4
|
||||
```
|
||||
|
||||
### 2.6: External API Resilience
|
||||
For tests that call live APIs:
|
||||
|
||||
```python
|
||||
# Add retry decorator
|
||||
@pytest.mark.flaky(retries=3, delay=5)
|
||||
|
||||
# For Jest/Node.js tests - add graceful skip
|
||||
if (!spendData || !spendData.length || !spendData[0]) {
|
||||
console.warn('Data not available - skipping assertions');
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.7: UI Test Timeouts
|
||||
Vitest tests with `userEvent.type()` are slow:
|
||||
|
||||
```typescript
|
||||
// Fix: Remove typing delay
|
||||
const user = userEvent.setup({ delay: null });
|
||||
|
||||
// Increase timeout for heavy tests
|
||||
it("should ...", async () => { ... }, { timeout: 15000 });
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Push & Monitor Loop
|
||||
|
||||
### Step 3.1: Create CI Branch
|
||||
```bash
|
||||
# Branch MUST match /litellm_.*/ for CircleCI to run
|
||||
git checkout -b litellm_<descriptive_name>
|
||||
git push -u origin litellm_<descriptive_name>
|
||||
```
|
||||
|
||||
### Step 3.2: Monitor Pipeline
|
||||
```bash
|
||||
# Poll pipeline status
|
||||
curl -s -H "Circle-Token: $CIRCLECI_TOKEN" \
|
||||
"https://circleci.com/api/v2/project/gh/BerriAI/litellm/pipeline?branch=litellm_<branch>" | \
|
||||
python3 -c "
|
||||
import sys,json,subprocess
|
||||
data=json.load(sys.stdin)
|
||||
pid=data['items'][0]['id']
|
||||
wf=json.loads(subprocess.run(['curl','-s','-H',f'Circle-Token: {TOKEN}',
|
||||
f'https://circleci.com/api/v2/pipeline/{pid}/workflow'],
|
||||
capture_output=True, text=True).stdout)
|
||||
# ... check job statuses
|
||||
"
|
||||
```
|
||||
|
||||
### Step 3.3: Iterate
|
||||
After each CI run:
|
||||
1. Check which jobs failed
|
||||
2. Get the exact failing test and error message
|
||||
3. Categorize the failure
|
||||
4. Apply the fix pattern from Phase 2
|
||||
5. Commit, push, wait for next run
|
||||
6. Repeat until 0 failures
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### ❌ Don't bump litellm-proxy-extras in requirements.txt
|
||||
The package isn't published to PyPI yet. Only bump the source `pyproject.toml`. Bumping `requirements.txt` will break ALL jobs.
|
||||
|
||||
### ❌ Don't use `-n 8` for heavy proxy tests
|
||||
8 parallel workers each loading the full FastAPI proxy causes OOM. Use `-n 4`.
|
||||
|
||||
### ❌ Don't assume test failures are code bugs
|
||||
Check if the same test passes in other runs. External API failures SHUFFLE between runs randomly.
|
||||
|
||||
### ❌ Don't patch auth with `unittest.mock.patch()`
|
||||
FastAPI dependency injection requires `app.dependency_overrides`, not `patch()`.
|
||||
|
||||
### ❌ Don't create migrations without checking the actual diff
|
||||
Run `prisma migrate diff` output from CI to see exactly what SQL is needed.
|
||||
|
||||
---
|
||||
|
||||
## Key Files Reference
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `.circleci/config.yml` | CI job definitions, parallelism, timeouts |
|
||||
| `litellm-proxy-extras/pyproject.toml` | Proxy extras version |
|
||||
| `schema.prisma` (3 copies) | DB schema - must stay in sync |
|
||||
| `litellm-proxy-extras/.../migrations/` | DB migrations |
|
||||
| `Dockerfile` | Docker image deps (check for pinned vulnerable versions) |
|
||||
| `docs/my-website/package.json` | npm overrides for security |
|
||||
| `ui/litellm-dashboard/package-lock.json` | UI dependencies |
|
||||
|
||||
## Success Criteria
|
||||
- All CircleCI jobs pass (green)
|
||||
- No worker crashes
|
||||
- No auth 401 errors in tests
|
||||
- External API tests have retries/graceful handling
|
||||
- Security scans pass (no HIGH/CRITICAL CVEs)
|
||||
Loading…
Add table
Reference in a new issue