#!/usr/bin/env bash # # commitlint [GITRANGE|FILE] # Check unpushed commits, or commits in the specified range, or a # commit message in FILE, for compliance with hledger's conventions # (see https://hledger.org/COMMITS.html or the code below). # If the argument contains - or .. or ^! it's a range, otherwise # a file containing a proposed commit message. # Run interactively, or symlink as .git/hooks/commit-msg to check # your messages before commit. # # Examples: # commitlint foo # commit message in ./foo # commitlint HEAD^! # last commit # commitlint d5d19f841^! # this commit # commitlint -20 # last 20 commits # commitlint master.. # commits in this branch # commitlint 1.21..1.22 | grep -F [FAIL] # bad commits in 1.22 release cycle # commitlint # unpushed commits set -e if [[ -n ${NO_COLOR+set} ]] then RED="" GRN="" NRM="" else RED="\033[31m" GRN="\033[32m" NRM="\033[0m" fi # checkcommit GITHASH - check this commit's message and print result function checkcommit() { HASH=${1} MSG=$(git log -1 "$HASH" --pretty=format:"%s%n%b") checkmsg "$MSG" } # checkmsg MSG [GITHASH] - check this commit message and print result function checkmsg() { MSG=${1} HASH=${2} if [[ -n $HASH ]] then HASH="$HASH " fi SUMMARY=$(echo "$MSG" | head -1) FMT="%s%-60s %b${NRM}\n" # Ignore certain boring commits, like a github merge commit # or a temporary "git commit --fixup" commit. if echo "$SUMMARY" | grep -qE '^(Merge|fixup!)' then # shellcheck disable=SC2059 printf "$FMT" "$HASH" "$SUMMARY" "[ignored]" # Does the summary follow the conventions described in COMMITS.md ? Roughly: # [;][feat|imp|fix[!]:] topic: Summary # # Some passing examples: # feat: accounts: --types shows account types (#1820) # imp!: journal: Remove deprecated account type code syntax from account directives. # fix: types: Ensure auto postings can match against and be matched by type: queries. # tools: commitlint: allow a git "fixup! " prefix # doc: releasing: tweaks # # Some failing examples: # Revert "imp: ui: accounts: also show declared accounts, even if unused" # Update description of hledger-check-tagfiles.hs # ; PR-template: Change comment syntax # ; cabal.project: Drop compatibility comment # # At least one type/topic prefix is required. The first must be all word characters, # others may contain commas/slashes/spaces. # Spaces are allowed around the ; (and before the ! and :, though it's not preferred). elif ! echo "$SUMMARY" | grep -qE '^( *[;!] *)?\w+ *!? *:( *\w[\w,/ ]* *:)*' # keep synced with COMMITS.md: then # shellcheck disable=SC2059 printf "$FMT" "$HASH" "$SUMMARY" "${RED}[FAIL]" STATUS=1 # Looks like a good commit. else # shellcheck disable=SC2059 printf "$FMT" "$HASH" "$SUMMARY" "${GRN}[ok]" fi } STATUS= RANGE=${*:-"@{u}.."} # @{u} = upstream if [[ $RANGE =~ (-|\.\.|\^!) ]] then HASHES=$(git log --abbrev-commit --pretty=format:%h "$RANGE") for HASH in $HASHES; do checkcommit "$HASH"; done else MSG=$(cat "$1") checkmsg "$MSG" fi if [[ -z $STATUS ]] then printf "" # "${GRN}Ok${NRM}\n" else # shellcheck disable=SC2059 printf "\n${RED}Commit(s) not in preferred style.${NRM}\n" cat <release notes & changelogs) cha pkg lib - packager/builder/lib-user changes (->changelogs) dev doc test ci ref cln - developer changes (->just commit log, mostly) It can additionally have a topic prefix (and optionally subtopics), such as: bin examples install cli ui web print reg bal bs balcmds journal csv ... (see https://hledger.org/CONTRIBUTING.html#open-issues -> COMPONENT) Space, comma and slash are also tolerated inside topics for now. Eg: imp: bs, cf, is: cli/doc: blah blah blah Mention any related issues, usually parenthesised at end of summary: (#1234) ! indicates a breaking change. ; skips expensive CI tests. These conventions are evolving. In practice, any type or topic will do. Use your best judgement and we'll polish during code review. More context: https://hledger.org/CONTRIBUTING.html#commit-messages You can set up this script to check your commit messages locally: 1. before committing: a. safer but must redo: cp tools/commitlint .git/hooks/commit-msg b. more convenient: ln -s ../../tools/commitlint .git/hooks/commit-msg 2. before pushing: tools/commitlint && git push --------------------------------------------------------------------------- EOF fi exit 0"$STATUS"