From e25a988a3feb4a31843a67274a3a64fea2fed805 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 14 May 2026 13:28:25 -0700 Subject: [PATCH 1/3] ci(codecov): restore litellm/ prefix on uploaded coverage paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pytest-cov runs with --cov=litellm, which makes coverage.xml store paths relative to the package root (e.g. `proxy/proxy_server.py` instead of `litellm/proxy/proxy_server.py`). Codecov auto-resolves these only when the basename is unique in the repo. Files like proxy_server.py, router.py, utils.py, main.py, and constants.py — which have duplicates under enterprise/ or other subpackages — get silently dropped during ingest. The `fixes: ["::litellm/"]` rule prepends `litellm/` to every uploaded path so they resolve unambiguously. Confirmed against multiple recent coverage.xml artifacts that no uploader currently emits paths already prefixed with `litellm/`, so the rule is safe to apply universally. This restores Codecov visibility for the highest-fix-rate hotspots: proxy_server.py, router.py, proxy/utils.py, litellm_logging.py, constants.py, key_management_endpoints.py, utils.py, main.py, user_api_key_auth.py, team_endpoints.py, and litellm_pre_call_utils.py. --- codecov.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/codecov.yaml b/codecov.yaml index 8609d3143d..7900fe0bbb 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -38,3 +38,15 @@ coverage: default: target: auto threshold: 0% # patch coverage should be 100% + +# pytest-cov runs with --cov=litellm, which stores file paths in the XML +# relative to the litellm/ package root (e.g. proxy/proxy_server.py instead +# of litellm/proxy/proxy_server.py). Codecov's auto-prefix heuristic only +# resolves files whose basename is unique in the repo — files like +# proxy_server.py (3 copies), router.py (2 copies), utils.py (20+ copies), +# main.py (20+ copies), constants.py (2 copies) get silently dropped. The +# rule below restores the litellm/ prefix on every uploaded path so they +# resolve unambiguously. Safe because no current uploader emits paths that +# already start with litellm/. +fixes: + - "::litellm/" From ea2c5cf02641943cac5babf3cd4b9cd3967d79ca Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 14 May 2026 13:48:58 -0700 Subject: [PATCH 2/3] Revert "ci(codecov): restore litellm/ prefix on uploaded coverage paths" This reverts commit e25a988a3feb4a31843a67274a3a64fea2fed805. The `fixes: ["::litellm/"]` rule turned out to be applied *after* Codecov's auto-resolution, not before. Files with unique basenames (which were auto-resolving correctly to `litellm/`) got an extra `litellm/` prepended, producing `litellm/litellm/` storage. Files with ambiguous basenames (the actual target of the fix) continued to be dropped because the auto-resolution still failed for them. Net result on the verification run: 1375 files now stored under unresolvable `litellm/litellm/...` paths, and the 11 originally-missing hotspots are still missing. Reverting before piling on further changes. --- codecov.yaml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/codecov.yaml b/codecov.yaml index 7900fe0bbb..8609d3143d 100644 --- a/codecov.yaml +++ b/codecov.yaml @@ -38,15 +38,3 @@ coverage: default: target: auto threshold: 0% # patch coverage should be 100% - -# pytest-cov runs with --cov=litellm, which stores file paths in the XML -# relative to the litellm/ package root (e.g. proxy/proxy_server.py instead -# of litellm/proxy/proxy_server.py). Codecov's auto-prefix heuristic only -# resolves files whose basename is unique in the repo — files like -# proxy_server.py (3 copies), router.py (2 copies), utils.py (20+ copies), -# main.py (20+ copies), constants.py (2 copies) get silently dropped. The -# rule below restores the litellm/ prefix on every uploaded path so they -# resolve unambiguously. Safe because no current uploader emits paths that -# already start with litellm/. -fixes: - - "::litellm/" From 538092a55f9304e4acb84dd4dc7547ad442c1ae8 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 14 May 2026 14:01:05 -0700 Subject: [PATCH 3/3] ci: use --cov=./litellm so coverage paths resolve unambiguously in Codecov MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pytest-cov treats --cov= as a Python package and emits XML paths relative to the package root, stripping the litellm/ prefix (`proxy/proxy_server.py` instead of `litellm/proxy/proxy_server.py`). Codecov's auto-prefix heuristic then drops every file whose basename is ambiguous in the repo — `proxy_server.py` (3 copies under enterprise/), `router.py` (2 copies), `utils.py` (20+), `main.py` (20+), `constants.py` (2). The 11 highest-fix-rate hotspots have never appeared in Codecov. Switching to --cov=./litellm treats the argument as a path, which makes coverage.xml emit repo-relative paths (`litellm/proxy/proxy_server.py`). Each path is unambiguous, so Codecov resolves all files correctly. Verified locally: rerunning a single proxy_unit_tests test with --cov=./litellm produced `filename="litellm/proxy/proxy_server.py"`, `filename="litellm/router.py"`, and `filename="litellm/types/router.py"` as distinct entries — exactly the disambiguation Codecov needs. Touches every workflow that uploads coverage: the two reusable GHA workflows (_test-unit-base.yml, _test-unit-services-base.yml), test-mcp.yml, and all 14 invocations in .circleci/config.yml. --- .circleci/config.yml | 28 +++++++++---------- .github/workflows/_test-unit-base.yml | 2 +- .../workflows/_test-unit-services-base.yml | 4 +-- .github/workflows/test-mcp.yml | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0966da461e..9a5b6da77f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -228,7 +228,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv \ - --cov=litellm \ + --cov=./litellm \ --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=20 \ @@ -293,7 +293,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv \ - --cov=litellm \ + --cov=./litellm \ --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=20 \ @@ -603,7 +603,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=20 \ -n 4 \ @@ -646,7 +646,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x -s \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5" no_output_timeout: 15m @@ -688,7 +688,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ -n 2 \ @@ -732,7 +732,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x -s \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ --retries 3 --retry-delay 5" @@ -814,7 +814,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ -n 4" @@ -856,7 +856,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ -n 4" @@ -930,7 +930,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x -s \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ -n 2" @@ -972,7 +972,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x -s \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ -n 2" @@ -1015,7 +1015,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 \ -n 4" @@ -1090,7 +1090,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ -n 4 \ --junitxml=test-results/junit.xml \ --durations=5 \ @@ -1133,7 +1133,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x -s \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5" no_output_timeout: 15m @@ -1184,7 +1184,7 @@ jobs: --verbose \ --command="awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest \ -vv -x -s \ - --cov=litellm --cov-report=xml \ + --cov=./litellm --cov-report=xml \ --junitxml=test-results/junit.xml \ --durations=5 -n 2 \ --reruns 2 --reruns-delay 1" diff --git a/.github/workflows/_test-unit-base.yml b/.github/workflows/_test-unit-base.yml index 9377cbeb0c..64862f3c8f 100644 --- a/.github/workflows/_test-unit-base.yml +++ b/.github/workflows/_test-unit-base.yml @@ -91,7 +91,7 @@ jobs: --reruns-delay 1 \ --dist=loadscope \ --durations=20 \ - --cov=litellm \ + --cov=./litellm \ --cov-report=xml:coverage.xml \ --cov-config=pyproject.toml diff --git a/.github/workflows/_test-unit-services-base.yml b/.github/workflows/_test-unit-services-base.yml index 8c47b6d766..9dd668cbf3 100644 --- a/.github/workflows/_test-unit-services-base.yml +++ b/.github/workflows/_test-unit-services-base.yml @@ -132,7 +132,7 @@ jobs: --reruns "${RERUNS}" \ --reruns-delay 1 \ --durations=20 \ - --cov=litellm \ + --cov=./litellm \ --cov-report=xml:coverage.xml \ --cov-config=pyproject.toml else @@ -144,7 +144,7 @@ jobs: --reruns-delay 1 \ --dist="${DIST}" \ --durations=20 \ - --cov=litellm \ + --cov=./litellm \ --cov-report=xml:coverage.xml \ --cov-config=pyproject.toml fi diff --git a/.github/workflows/test-mcp.yml b/.github/workflows/test-mcp.yml index 313043e12f..2ae60951af 100644 --- a/.github/workflows/test-mcp.yml +++ b/.github/workflows/test-mcp.yml @@ -43,4 +43,4 @@ jobs: - name: Run MCP tests run: | - uv run --no-sync pytest tests/mcp_tests -x -vv -n 4 --cov=litellm --cov-report=xml --durations=5 + uv run --no-sync pytest tests/mcp_tests -x -vv -n 4 --cov=./litellm --cov-report=xml --durations=5