Skip to content

Commit 4f055ae

Browse files
ryderstormclaude
andcommitted
ci: add PR title validation workflow
Implement automated enforcement of Conventional Commits specification for pull request titles using GitHub Actions. Changes: - Add pr-title-lint workflow using amannn/action-semantic-pull-request - Configure validation for standard commit types matching commitlint - Add sticky comments to guide contributors on invalid titles - Update CONTRIBUTING.md with PR title format requirements - Add PR template header with title format examples and guidance This ensures PR titles follow the same conventions as commits, which is especially important when using squash merge strategy where the PR title becomes the final commit message. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 387568f commit 4f055ae

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

.github/pull_request_template.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
<!--
2+
📋 PR Title Format: <type>(<optional scope>): <description>
3+
4+
Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
5+
6+
Examples:
7+
✅ feat(auth): add login button to navigation
8+
✅ fix: resolve race condition in async handler
9+
✅ docs: update installation instructions
10+
❌ Add new feature (missing type)
11+
❌ Feat: Add feature (uppercase description)
12+
13+
The PR title will be validated automatically.
14+
-->
15+
116
## Why?
217

318
<!-- Summarize the motivation for this change. Reference specs/tasks/issues as needed. -->
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
name: Lint PR Title
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize, reopened]
6+
7+
jobs:
8+
lint-pr-title:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
pull-requests: write
12+
statuses: write
13+
steps:
14+
- uses: amannn/action-semantic-pull-request@v5
15+
id: lint_pr_title
16+
env:
17+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18+
with:
19+
# Match commitlint config-conventional types
20+
types: |
21+
feat
22+
fix
23+
docs
24+
style
25+
refactor
26+
perf
27+
test
28+
build
29+
ci
30+
chore
31+
revert
32+
# Allow optional scope
33+
requireScope: false
34+
# Subject should not start with uppercase (matches conventional commits)
35+
subjectPattern: ^(?![A-Z]).+$
36+
subjectPatternError: |
37+
The subject "{subject}" found in the pull request title "{title}"
38+
didn't match the configured pattern. Please ensure that the subject
39+
doesn't start with an uppercase character.
40+
41+
# Add comment when PR title is invalid
42+
- uses: marocchino/sticky-pull-request-comment@v2
43+
if: always() && (steps.lint_pr_title.outputs.error_message != null)
44+
with:
45+
header: pr-title-lint-error
46+
message: |
47+
👋 Thank you for opening this pull request!
48+
49+
We require PR titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/).
50+
51+
**Error details:**
52+
```
53+
${{ steps.lint_pr_title.outputs.error_message }}
54+
```
55+
56+
**Valid format:** `<type>(<optional scope>): <description>`
57+
58+
**Valid types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
59+
60+
**Examples:**
61+
- `feat(auth): add login button to navigation`
62+
- `fix: resolve race condition in async handler`
63+
- `docs: update installation instructions`
64+
65+
Please update your PR title and the check will run automatically.
66+
67+
# Delete comment when PR title is fixed
68+
- uses: marocchino/sticky-pull-request-comment@v2
69+
if: ${{ steps.lint_pr_title.outputs.error_message == null }}
70+
with:
71+
header: pr-title-lint-error
72+
delete: true

CONTRIBUTING.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ Semantic versioning and releases are automated in CI (e.g., `python-semantic-rel
9696
## Pull Requests
9797

9898
- Keep PRs focused and well scoped.
99-
- Use a conventional title (e.g., `feat: add new feature`).
99+
- **PR titles must follow Conventional Commits format** (e.g., `feat: add new feature`). This is enforced by an automated check.
100100
- PR description template:
101101

102102
```markdown
@@ -110,6 +110,31 @@ Semantic versioning and releases are automated in CI (e.g., `python-semantic-rel
110110
- Ensure all checks pass (tests and pre-commit) before requesting review.
111111
- Reference related issues and task IDs where applicable.
112112

113+
### PR Title Format
114+
115+
PR titles are validated automatically and must follow this format:
116+
117+
```
118+
<type>(<optional scope>): <description>
119+
```
120+
121+
**Valid types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
122+
123+
**Examples:**
124+
- `feat(auth): add login button to navigation`
125+
- `fix: resolve race condition in async handler`
126+
- `docs: update installation instructions`
127+
- `chore: bump dependencies and run pre-commit`
128+
129+
The description should:
130+
- Start with a lowercase letter
131+
- Be concise and descriptive
132+
- Use imperative mood (e.g., "add" not "added" or "adds")
133+
134+
**Breaking changes:** Add `!` after the type (e.g., `feat!: drop Python 3.10 support`)
135+
136+
If the automated check fails, update your PR title and it will re-run automatically.
137+
113138
## Issue Templates
114139

115140
Use the GitHub issue templates under `.github/ISSUE_TEMPLATE/` for bug reports, feature requests, and questions. These templates prompt for summary, context/repro, environment (Python/OS), and related prompt/task IDs.

0 commit comments

Comments
 (0)