litellm/.github/workflows/claude_code_compat_matrix.yml
mateo-berri 0e65ce1495 compat-matrix: open a docs-repo PR instead of direct-pushing main
The daily Claude Code compatibility-matrix cron has been direct-pushing
`compatibility-matrix.json` to litellm-docs's main branch. Switch to
opening (or updating) a pull request so docs maintainers can review each
matrix update before it ships to readers.

Behavioural changes
-------------------

publisher.publish() now:
  * checks out a deterministic head branch
    (`compat-matrix/<litellm>-<claude>-<UTC-date>`) before staging the
    JSON, instead of committing on top of the docs branch directly;
  * `git push --force-with-lease` so a same-day rerun updates the
    existing branch (and therefore the existing PR), without
    overwriting any docs-maintainer fixup commit on the same branch;
  * shells out to `gh pr create` against `docs_repo` with a
    title/body that surfaces the resolved versions and a per-feature
    status summary, so reviewers can triage from the inbox;
  * treats 'a pull request for branch ... already exists' as success,
    so two cron runs on the same day produce one PR, not two.

Idempotency contract
--------------------

  * Same (litellm_version, claude_code_version, UTC date) -> same
    branch -> same PR. Verified by the new
    `test_pr_branch_name_is_deterministic_per_inputs` /
    `...changes_when_any_component_changes` tests.
  * Byte-identical JSON to the docs branch -> early-return before
    push, same as the previous direct-push path.
  * Empty version inputs are rejected up front so two distinct PRs
    can never silently collapse onto one branch.

Tests
-----

  * 8 new tests in `_publisher_unit_tests/test_publisher.py` cover
    `pr_branch_name`, `pr_title_for_matrix`, and `pr_body_for_matrix`
    (determinism, content, ordering, missing-provider rectangularity,
    empty-input rejection).
  * Existing 7 `commit_message_for_matrix` /
    `docker_image_for_tag` / `select_files_to_commit` tests are
    unchanged and still pass.

Workflow
--------

`.github/workflows/claude_code_compat_matrix.yml` updates only the
header doc comment to reflect that the GitHub App now needs
`pull-requests: write` in addition to `contents: write`. `gh` is
preinstalled on `ubuntu-latest` (also used by
`auto_update_price_and_context_window.yml`), so no install step is
needed.

Operator action required (one-time)
-----------------------------------

The compat-matrix GitHub App installation on `BerriAI/litellm-docs`
needs `pull-requests: write` added to its installation permissions
before the next cron run. Without it, the new `gh pr create` call
will fail with a 403; `compat-results.json` and
`compatibility-matrix.json` will still upload as workflow artifacts
for debugging.
2026-05-06 23:27:14 +00:00

130 lines
5.3 KiB
YAML

name: Claude Code Compatibility Matrix (daily cron)
# Slice 4 of the Claude Code Compatibility Matrix (PRD #26476, issue #26480).
#
# Three triggers per the PRD's "Daily Cron" section:
# - Daily cron (06:00 UTC) — picks up newly-published Claude Code releases.
# - `release` of a `v*-stable` tag on this repo — re-runs the matrix the
# moment a new stable LiteLLM ships.
# - Manual dispatch — operators can re-run the publisher on demand.
#
# The job runs on a GitHub-hosted ubuntu-latest runner, which gives us a
# fresh VM per run and is "isolated from the main CI environment" in the
# sense that nothing else on this runner survives the run. Since the
# always-latest Claude Code CLI is only installed inside this ephemeral
# VM, a malicious or broken Claude Code release cannot affect the trusted
# build infrastructure used by the PR gate (which lives in CircleCI and
# uses a `latest minus 3 days` Claude Code pin).
#
# Cross-repo authentication (per "Cross-repo authentication" in the PRD):
# A GitHub App installed on `BerriAI/litellm-docs` only, scoped to
# `contents: write` (so the publisher can push the head branch) and
# `pull-requests: write` (so `gh pr create` can open the docs PR), mints
# an installation token at job-start. The token is only ever used by the
# publisher, which only ever writes `compatibility-matrix.json`
# (enforced by `select_files_to_commit`) and only ever opens PRs against
# `litellm-docs` (enforced by the `--repo` flag passed to `gh`).
on:
schedule:
- cron: "0 6 * * *" # daily at 06:00 UTC
release:
types: [published]
workflow_dispatch:
inputs:
skip_publish:
description: "Run the test pipeline but skip the docs-repo push."
required: false
type: boolean
default: false
permissions:
contents: read
jobs:
publish-matrix:
# Skip release runs that aren't tagged `v*-stable`. Plain `v1.84.0-rc1`
# or `v1.84.0` releases must NOT republish the matrix — only the
# latest *stable* tag is reflected on the docs page.
if: |
github.repository == 'BerriAI/litellm' && (
github.event_name != 'release' ||
endsWith(github.event.release.tag_name, '-stable')
)
runs-on: ubuntu-latest
timeout-minutes: 90
steps:
- name: Checkout litellm
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
- name: Set up uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
with:
version: "0.10.9"
enable-cache: false
- name: Set up Node (for the Claude Code CLI)
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: "20"
- name: Mint docs-repo installation token from GitHub App
id: docs-token
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0
with:
app-id: ${{ secrets.COMPAT_MATRIX_APP_ID }}
private-key: ${{ secrets.COMPAT_MATRIX_APP_PRIVATE_KEY }}
owner: BerriAI
repositories: litellm-docs
- name: Install LiteLLM dev deps
run: uv sync --frozen
- name: Run matrix publisher
env:
# Token used to direct-push compatibility-matrix.json to the docs
# repo's main branch. Comes from the GitHub App installation token
# minted above; scoped to litellm-docs only.
DOCS_REPO_TOKEN: ${{ steps.docs-token.outputs.token }}
# Token used by the resolver to lift the unauthenticated GitHub
# rate limit on the Releases API. The default GITHUB_TOKEN is
# sufficient for read-only access to public release metadata.
GITHUB_TOKEN: ${{ github.token }}
# Real provider credentials needed by the per-cell tests. These
# are the same secrets the LLM-translation workflow uses.
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION_NAME: ${{ secrets.AWS_REGION_NAME }}
VERTEXAI_PROJECT: ${{ secrets.VERTEXAI_PROJECT }}
VERTEXAI_LOCATION: ${{ secrets.VERTEXAI_LOCATION }}
GOOGLE_APPLICATION_CREDENTIALS_JSON: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS_JSON }}
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
AZURE_API_BASE: ${{ secrets.AZURE_API_BASE }}
SKIP_PUBLISH: ${{ inputs.skip_publish }}
run: |
set -euo pipefail
if [ "${SKIP_PUBLISH:-false}" = "true" ]; then
uv run python -m tests.claude_code.publisher --skip-publish
else
uv run python -m tests.claude_code.publisher
fi
- name: Upload compat-results.json artifact (debugging)
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: compat-results-${{ github.run_id }}
path: |
compat-results.json
compatibility-matrix.json
if-no-files-found: ignore
retention-days: 30