Skip to content

Commit e4e3a9b

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 dda693a commit e4e3a9b

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
@@ -140,7 +140,7 @@ Semantic versioning and releases are automated in CI using `python-semantic-rele
140140
## Pull Requests
141141

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

146146
```markdown
@@ -154,6 +154,31 @@ Semantic versioning and releases are automated in CI using `python-semantic-rele
154154
- Ensure all checks pass (pre-commit) before requesting review.
155155
- Reference related issues where applicable.
156156

157+
### PR Title Format
158+
159+
PR titles are validated automatically and must follow this format:
160+
161+
```
162+
<type>(<optional scope>): <description>
163+
```
164+
165+
**Valid types:** `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
166+
167+
**Examples:**
168+
- `feat(auth): add login button to navigation`
169+
- `fix: resolve race condition in async handler`
170+
- `docs: update installation instructions`
171+
- `chore: bump dependencies and run pre-commit`
172+
173+
The description should:
174+
- Start with a lowercase letter
175+
- Be concise and descriptive
176+
- Use imperative mood (e.g., "add" not "added" or "adds")
177+
178+
**Breaking changes:** Add `!` after the type (e.g., `feat!: drop Python 3.10 support`)
179+
180+
If the automated check fails, update your PR title and it will re-run automatically.
181+
157182
## Issue Templates
158183

159184
Use the GitHub issue templates under `.github/ISSUE_TEMPLATE/` for bug reports, feature requests, and questions. These templates prompt for summary, context/repro, and related prompt/workflow information.

0 commit comments

Comments
 (0)