This commit is contained in:
Kazuki Hashimoto 2026-10-11 16:21:30 +00:00 • committed by GitHub
commit 2e5c83e1fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 41 additions and 16 deletions

View file

@ -1,10 +1,11 @@
#!/usr/bin/env bash
#
# pre-push — enforce Conventional Branches
# https://conventional-branch.github.io/
# pre-push hook enforcing the repo's branch naming conventions
#
# Branch format: <type>/<description>
# <type> must be one of: feature, bugfix, hotfix, release, chore
# Accepted formats:
# litellm_<description> (internal convention, see AGENTS.md)
# <type>/<description> (Conventional Branches, https://conventional-branch.github.io/)
# <type> must be one of: feature, bugfix, hotfix, release, chore
#
# Protected branches (always allowed):
# - main
@ -19,7 +20,8 @@ set -eu
ZERO_OID="0000000000000000000000000000000000000000"
ZERO_OID_SHA256="0000000000000000000000000000000000000000000000000000000000000000"
ALLOWED_TYPES="feature|bugfix|hotfix|release|chore"
BRANCH_PATTERN="^(${ALLOWED_TYPES})/.+"
INTERNAL_PREFIX="litellm_"
BRANCH_PATTERN="^((${ALLOWED_TYPES})/|${INTERNAL_PREFIX}).+"
PROTECTED_NAMES="main"
PROTECTED_PREFIXES="dependabot/ gh-readonly-queue/"
@ -64,22 +66,23 @@ done
if [ -n "$invalid" ]; then
cat >&2 <<EOF
✗ Branch name does not follow Conventional Branches.
✗ Branch name does not follow the repo's branch naming conventions.
Invalid:$invalid
Expected: <type>/<description>
Expected: litellm_<description>
or: <type>/<description> (Conventional Branches)
Allowed types: feature, bugfix, hotfix, release, chore
Examples:
litellm_weighted_round_robin
feature/weighted-round-robin
bugfix/streaming-empty-chunks
chore/bump-deps
hotfix/auth-bypass
Protected (always allowed): main, dependabot/*, gh-readonly-queue/*.
See https://conventional-branch.github.io/
See AGENTS.md and https://conventional-branch.github.io/
Rename with: git branch -m <new-name>
To bypass (use sparingly): git push --no-verify

View file

@ -74,7 +74,7 @@ Always pull before starting any work. The checkout or worktree may be sitting on
If you're an internal contributor, when creating a new PR, the typical flow is to branch off the repository's current default branch and create a branch prefixed with litellm_. Do not create a branch prefixed with claude/ and generally do not have / in your branch names
Do not add `Co-Authored-By: Claude` or any Claude attribution to commit messages. Never use a `claude/` prefix or put a `/` in a branch name. Do not add "Generated with Claude Code" (or any similar attribution) to PR descriptions or comments. Do not create a new PR/branch off the existing PR to fix/add something that is related and could've just been committed directly to the existing PR's branch
Do not add `Co-Authored-By: Claude` or any Claude attribution to commit messages. Never use a `claude/` branch prefix. Do not add "Generated with Claude Code" (or any similar attribution) to PR descriptions or comments. Do not create a new PR/branch off the existing PR to fix/add something that is related and could've just been committed directly to the existing PR's branch
When working on a PR, keep the PR description in sync with new commits being made

View file

@ -55,7 +55,7 @@ That's it! Your local development environment is ready.
## Commit and Branch Conventions
Commits follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) and branches follow [Conventional Branches](https://conventional-branch.github.io/). Run `make install-hooks` once per clone to enable the local git hooks that enforce these — see the [contributor docs](https://docs.litellm.ai/docs/extras/contributing_code#commit-and-branch-conventions) for the full type list, examples, the protected-branch bypass list, and how to opt out.
Commits follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). Branches are named either `litellm_<description>` (the form most PRs in this repo use, and the one AGENTS.md asks internal contributors to use) or in the [Conventional Branches](https://conventional-branch.github.io/) form `<type>/<description>`, where `<type>` is one of `feature`, `bugfix`, `hotfix`, `release`, or `chore`. Run `make install-hooks` once per clone to enable the local git hooks that enforce these. See the [contributor docs](https://docs.litellm.ai/docs/extras/contributing_code#commit-and-branch-conventions) for the full type list, examples, the protected-branch bypass list, and how to opt out.
### 2. Development Workflow
@ -78,7 +78,7 @@ uv run pytest tests/unit/<your_test_file>.py -v
git add .
git commit -m "feat(scope): your descriptive commit message"
# Push and create a PR (branch must follow Conventional Branches — see above)
# Push and create a PR (branch name must follow the conventions above)
git push origin feature/your-feature
```

View file

@ -31,7 +31,8 @@ cat <<EOF
core.hooksPath = .githooks
active hooks: $(ls "$hooks_dir" | tr '\n' ' ')
These hooks enforce Conventional Commits and Conventional Branches.
These hooks enforce Conventional Commits and the repo's branch naming
conventions (litellm_<description> or Conventional Branches <type>/<description>).
Bypass with --no-verify when you need to (e.g. for emergency hotfixes).
The CI-equivalent lint is deliberately not installed as an auto-firing hook

View file

@ -1,7 +1,8 @@
"""Tests for the repo's git hook scripts in ``.githooks/``.
The hooks enforce Conventional Commits 1.0.0 on the commit-msg path and
Conventional Branches on the pre-push path. Each hook is exercised here as a
The hooks enforce Conventional Commits 1.0.0 on the commit-msg path and, on the
pre-push path, either the internal ``litellm_`` branch prefix or Conventional
Branches. Each hook is exercised here as a
subprocess against representative valid / invalid inputs so that any future
regex change or accidental edit gets caught by ``make test-unit``.
@ -222,15 +223,35 @@ def test_pre_push_accepts_conventional_branches(branch):
)
@pytest.mark.parametrize(
"branch",
[
"litellm_fix_bedrock_sts_region",
"litellm_conventional_commits",
"litellm_backport_45721_rc_1_106_0",
"litellm_fix/optimize-streaming",
],
)
def test_pre_push_accepts_litellm_prefixed_branches(branch):
result = _run_pre_push(_ref_line(branch))
assert result.returncode == 0, (
f"hook rejected a litellm_ branch:\n branch: {branch!r}\n"
f" stderr: {result.stderr}"
)
@pytest.mark.parametrize(
"branch",
[
"random-branch-name",
"litellm_fix/optimize-streaming", # legacy pattern is now rejected
"ui/navbar-notifications", # not in the allow list
"feature/", # empty description
"Feature/foo", # type is case-sensitive
"feat/foo", # angular commit type, not branch type
"litellm_", # empty description
"litellm-fix-foo", # hyphen is not the litellm_ prefix
"Litellm_fix_foo", # prefix is case-sensitive
"mylitellm_fix_foo", # prefix must start the name
],
)
def test_pre_push_rejects_non_conventional_branches(branch):