Skip to content

Commit fa24fc0

Browse files
2 add makefile for quick actions (#6)
* chore(build): add Makefile for dev tasks * chore(githooks): Run tests and build in pre-push * docs(makefile): Add Makefile usage to docs * chore(commit): enforce commit message linting Improve local commit-msg hook with stricter Conventional Commits validation. Add commitlint GitHub Action for push and PRs, add Makefile targets (hooks, commit-lint), and update CONTRIBUTING and docs with usage and examples.
1 parent 61d415c commit fa24fc0

File tree

9 files changed

+569
-103
lines changed

9 files changed

+569
-103
lines changed

.githooks/commit-msg

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,95 @@
22
# Validates commit messages against the Conventional Commits spec.
33
# Activate with: git config core.hooksPath .githooks
44

5+
set -e
6+
57
MSG=$(cat "$1")
68

7-
# Strip comments and trailing whitespace
8-
SUBJECT=$(echo "$MSG" | sed '/^#/d' | head -1 | sed 's/[[:space:]]*$//')
9+
# Strip git comments (lines starting with #) to get the actual message
10+
SUBJECT=$(echo "$MSG" | grep -v '^#' | head -1)
11+
12+
# Remove trailing whitespace
13+
SUBJECT=$(echo "$SUBJECT" | sed 's/[[:space:]]*$//')
14+
15+
# Validate commit message format: type(scope): subject
16+
# Types: feat, fix, docs, style, refactor, perf, test, chore, ci, revert
17+
# Scope is optional
18+
# Subject must be lowercase, start with lowercase, no period at end
19+
# Max length: 100 characters for full header, 72 for subject line
20+
21+
TYPE_PATTERN='feat|fix|docs|style|refactor|perf|test|chore|ci|revert'
22+
SCOPE_PATTERN='[a-z0-9\-]*'
923

10-
PATTERN='^(feat|fix|refactor|test|docs|chore|perf|ci)(\(.+\))?(!)?: .{1,72}$'
24+
# Full pattern: type(scope): subject
25+
# Where scope is optional
26+
if echo "$SUBJECT" | grep -qE "^(${TYPE_PATTERN})(\(${SCOPE_PATTERN}\))?: .+\$"; then
27+
# Check length
28+
LENGTH=$(echo "$SUBJECT" | wc -c)
29+
if [ "$LENGTH" -gt 101 ]; then
30+
echo ""
31+
echo " ✗ Commit message rejected — header exceeds 100 characters."
32+
echo ""
33+
echo " Length: $LENGTH (max: 100)"
34+
echo " Your message: $SUBJECT"
35+
echo ""
36+
exit 1
37+
fi
1138

12-
if ! echo "$SUBJECT" | grep -qE "$PATTERN"; then
39+
# Check subject line (after ": ") is not empty and doesn't end with period
40+
SUBJECT_TEXT=$(echo "$SUBJECT" | sed 's/^[^:]*: //')
41+
if [ -z "$SUBJECT_TEXT" ]; then
42+
echo ""
43+
echo " ✗ Commit message rejected — missing description after colon."
44+
echo ""
45+
exit 1
46+
fi
47+
48+
if echo "$SUBJECT_TEXT" | grep -q '\.$'; then
49+
echo ""
50+
echo " ✗ Commit message rejected — subject should not end with a period."
51+
echo ""
52+
echo " Your message: $SUBJECT"
53+
echo ""
54+
exit 1
55+
fi
56+
57+
# Check first letter after colon+space is lowercase
58+
FIRST_CHAR=$(echo "$SUBJECT_TEXT" | sed 's/^.//')
59+
if ! echo "$SUBJECT_TEXT" | grep -qE '^[a-z]'; then
60+
echo ""
61+
echo " ✗ Commit message rejected — subject must start with lowercase letter."
62+
echo ""
63+
echo " Your message: $SUBJECT"
64+
echo ""
65+
exit 1
66+
fi
67+
68+
exit 0
69+
else
1370
echo ""
14-
echo " Commit message rejected — does not follow Conventional Commits."
71+
echo " Commit message rejected — does not follow Conventional Commits."
1572
echo ""
16-
echo " Format : <type>(<scope>): <description>"
73+
echo " Format: <type>(<scope>): <description>"
1774
echo " Example: feat(auth): add refresh token rotation"
1875
echo ""
19-
echo " Allowed types: feat | fix | refactor | test | docs | chore | perf | ci"
20-
echo " Subject must be lowercase and under 72 characters."
76+
echo " Allowed types:"
77+
echo " • feat — new feature"
78+
echo " • fix — bug fix"
79+
echo " • docs — documentation"
80+
echo " • style — code style (formatting, semicolons, etc)"
81+
echo " • refactor — code refactoring without feature change"
82+
echo " • perf — performance improvement"
83+
echo " • test — test changes"
84+
echo " • chore — dependency or tooling change"
85+
echo " • ci — CI/CD changes"
86+
echo " • revert — revert a previous commit"
87+
echo ""
88+
echo " Rules:"
89+
echo " • Type and scope are lowercase"
90+
echo " • Scope is optional"
91+
echo " • Subject starts with lowercase"
92+
echo " • No period at end"
93+
echo " • Max 100 characters"
2194
echo ""
2295
echo " Your message: $SUBJECT"
2396
echo ""

.githooks/pre-push

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
# Uncomment and adapt the checks below to match your project's tooling.
66
# Remove checks that don't apply. Keep this hook fast — slow hooks get bypassed.
77

8-
# echo "Running tests before push..."
9-
# your-test-command || exit 1
8+
echo "Running tests before push..."
9+
make test || exit 1
1010

11-
# echo "Running build check..."
12-
# your-build-command || exit 1
11+
echo "Running build check..."
12+
make build || exit 1
1313

1414
exit 0

.github/workflows/commitlint.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ name: Commitlint
33
on:
44
pull_request:
55
branches: [main]
6+
push:
7+
branches: [main]
68

79
jobs:
810
commitlint:
@@ -13,8 +15,10 @@ jobs:
1315
with:
1416
fetch-depth: 0
1517

16-
- name: Check commit messages
18+
- name: Validate commit messages
1719
uses: wagoid/commitlint-github-action@v6
1820
with:
21+
configFile: .commitlintrc.json
1922
failOnWarnings: false
2023
helpURL: https://www.conventionalcommits.org
24+
token: ${{ secrets.GITHUB_TOKEN }}

CONTRIBUTING.md

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,74 +72,149 @@ Open a **Feature Request** issue with:
7272

7373
Features that align with the project's scope and architecture are more likely to be accepted.
7474

75-
### Activating the commit-msg hook
75+
### Activating git hooks
7676

77-
A shell-based hook validates commit messages locally against the Conventional Commits spec. Activate it once after cloning — no runtime or dependencies required:
77+
Git hooks validate commit messages locally and prevent commits that don't follow our conventions. Activate them once after cloning:
7878

79+
**Using Make (recommended):**
80+
```bash
81+
make hooks
82+
```
83+
84+
**Or manually:**
7985
```bash
8086
git config core.hooksPath .githooks
87+
chmod +x .githooks/commit-msg
8188
```
8289

83-
Commit messages are also validated in CI on every PR via GitHub Actions.
90+
Commit messages are validated:
91+
- **Locally** — before commit (via `.githooks/commit-msg` hook)
92+
- **In CI** — on every PR (via GitHub Actions with commitlint)
93+
94+
**View commit rules anytime:**
95+
```bash
96+
make commit-lint
97+
```
8498

8599
### Submitting Code Changes
86100

87-
1. Create a branch from `main`:
101+
1. **Create a branch** from `main`:
88102
```bash
89103
git checkout main
90104
git pull upstream main
91105
git checkout -b feat/your-feature-name
92106
```
93-
2. Make your changes following the [code style](#code-style) guidelines
94-
3. Write or update tests
95-
4. Run the validation suite locally (see [Development Setup](docs/getting-started/README.md))
96-
5. Commit following [commit conventions](#commit-conventions)
97-
6. Push and open a Pull Request
107+
108+
2. **Make your changes** following the [code style](#code-style) guidelines
109+
110+
3. **Write or update tests** as needed
111+
112+
4. **Run validation locally**:
113+
```bash
114+
make validate
115+
```
116+
This runs: format → vet → lint → tests (with nice colored output)
117+
118+
5. **Commit following [commit conventions](#commit-conventions)**:
119+
```bash
120+
git commit -m "feat(scope): your message"
121+
```
122+
Your commit message will be validated automatically by the local hook.
123+
124+
6. **Push and open a Pull Request**:
125+
```bash
126+
git push origin feat/your-feature-name
127+
```
128+
129+
**Before submitting the PR, verify:**
130+
- [ ] All validations pass (`make validate`)
131+
- [ ] Commits follow Conventional Commits (`make commit-lint` to review rules)
132+
- [ ] Tests pass (`make test`)
133+
- [ ] Code is formatted (`make fmt`)
134+
- [ ] Documentation is updated if needed
98135

99136
---
100137

101138
## Commit Conventions
102139

103-
We follow **Conventional Commits**. Each commit message should be:
140+
We follow **Conventional Commits** format. Messages are validated both locally (via git hook) and in CI.
141+
142+
### Format
104143

105144
```
106-
<type>(<scope>): <short description>
145+
<type>(<scope>): <description>
107146
108147
[optional body]
109148
110149
[optional footer]
111150
```
112151

113-
**Types:**
152+
### Types
114153

115154
| Type | When to use |
116155
|------------|---------------------------------------|
117156
| `feat` | New feature or behavior |
118157
| `fix` | Bug fix |
158+
| `docs` | Documentation only |
159+
| `style` | Code style (formatting, semicolons) |
119160
| `refactor` | Code change with no behavior change |
161+
| `perf` | Performance improvement |
120162
| `test` | Adding or updating tests |
121-
| `docs` | Documentation only |
122163
| `chore` | Tooling, dependencies, config |
123-
| `perf` | Performance improvement |
124164
| `ci` | CI/CD changes |
165+
| `revert` | Revert a previous commit |
166+
167+
**Scope** (optional): the module or area affected, e.g. `auth`, `api`, `generators`, `docker`.
125168

126-
**Scope** (optional): the module or area affected, e.g. `auth`, `api`, `ui`, `docker`.
169+
### Examples
127170

128-
**Examples:**
171+
**Good examples:**
129172
```
130-
feat(auth): add refresh token revocation on logout
131-
fix(api): return 409 when resource already exists
132-
refactor(core): extract validation to separate utility
133-
test(auth): add unit tests for login use case
134-
docs(setup): add environment variable reference
135-
chore(deps): upgrade dependencies
173+
feat: add user authentication
174+
feat(api): add rate limiting middleware
175+
fix(generators): handle empty project spec
176+
docs(readme): update installation steps
177+
refactor(survey): extract validation logic
178+
test: add test for spec validation
179+
chore: update dependencies
180+
ci: add commitlint to GitHub Actions
136181
```
137182

138-
**Rules:**
183+
**Bad examples (will be rejected):**
184+
```
185+
Add user auth # Missing type
186+
FEAT: add auth # Type not lowercase
187+
feat: Add auth. # Description starts with uppercase, ends with period
188+
feat(api): this is a very long commit message that exceeds the 100 character limit # Too long
189+
```
190+
191+
### Rules
192+
193+
- **Type is required** and must be lowercase
194+
- **Scope is optional** (lowercase) and indicates what part changed
195+
- **Description is required**, starts with lowercase, no period at end
196+
- **Max 100 characters** for the full header (subject line)
139197
- Use the **imperative mood** ("add" not "adds" or "added")
140-
- Keep the first line under **72 characters**
141198
- Reference issues in the footer: `Closes #42`, `Fixes #17`
142199

200+
### Local Validation
201+
202+
Your commits are validated automatically before creation. If the message is invalid, the commit is rejected with a helpful error message.
203+
204+
**To see validation rules:**
205+
```bash
206+
make commit-lint
207+
```
208+
209+
**If a commit is rejected, fix and try again:**
210+
```bash
211+
git commit --amend -m "feat(scope): corrected message"
212+
```
213+
214+
### CI Validation
215+
216+
Commits are also validated in GitHub Actions using commitlint with the `.commitlintrc.json` configuration. This ensures consistency across all contributions.
217+
143218
---
144219

145220
## Pull Request Process

README.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,25 +65,34 @@ See [docs/getting-started](docs/getting-started/README.md) for the full setup gu
6565

6666
## Development
6767

68+
We use a **Makefile** for convenient command execution with clean, colored output:
69+
6870
```bash
69-
# Build the CLI binary
70-
go build -o scaffold ./cmd/scaffold
71+
# See all available commands
72+
make help
7173

72-
# Run the CLI directly (interactive questionnaire)
73-
go run ./cmd/scaffold new
74+
# Build and run the CLI
75+
make scaffold
7476

75-
# Run tests
76-
go test ./...
77+
# Run validation suite (fmt → vet → lint → test)
78+
make validate
7779

78-
# Run tests with coverage
79-
go test -v -coverprofile=coverage.out ./...
80-
go tool cover -html=coverage.out
80+
# Individual commands
81+
make build # Build to bin/scaffold
82+
make test # Run tests
83+
make fmt # Format code
84+
make lint # Lint code
85+
make clean # Remove build artifacts
86+
```
8187

82-
# Format code
83-
go fmt ./...
88+
**Or use raw Go commands:**
8489

85-
# Lint code
86-
golangci-lint run ./...
90+
```bash
91+
go build -o scaffold ./cmd/scaffold # Build
92+
go run ./cmd/scaffold # Run
93+
go test ./... # Test
94+
go fmt ./... # Format
95+
golangci-lint run ./... # Lint
8796
```
8897

8998
---

0 commit comments

Comments
 (0)