Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Commitlint

on:
pull_request:
types: [opened, synchronize, reopened]

permissions:
contents: read
pull-requests: read
Comment thread
willgriffin marked this conversation as resolved.
Outdated

jobs:
commitlint:
name: Validate conventional commits
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
Comment thread
willgriffin marked this conversation as resolved.
- uses: actions/checkout@v5
with:
fetch-depth: 0

- name: Validate commit messages
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# SHAs are hex so safe to interpolate, but use env vars per
# GitHub Actions injection-defense guidance.
COMMITS=$(git log --format=%s "$BASE_SHA".."$HEAD_SHA")

FAILED=0
while IFS= read -r msg; do
[[ -z "$msg" ]] && continue
# Allow merge commits
if [[ "$msg" =~ ^Merge\ ]]; then
Comment thread
willgriffin marked this conversation as resolved.
Outdated
continue
fi
if ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\([a-z0-9-]+\))?!?: .+'; then
echo "::error::Invalid commit message: $msg"
echo " Expected format: type(scope?): subject"
echo " Valid types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert"
FAILED=1
Comment thread
willgriffin marked this conversation as resolved.
Outdated
fi
done <<< "$COMMITS"

if [[ "$FAILED" -eq 1 ]]; then
echo ""
echo "See https://www.conventionalcommits.org/ for the full spec."
exit 1
fi

echo "✓ All commits follow Conventional Commits format."