diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c640cf003..f972a2c97 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,6 +30,11 @@ repos: types: [python] pass_filenames: false args: [src/adcp] + - id: check-commit-msg + name: release-please commit subject check + entry: scripts/check-commit-msg.sh + language: script + stages: [commit-msg] # Security scanning with bandit - repo: https://github.com/PyCQA/bandit diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a443d8369..ff1e3051e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,9 +10,11 @@ git clone https://github.com/adcontextprotocol/adcp-client-python.git cd adcp-client-python ``` -2. Install dependencies: +2. Install dependencies and pre-commit hooks: ```bash pip install -e ".[dev]" +pre-commit install +pre-commit install --hook-type commit-msg ``` 3. Run tests: @@ -82,6 +84,40 @@ src/adcp/ 4. Update documentation 5. Submit PR with clear description +### PR Title Format + +This repository uses squash merges. The PR title becomes the commit subject that +release-please reads to build the CHANGELOG and determine version bumps. + +**The description portion of the commit subject — the text after `type(scope):` — +must not contain `(`, `)`, or `"` characters.** The release-please parser treats +those characters as grammar tokens when they appear in the description and silently +drops the commit from the CHANGELOG with no error signal. (The `type(scope)` prefix +itself is fine; only the description portion is constrained.) + +**Wrong — parser drops these commits silently:** + +``` +fix(auth): synthesize AuthInfo(kind="bearer") in _build_request_context +feat(auth): serve(auth=BearerTokenAuth(...)) — A2A sibling shortcut +``` + +**Right — move code examples and parenthetical details to the PR body:** + +``` +fix(auth): synthesize bearer AuthInfo in _build_request_context +feat(auth): add A2A sibling and cross-transport shortcut for bearer auth +``` + +Place code snippets, type names with parens, and parenthetical clarifications in the PR +body (release-please reads body footers like `BREAKING CHANGE:` and `Fixes #N` but +otherwise ignores the body for CHANGELOG purposes). + +A `commit-msg` pre-commit hook (`scripts/check-commit-msg.sh`) catches violations on +direct commits. It does **not** catch squash-merge subjects (those are set by GitHub on +merge from the PR title), so keeping the PR title clean is the primary responsibility. +Hook setup is included in step 2 of Development Setup above. + ## Questions? Open an issue or email maintainers@adcontextprotocol.org diff --git a/scripts/check-commit-msg.sh b/scripts/check-commit-msg.sh new file mode 100755 index 000000000..5507732ca --- /dev/null +++ b/scripts/check-commit-msg.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Validates commit subjects against release-please parser constraints. +# Embedded ( ) or " in the description silently drop commits from the CHANGELOG. +# NOTE: this hook runs on direct commits only — squash-merge subjects (set by +# GitHub from the PR title) bypass it. Keep the PR title clean as the primary fix. +# +# Enable: pre-commit install --hook-type commit-msg + +set -euo pipefail + +msg_file="$1" +subject=$(head -1 "$msg_file") + +# Only validate conventional commit messages: type(scope): desc or type: desc +cc_pattern='^[a-z]+(\([^)]*\))?(!)?: ' +if echo "$subject" | grep -qE "$cc_pattern"; then + description="${subject#*: }" + if echo "$description" | grep -qE '[()"]'; then + echo "" + echo "commit-msg: release-please will silently drop this commit from the CHANGELOG." + echo "" + echo " Subject: $subject" + echo "" + echo ' The description (text after "type(scope):") contains ( ) or " characters,' + echo " which break release-please's conventional commit parser." + echo "" + echo " Fix: reword to avoid parentheses and quotes in the description." + echo " Move code snippets and type names with parens to the PR body instead." + echo "" + echo " Example:" + echo ' Wrong: fix(auth): synthesize AuthInfo(kind="bearer") in _build_request_context' + echo " Right: fix(auth): synthesize bearer AuthInfo in _build_request_context" + echo "" + exit 1 + fi +fi + +exit 0