mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-25 05:54:53 +00:00
* chore(hooks): drop Conventional Branches pre-push hook in favor of litellm_ prefix Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * docs(makefile): describe install-hooks as Conventional Commits only * docs(contributing): scope the litellm_ branch prefix to internal contributors --------- Co-authored-by: nate <nate@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
178 lines
6 KiB
Python
178 lines
6 KiB
Python
"""Tests for the repo's git hook scripts in ``.githooks/``.
|
|
|
|
The commit-msg hook enforces Conventional Commits. It is exercised as a
|
|
subprocess against representative valid / invalid inputs so that any future
|
|
regex change or accidental edit gets caught by ``make test-unit``.
|
|
|
|
The hook is a bash script; the test is skipped on Windows where ``bash`` may
|
|
not be on PATH.
|
|
"""
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
_REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
_HOOKS_DIR = _REPO_ROOT / ".githooks"
|
|
_COMMIT_MSG_HOOK = _HOOKS_DIR / "commit-msg"
|
|
|
|
pytestmark = pytest.mark.skipif(
|
|
shutil.which("bash") is None,
|
|
reason="bash not available; git hook scripts are bash-based",
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _ensure_hooks_exist():
|
|
assert _COMMIT_MSG_HOOK.exists(), f"missing hook: {_COMMIT_MSG_HOOK}"
|
|
# Exec bit may be missing on a fresh clone on case-preserving filesystems;
|
|
# the installer normalizes this, but the test shouldn't depend on having
|
|
# run it.
|
|
mode = _COMMIT_MSG_HOOK.stat().st_mode
|
|
if not (mode & 0o100):
|
|
_COMMIT_MSG_HOOK.chmod(mode | 0o755)
|
|
|
|
|
|
def _run_commit_msg(subject: str, tmp_path: Path) -> subprocess.CompletedProcess:
|
|
msg_file = tmp_path / "COMMIT_EDITMSG"
|
|
msg_file.write_text(subject + "\n", encoding="utf-8")
|
|
return subprocess.run(
|
|
["bash", str(_COMMIT_MSG_HOOK), str(msg_file)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
|
|
|
|
# ----- commit-msg -----------------------------------------------------------
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"subject",
|
|
[
|
|
"feat(router): add weighted round-robin strategy",
|
|
"fix(bedrock): decouple STS region from aws_region_name",
|
|
"chore(deps): bump black to 26.3.1",
|
|
"docs: rewrite contributing guide",
|
|
"refactor!: drop Python 3.8 support",
|
|
"feat(api,proxy)!: rename endpoint",
|
|
"test: cover hook bypass list",
|
|
"perf(streaming): avoid extra json parse",
|
|
"revert: feat(router): add weighted round-robin",
|
|
],
|
|
)
|
|
def test_commit_msg_accepts_conventional_subjects(tmp_path, subject):
|
|
result = _run_commit_msg(subject, tmp_path)
|
|
assert result.returncode == 0, (
|
|
f"hook rejected a valid subject:\n subject: {subject!r}\n"
|
|
f" stderr: {result.stderr}"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"subject",
|
|
[
|
|
"add stuff", # no type
|
|
"feat add router strategy", # missing colon
|
|
"feat:add router strategy", # missing space after colon
|
|
"feat():", # empty description
|
|
"ux: thing", # unknown type
|
|
"Feat(router): capital type", # types are lowercase
|
|
"feat(router):", # empty description
|
|
# Description must start with a lowercase letter — kept in sync with
|
|
# the CI workflow's subjectPattern so the local hook never accepts a
|
|
# subject that CI will later reject.
|
|
"feat: Add thing",
|
|
"fix(router): Decouple something",
|
|
"chore: BUMP deps",
|
|
"feat: A",
|
|
],
|
|
)
|
|
def test_commit_msg_rejects_invalid_subjects(tmp_path, subject):
|
|
result = _run_commit_msg(subject, tmp_path)
|
|
assert result.returncode == 1, (
|
|
f"hook accepted an invalid subject:\n subject: {subject!r}\n"
|
|
f" stderr: {result.stderr}"
|
|
)
|
|
assert "Conventional Commits" in result.stderr
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"subject",
|
|
[
|
|
# Lowercase letter — the common case.
|
|
"feat: lowercase start is fine",
|
|
# The CI's `^(?![A-Z]).+$` rejects only uppercase A-Z, so digits and
|
|
# symbols are still allowed; mirror that behavior here.
|
|
"feat: 1-based indexing now works",
|
|
"fix(deps): @types/node bump",
|
|
],
|
|
)
|
|
def test_commit_msg_accepts_non_uppercase_starts(tmp_path, subject):
|
|
result = _run_commit_msg(subject, tmp_path)
|
|
assert result.returncode == 0, (
|
|
f"hook rejected a valid non-uppercase-start subject:\n"
|
|
f" subject: {subject!r}\n stderr: {result.stderr}"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"subject",
|
|
[
|
|
"Merge branch 'main' into feature/foo",
|
|
'Revert "feat(router): add weighted round-robin strategy"',
|
|
"fixup! feat(router): add weighted round-robin strategy",
|
|
"squash! feat(router): add weighted round-robin strategy",
|
|
"amend! feat(router): add weighted round-robin strategy",
|
|
],
|
|
)
|
|
def test_commit_msg_passes_git_generated_messages(tmp_path, subject):
|
|
result = _run_commit_msg(subject, tmp_path)
|
|
assert result.returncode == 0, (
|
|
f"hook should pass git-generated subject:\n subject: {subject!r}\n"
|
|
f" stderr: {result.stderr}"
|
|
)
|
|
|
|
|
|
def test_commit_msg_rejects_empty_message(tmp_path):
|
|
result = _run_commit_msg("", tmp_path)
|
|
assert result.returncode == 1
|
|
assert "empty commit message" in result.stderr
|
|
|
|
|
|
def test_commit_msg_skips_comment_only_lines(tmp_path):
|
|
# An all-comments file has no subject — should be rejected.
|
|
msg_file = tmp_path / "COMMIT_EDITMSG"
|
|
msg_file.write_text("# please enter a commit message\n# above this line\n", encoding="utf-8")
|
|
result = subprocess.run(
|
|
["bash", str(_COMMIT_MSG_HOOK), str(msg_file)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
assert result.returncode == 1
|
|
assert "empty commit message" in result.stderr
|
|
|
|
|
|
def test_commit_msg_uses_first_non_comment_line(tmp_path):
|
|
# Real git-generated COMMIT_EDITMSG has a status block prefixed with '#'
|
|
# below the subject. Make sure leading comment lines are skipped too.
|
|
msg_file = tmp_path / "COMMIT_EDITMSG"
|
|
msg_file.write_text(
|
|
"# On branch feature/foo\n"
|
|
"\n"
|
|
"feat(router): add weighted round-robin\n"
|
|
"\n"
|
|
"# Please enter the commit message...\n",
|
|
encoding="utf-8",
|
|
)
|
|
result = subprocess.run(
|
|
["bash", str(_COMMIT_MSG_HOOK), str(msg_file)],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
assert result.returncode == 0, result.stderr
|