Skip to content

Commit 6796475

Browse files
authored
[ci] Add git hooks and PR validation (#32)
* [ci] Add pre-commit and commit-msg git hooks * [ci] Add PR title and description validation workflow * [docs] Add hooks target and development section
1 parent 18e9026 commit 6796475

5 files changed

Lines changed: 121 additions & 1 deletion

File tree

.githooks/commit-msg

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/sh
2+
# Commit-msg hook: enforce [type] prefix convention.
3+
4+
SUBJECT=$(head -1 "$1")
5+
6+
# Allow merge commits and reverts
7+
case "$SUBJECT" in
8+
Merge*|Revert*) exit 0 ;;
9+
esac
10+
11+
# Keep in sync with .github/workflows/pr.yml
12+
PATTERN='^\[(feat|fix|refactor|test|ci|docs|perf|chore|polish|breaking)\] .+'
13+
14+
if ! echo "$SUBJECT" | grep -qE "$PATTERN"; then
15+
echo ""
16+
echo "ERROR: Invalid commit message:"
17+
echo " $SUBJECT"
18+
echo ""
19+
echo "Expected format:"
20+
echo " [type] Description"
21+
echo ""
22+
echo "Allowed types:"
23+
echo " feat, fix, refactor, test, ci, docs, perf, chore, polish, breaking"
24+
echo ""
25+
echo "Examples:"
26+
echo " [feat] Add worktree sync command"
27+
echo " [fix] Resolve branch detection on Windows"
28+
echo " [ci] Add coverage gate to CI pipeline"
29+
exit 1
30+
fi

.githooks/pre-commit

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
# Pre-commit hook: format staged Go files and run linter.
3+
4+
set -e
5+
6+
# Format staged Go files
7+
STAGED_GO_FILES=$(git diff --cached --name-only --diff-filter=ACM -- '*.go')
8+
9+
if [ -n "$STAGED_GO_FILES" ]; then
10+
echo "$STAGED_GO_FILES" | xargs gofmt -l -w
11+
echo "$STAGED_GO_FILES" | xargs git add
12+
fi
13+
14+
# Run linter
15+
make lint

.github/workflows/pr.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: PR Validation
2+
3+
on:
4+
pull_request:
5+
types: [opened, edited, synchronize]
6+
branches: [main]
7+
8+
jobs:
9+
validate-pr:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- name: Validate PR title
13+
env:
14+
PR_TITLE: ${{ github.event.pull_request.title }}
15+
run: |
16+
# Keep in sync with .githooks/commit-msg
17+
PATTERN='^\[(feat|fix|refactor|test|ci|docs|perf|chore|polish|breaking)\] .+'
18+
if ! echo "$PR_TITLE" | grep -qE "$PATTERN"; then
19+
echo "::error::PR title must match format: [type] Description (e.g. [feat] Add new feature)"
20+
echo ""
21+
echo "Allowed types: feat, fix, refactor, test, ci, docs, perf, chore, polish, breaking"
22+
exit 1
23+
fi
24+
25+
- name: Validate PR description
26+
env:
27+
PR_BODY: ${{ github.event.pull_request.body }}
28+
run: |
29+
TRIMMED=$(echo "$PR_BODY" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
30+
if [ -z "$TRIMMED" ]; then
31+
echo "::error::PR description must not be empty"
32+
exit 1
33+
fi

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LDFLAGS = -s -w \
66
-X github.com/lugassawan/rimba/cmd.commit=$(COMMIT) \
77
-X github.com/lugassawan/rimba/cmd.date=$(DATE)
88

9-
.PHONY: build test test-short test-e2e test-coverage clean lint bench
9+
.PHONY: build test test-short test-e2e test-coverage clean lint bench hooks
1010

1111
build:
1212
go build -ldflags '$(LDFLAGS)' -o bin/rimba .
@@ -32,3 +32,7 @@ lint:
3232

3333
bench:
3434
go test -bench=. -benchmem -run=^$$ ./...
35+
36+
hooks:
37+
git config core.hooksPath .githooks
38+
@echo "Git hooks activated from .githooks/"

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [Commands](#commands)
2222
- [Configuration](#configuration)
2323
- [Environment Variables](#environment-variables)
24+
- [Development](#development)
2425
- [License](#license)
2526

2627
## Features
@@ -396,6 +397,43 @@ work_dir = 'api'
396397
| `RIMBA_QUIET` | Suppress pre-execution hints (set to any value, e.g. `RIMBA_QUIET=1`) |
397398
| `NO_COLOR` | Disable colored output globally (per [no-color.org](https://no-color.org)) |
398399

400+
## Development
401+
402+
### Setup
403+
404+
```sh
405+
git clone https://github.com/lugassawan/rimba.git
406+
cd rimba
407+
make hooks # Activate git hooks
408+
make build # Build the binary
409+
```
410+
411+
### Git Hooks
412+
413+
Running `make hooks` configures Git to use the hooks in `.githooks/`:
414+
415+
- **pre-commit** — formats staged Go files with `gofmt` and runs `make lint`
416+
- **commit-msg** — enforces the `[type] Description` commit message format
417+
418+
### Commit Convention
419+
420+
All commit messages must follow the format `[type] Description`, where type is one of:
421+
422+
| Type | Purpose |
423+
|------|---------|
424+
| `feat` | New feature |
425+
| `fix` | Bug fix |
426+
| `refactor` | Code restructuring (no behavior change) |
427+
| `test` | Adding or updating tests |
428+
| `ci` | CI/CD changes |
429+
| `docs` | Documentation |
430+
| `perf` | Performance improvement |
431+
| `chore` | Maintenance tasks |
432+
| `polish` | Minor improvements and cleanups |
433+
| `breaking` | Breaking changes |
434+
435+
This convention is enforced locally by git hooks and in CI by PR title validation.
436+
399437
## License
400438

401439
[MIT](LICENSE)

0 commit comments

Comments
 (0)