Skip to content

Commit 22621f6

Browse files
committed
ci: standardize commit messages
1 parent 1326d6d commit 22621f6

3 files changed

Lines changed: 84 additions & 0 deletions

File tree

‎.github/workflows/pr-title.yml‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
name: PR Title
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- edited
8+
- synchronize
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
pr-title:
15+
name: PR title format
16+
if: github.actor != 'dependabot[bot]' && github.actor != 'github-actions[bot]'
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout Repo
20+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
21+
- name: Check PR title
22+
env:
23+
PR_TITLE: ${{ github.event.pull_request.title }}
24+
run: node scripts/check-commit-message.mjs --message "$PR_TITLE"

‎AGENTS.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ haptic('light') // fire haptic
9595
- Data fetching: TanStack Query v5 via hooks package (`useQuote`, `useTokenList`, `useRelayChains`)
9696
- localStorage key: `relay-ui-kit` (starred chains, accepted unverified tokens)
9797

98+
## Commit messages
99+
100+
PR titles use conventional commits:
101+
102+
```
103+
type(scope): subject
104+
```
105+
106+
- Types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `obs`, `perf`, `refactor`, `revert`, `style`, `test`
107+
- Scope is optional (`fix(ui): ...`); `!` before the colon marks a breaking change
108+
- PRs are squash-merged, so the PR title is what lands on `main` and must follow this
109+
format (CI checks it); local branch commits are not restricted
110+
98111
## Writing changesets
99112

100113
Every changeset becomes a public changelog entry at

‎scripts/check-commit-message.mjs‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env node
2+
// Validates a PR title: type(scope): subject
3+
//
4+
// Usage: node scripts/check-commit-message.mjs --message "<title>"
5+
6+
const TYPES = [
7+
'build',
8+
'chore',
9+
'ci',
10+
'docs',
11+
'feat',
12+
'fix',
13+
'obs',
14+
'perf',
15+
'refactor',
16+
'revert',
17+
'style',
18+
'test'
19+
]
20+
21+
const EXEMPT = [/^Revert ".+"$/, /^Version Packages/, /^Release the: /]
22+
23+
const HEADER_RE = new RegExp(`^(${TYPES.join('|')})(\\([^)]+\\))?!?: \\S.*$`)
24+
25+
const title = (process.argv[2] === '--message' ? process.argv[3] : process.argv[2])?.trim()
26+
27+
if (title && (EXEMPT.some((re) => re.test(title)) || HEADER_RE.test(title))) {
28+
process.exit(0)
29+
}
30+
31+
console.error(`✖ Invalid PR title:
32+
33+
${title ?? ''}
34+
35+
Expected format:
36+
37+
type(scope): subject (scope is optional, "!" marks breaking changes)
38+
39+
Allowed types: ${TYPES.join(', ')}
40+
41+
Examples:
42+
43+
feat(ui): add XRP destination support
44+
fix: block token contract addresses in recipient field
45+
chore(sdk): sync api types
46+
`)
47+
process.exit(1)

0 commit comments

Comments
 (0)