Search code examples
bashgitshellgithooks

Hard-coded commit message policy


I am trying to write a server side hook to check the pattern of the commit messages using bash.

I want to reject the push if any commit not followed the specific Commit-Message format.

For example,

Commit didn't follow the specific commit message format:-

$ git log -1
commit 98yad93c64d06f8cd49a8905b2b28f7509c87aef (HEAD -> master)
Author: Admin <[email protected]>
Date:   Mon Jun 20 16:33:00 2022 +0530

    Updated java file.

For the above case, script need to reject to follow the hard-coded commit message format.

For the below commit message case, push should allow.

$ git log -1
commit c4d4a5c1d83ca1327c1b7e57f60eabe161d467b3 (HEAD -> master)
Author: Admin <[email protected]>
Date:   Mon Jun 20 16:33:00 2022 +0530

    1. Project Name: Java App
    2. Jira ID: 12345
    3. Testing Status: Completed
    4. Employee Name: Robby Nithin
    5. Office: Norway

I have below script to enforce the hard-coded commit message policy.

#!/bin/bash

echo $@

COMMIT_MSG="Project Name:","Jira ID:","Testing Status:","Employee Name:","Office:"

# Hard-coded template
FORMAT=$(cat /opt/template)

if echo "$FORMAT" | grep -qE "$COMMIT_MSG" ;then
    echo "Commit message validation is success!"
    exit 0
else
    echo "Validation failed!"
    exit 1
fi

Script is getting success even the commit not followed the commit message format.

Need help to enforce a specific(Hard-coded) commit message format. Thanks in advance.


Solution

  • You haven't mentioned how your are running the script, so I'll assume you're talking about a local git repo and are not asking about a particular vendor's hooks. In that case, you could put something like the following in .git/hooks/commit-msg:

    #!/bin/sh
    
    
    i=1
    for label in 'Project Name' 'Jira ID' 'Testing Status' 'Employee Name' Office; do
        if ! grep -q "^    $((i++)). $label:" $1; then
            cat <<- EOF
                Proposed commit message does not satisfy this repository's exacting standards
                It must match the template:
                    1. Project Name: xxx
                    2. Jira ID: xxx
                    3. Testing Status: xxx
                    4. Employee Name: xxx
                    5. Office: xxx
    
                The proposed commit message does not contain the label: $label" >&2
            EOF
            exit 1
        fi
    done
    

    Make sure the hook script is executable. Also note that the above mixes hard tabs and spaces to take advantage of the <<- heredoc syntax in the error message. The script will be called with the file name of the proposed commit message as its sole argument. This particular script is IMO far too finicky, and you will probably want to verify the ordering of the labels and be more flexible with whitespace, but this should get you started.

    As with most hooks, exiting non-zero will cause the commit to fail. But this script can easily be by-passed with the --no-verify option to git commit. YMMV

    Running multiple greps against the file is ... icky, but for simplicity I'll leave that example here. But you may prefer to use something like:

    #!/bin/sh    
    
    if ! awk '
        NR==3 && ! /^    1. Project Name:/{exit 1}
        NR==4 && ! /^    2. Jira ID:/{exit 1}
        NR==5 && ! /^    3. Testing Status:/{exit 1}
        NR==6 && ! /^    4. Employee Name:/{exit 1}
        NR==7 && ! /^    5. Office:/{exit 1}
        END { exit NR < 7}
    ' "$1"; then
        sed -e 's/<t>/    /' <<- EOF
            Proposed commit message does not satisfy this repository's exacting standards
            It must match the template: (starting in line 3, and with correct leading whitespace)
            <t>1. Project Name: xxx
            <t>2. Jira ID: xxx
            <t>3. Testing Status: xxx
            <t>4. Employee Name: xxx
            <t>5. Office: xxx
        EOF
        exit 1
    fi >&2