Since the version 5.3.x it is possible to install a local commit hook, which will evaluate the commit message in addition at commit time. Therefore we provide a Rest-API, which you can use to evaluate a commit message at any time in your process.

How to create a commit message hook?

Please create a file “.git/hooks/commit-msg“ in your repository. This file is a Git hook and will be called during a commit. In this file we can now create a Rest-API call, to evaluate the commit message, based on the rules you have configured in the Push Check (see Rest-API Version 1.0.0 ). So you will have always the same configuration, for a local commit message check (at commit time) and remote check (at push time).

Example hook

In general the .git/hooks/commit-msg can be created like in the following example. The example is working and needs only some configuration. But please feel free to change this hook according to your needs or company guidelines.

#!/usr/bin/python3
    
import sys, re, json, requests

#Load commit message
commitMessageFile = open(sys.argv[1])  
commitMessage = commitMessageFile.read().strip()

# Hook configuration
url = "<your Bitbucket URL (e.g. https://bitbucket-server)>"
project = "<your project slug (e.g. project_1)>"
repository = "<your repsitory slug (e.g. rep_1)>"
accessToken = "<your personal accesstoken>"
endpoint = url + "/rest/jhfb/1.0.0/check/commit"

print("Check commit message")
print("End-point: %s" % (endpoint)) 

headers = {"Authorization": "Bearer %s" % (accessToken)}
payload = {"message": commitMessage, "project-slug": project, "repository-slug" : repository }

# Ask the rest api
resp = requests.post(endpoint, json=payload, headers=headers)

# Everyting fine
if resp.status_code == 200:
    print("Commit message is valid")
    sys.exit(0)

# The evaluation of the commit message fails
if(resp.status_code == 400):
    json_data = json.loads(resp.text)    
    print("JHFB Commit Message Check")
    print("-------------------------------------------")
    for answer in json_data['answers']:
        print(answer['title'])
        print(answer['message'])
    sys.exit(1)
        
# Any other http errors
if(resp.status_code == 404):
    print("[%s] Check if Bitbucket is up, the jhfb hook is enabled and configured" % (resp.status_code))
    sys.exit(1)
    
if(resp.status_code == 401):
    print("[%s] Unauthorized - Please add your accessToken to the script" % (resp.status_code))
    sys.exit(1)

print("[%s] Any other HTTP error" % (resp.status_code))
sys.exit(1)


PY

As you see there is some configuration needed:

url = "<your Bitbucket URL (e.g. https://bitbucket-server)>"
project = "<your project slug (e.g. project_1)>"
repository = "<your repsitory slug (e.g. rep_1)>"
accessToken = "<your personal accesstoken>"
PY

KEY

Description

url

The base url of Bitbucket instance

e.g. https://bitbucket-server

project

The project key of your Bitbucket project. It is needed to access the hook configuration.

e.g. PROJECT_1

You can access this key in the URL of your repository:

https://bitbucket-server/projects/PROJECT_1/repos/rep_1/

repository

The repository key of your Bitbucket repository. It is needed to access the hook configuration.

e.g. rep_1

You can access this key in the URL of your repository:

https://bitbucket-server/projects/PROJECT_1/repos/rep_1/

accessToken

A authentication is needed. In our example we use personal access tokens to authenticate the hook agains Bitbucket. Feel free to change this according to your needs or your company guidelines.

e.g. NTgsajU0ODE3dsDgzdsOR9dF3SqA8DCYVKzAg4cXAdhz7

The following Atlassian article demonstrate, how you can create a personal access token.

https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html

Of course you can get this information in a dynamic way also. This example shows, how the needed configuration will be created based on the configured origin of the repository. This is just a example and needs to be adjusted to your origin:

# Example: access all data based on repository information
# SSH Example origin = ssh://git@bitbucket-server/project_1/rep_1.git

#get the origin of the repository
stream = os.popen('git config --get remote.origin.url')
originOutput = stream.read()

# extract url, project and repo information based on origin 
url = "https://%s" % originOutput.rsplit('/', 3)[-3].rsplit('@', 1)[-1]
project = originOutput.rsplit('/', 2)[-2].strip()
repository = originOutput.rsplit('/', 1)[-1].replace(".git","").strip()
PY

Hook Execution

Remind, that Git hooks needs to be executed. So the executable flag is needed. So please run the following command in your repository.

sudo chmod +x .git/hooks/commit-msg

Python dependencies

The hook needs some has some dependencies. This dependencies needs to be installed

sudo python3 -m pip install requests

How to create a commit message hook in Windows environments?

Windows environment

If you will work with windows it could be more complicated. On Windows, we saw a lot of problems regarding the SHEBANG (e.g. #!/usr/bin/python3). So you maybe need to use a little trick to make the script executable 

Create a wrapper script , which will trigger a python script

#!/bin/sh
#FILE: ./git/hooks/commit-msg

PYTHON = <PATH to your python executable>
$PYTHON .git/hooks/pre-commit.py 
CODE

Create a python script

Create a python script .git/hooks/pre-commit.py with the main functionality, like described in our example. See sections above.

Hook Execution

Remind, that Git hooks needs to be executed. So the executable flag is needed. So please run the following command in your repository.

sudo chmod +x .git/hooks/commit-msg .git/hooks/pre-commit.py

How to use the hook?

The usage is transparent. You do not need to do anything. Just commit!

Push hook

Of course the hook will evaluate in addition the behaviour of pushes is as before. No changes