diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f9ce9e5dcb8..67f342c0813 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,21 @@ + + ## Relevant issues @@ -45,14 +63,18 @@ If you're seeing a delay in your PR being merged, ping the LiteLLM Team on [Slac ## Type - - + -๐Ÿ†• New Feature -๐Ÿ› Bug Fix -๐Ÿงน Refactoring -๐Ÿ“– Documentation -๐Ÿš„ Infrastructure -โœ… Test +- `feat` โ€” New feature +- `fix` โ€” Bug fix +- `refactor` โ€” Refactoring (no behavior change) +- `docs` โ€” Documentation +- `perf` โ€” Performance improvement +- `test` โ€” Tests only +- `build` โ€” Build system / dependencies +- `ci` โ€” CI / GitHub Actions +- `chore` โ€” Maintenance / release / tooling +- `revert` โ€” Revert a previous commit +- `style` โ€” Formatting / whitespace ## Changes diff --git a/.github/workflows/validate-pr-title.yml b/.github/workflows/validate-pr-title.yml new file mode 100644 index 00000000000..1006191e4f4 --- /dev/null +++ b/.github/workflows/validate-pr-title.yml @@ -0,0 +1,69 @@ +name: Validate PR Title + +# Enforces Conventional Commits 1.0.0 on PR titles. +# PRs to litellm_internal_staging are squash-merged, so the PR title becomes +# the commit subject on the release-feeding branch. Mechanical parseability +# matters for changelogs and cherry-picks. +# +# Skipped on PRs to main: those are rollups from staging that preserve the +# underlying conventional commits, so the rollup title itself doesn't need +# to match. + +on: + pull_request: + types: [opened, edited, reopened, synchronize] + branches-ignore: + - main + workflow_dispatch: + inputs: + title: + description: 'PR title to validate (for runtime testing)' + required: true + type: string + +permissions: + contents: read + +jobs: + validate: + name: Conventional Commits PR title + runs-on: ubuntu-latest + timeout-minutes: 2 + steps: + - name: Validate title + env: + PR_TITLE: ${{ github.event.pull_request.title || inputs.title }} + run: | + set -u + echo "Validating title: $PR_TITLE" + + # Conventional Commits 1.0.0 โ€” allowed types per the spec plus + # the common extras the project uses. `security` is intentionally + # omitted: OSS commits use reliability/maintenance language. + # See: https://www.conventionalcommits.org/en/v1.0.0/ + PATTERN='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9._-]+(/[a-z0-9._-]+)*\))?!?: .+' + + if [[ "$PR_TITLE" =~ $PATTERN ]]; then + echo "PR title matches Conventional Commits format." + exit 0 + fi + + echo "::error::PR title does not match Conventional Commits 1.0.0." + cat <<'EOF' + + PR title must follow Conventional Commits 1.0.0: + + (): + + Allowed types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert + Use `!` after the type/scope for breaking changes (e.g. feat(api)!: drop /v1/foo). + + Examples: + feat(mcp): add oauth2 authorization flow + fix(ui-teams): refresh table on member change + refactor(ui-playground): extract message renderer + chore(release): merge internal staging into main + + See: https://www.conventionalcommits.org/en/v1.0.0/ + EOF + exit 1 diff --git a/AGENTS.md b/AGENTS.md index 4bdbf26ae9d..0ced0df3c43 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -140,6 +140,16 @@ When opening issues or pull requests, follow these templates: - Clearly describe the feature - Explain motivation and use case with concrete examples +### Pull Request Title Format + +**PR titles must follow [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/)**: `(): `. + +- Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. +- Append `!` for breaking changes (e.g. `feat(api)!: drop /v1/foo`). +- Examples: `feat(mcp): add oauth2 authorization flow`, `fix(ui-teams): refresh table on member change`, `chore(release): merge internal staging into main`. +- The `validate-pr-title` GitHub Actions check enforces this on every PR (rollup PRs to `main` are exempt). +- Local commits on the PR branch don't need to match โ€” `litellm_internal_staging` is squash-merge only, so the squash flattens to the PR title at merge time. + ### Pull Requests (`.github/pull_request_template.md`) - Add at least 1 test in `tests/litellm/` - Ensure `make test-unit` passes diff --git a/CLAUDE.md b/CLAUDE.md index 71e5af28ee7..6329eaec9c5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -48,6 +48,10 @@ When contributing to the project, use the appropriate templates: **Pull Requests** (`.github/pull_request_template.md`): - Add at least 1 test in `tests/litellm/` - Ensure `make test-unit` passes +- **PR title must follow [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/)** โ€” `(): `. Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. Use `!` for breaking changes. The `validate-pr-title` GHA enforces this on every PR (except rollups to `main`). + - Why: `litellm_internal_staging` is squash-merge only, so the PR title becomes the staging commit subject โ€” keep it parseable for changelogs and cherry-picks. `main` is merge-only and preserves the underlying commits. + - Examples: `feat(mcp): add oauth2 authorization flow`, `fix(ui-teams): refresh table on member change`, `chore(release): merge internal staging into main`. + - Local commits on the PR branch don't have to match โ€” the squash flattens to the PR title at merge time. Only the PR title needs to match. ## Architecture Overview diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ac83341f64..d5490d8b8ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,7 @@ Here are the core requirements for any PR submitted to LiteLLM: - [ ] **Sign the Contributor License Agreement (CLA)** - [see details](#contributor-license-agreement-cla) - [ ] **Keep scope isolated** - Your changes should address 1 specific problem at a time +- [ ] **Use a Conventional Commits PR title** - [see details](#commit-and-pr-conventions) #### Proxy (Backend) PRs @@ -67,9 +68,9 @@ make lint # Run unit tests to ensure nothing is broken make test-unit -# Commit your changes +# Commit your changes (see "Commit and PR Conventions" below for the title format) git add . -git commit -m "Your descriptive commit message" +git commit -m "feat(scope): short description of your change" # Push and create a PR git push origin your-feature-branch @@ -312,6 +313,40 @@ Ensure the UI builds successfully before submitting your PR: npm run build ``` +## Commit and PR Conventions + +LiteLLM follows [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/) for **PR titles**. A GitHub Actions check (`.github/workflows/validate-pr-title.yml`) enforces the format on every PR. + +### Format + +``` +(): +``` + +- **Allowed types**: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`. +- **Scope** (optional): a short noun for the area touched, lowercase, e.g. `mcp`, `ui-teams`, `proxy-auth`. +- **Description**: short imperative-mood summary, no trailing period. +- **Breaking changes**: append `!` after the type/scope, e.g. `feat(api)!: drop /v1/foo`. + +### Examples + +- `feat(mcp): add oauth2 authorization flow` +- `fix(ui-teams): refresh table on member change` +- `refactor(ui-playground): extract message renderer` +- `docs: clarify proxy startup steps` +- `chore(release): merge internal staging into main` + +### Why + +Branches we care about have different merge strategies: + +- **`litellm_internal_staging`** is **squash-merge only**, so the PR title becomes the squash commit subject. Conventional titles are mechanically parseable for changelogs and easy to cherry-pick. +- **`main`** is **merge-commit only** (no squash), so the underlying conventional commits are preserved through release rollups. + +You don't need to rewrite local commit history on the PR branch; the squash flattens to the PR title at merge time. Only the **PR title** needs to match the convention. + +> PRs to `main` (release rollups) are exempt from this check, since they aggregate already-conventional commits from staging. + ## Submitting Your PR 1. **Push your branch**: `git push origin your-feature-branch` diff --git a/README.md b/README.md index 72fd43925c9..e1ff16d37f9 100644 --- a/README.md +++ b/README.md @@ -482,6 +482,8 @@ make test-unit # Run unit tests make format-check # Check formatting only ``` +**PR titles follow [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/)** (e.g. `feat(mcp): add oauth2 flow`, `fix(ui-teams): refresh table`). A GitHub Actions check enforces the format. See [CONTRIBUTING.md โ†’ Commit and PR Conventions](CONTRIBUTING.md#commit-and-pr-conventions) for details. + For detailed contributing guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md). > **๐Ÿ“– Contributing to documentation?** The LiteLLM docs have moved to a separate repository: [BerriAI/litellm-docs](https://github.com/BerriAI/litellm-docs). Please open doc PRs there. Docs are served at [docs.litellm.ai](https://docs.litellm.ai).