139 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/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
 | 
						|
# (https://hledger.org/CONTRIBUTING.html#commit-messages). 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"
 | 
						|
 | 
						|
    # Is this some boring commit, eg a hard-to avoid github merge commit ?
 | 
						|
    # Ignore those.
 | 
						|
    if echo "$SUMMARY" | grep -qE '^Merge'
 | 
						|
    then 
 | 
						|
        # shellcheck disable=SC2059
 | 
						|
        printf "$FMT" "$HASH" "$SUMMARY" "[ignored]"
 | 
						|
    # Does the summary follow convention ?
 | 
						|
    # [;]type[!]: [topic: [subtopic: ...]] subject
 | 
						|
    # spaces after ; and ! and : are optional (also before, but that should be discouraged)
 | 
						|
    # the type prefix is required and must be all word characters
 | 
						|
    # there can be zero or more topic prefixes of increasing depth
 | 
						|
    # a topic prefix must begin with a word character, can contain spaces/slashes/commas
 | 
						|
    # (so potentially multiple topic labels, eg "imp: bs, cf, is: cli/doc: blah blah")
 | 
						|
    elif ! echo "$SUMMARY" | grep -qE '^( *; *)?\w+( *!)? *: *(\w[\w,/ ]* *: *)*'
 | 
						|
    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 <<EOF
 | 
						|
---------------------------------------------------------------------------
 | 
						|
Commit messages should follow this format:
 | 
						|
 | 
						|
  [;]type[!]: [topic:] summary
 | 
						|
 | 
						|
  [Optional description, ready for release notes/changelog.]
 | 
						|
 | 
						|
Explanation:
 | 
						|
 | 
						|
The subject line should have a type: prefix. Common types:
 | 
						|
 feat imp fix            - end-user changes (->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 bin/commitlint .git/hooks/commit-msg
 | 
						|
   b. more convenient:      ln -s ../../bin/commitlint .git/hooks/commit-msg
 | 
						|
2. before pushing:          bin/commitlint && git push
 | 
						|
---------------------------------------------------------------------------
 | 
						|
EOF
 | 
						|
 | 
						|
fi
 | 
						|
 | 
						|
exit 0"$STATUS"
 |