Skip to content
This repository has been archived by the owner on Dec 7, 2022. It is now read-only.

Have Travis validate commit messages #3614

Merged
merged 1 commit into from Sep 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 29 additions & 0 deletions .travis/check_commit.sh
@@ -0,0 +1,29 @@
#!/bin/bash

# skip this check for everything but PRs
if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
exit 0
fi

if [ "$TRAVIS_COMMIT_RANGE" != "" ]; then
RANGE=$TRAVIS_COMMIT_RANGE
elif [ "$TRAVIS_COMMIT" != "" ]; then
RANGE=$TRAVIS_COMMIT
fi

# Travis sends the ranges with 3 dots. Git only wants one.
if [[ "$RANGE" == *...* ]]; then
RANGE=`echo $TRAVIS_COMMIT_RANGE | sed 's/\.\.\./../'`
else
RANGE="$RANGE~..$RANGE"
fi

for sha in `git log --format=oneline --no-merges "$RANGE" | cut '-d ' -f1`
do
python .travis/validate_commit_message.py $sha
VALUE=$?

if [ "$VALUE" -gt 0 ]; then
exit $VALUE
fi
done
2 changes: 2 additions & 0 deletions .travis/script.sh
Expand Up @@ -11,6 +11,8 @@ if [ "$TEST" = 'docs' ]; then
fi


# check the commit message
./.travis/check_commit.sh

# Lint code.
flake8 --config flake8.cfg || exit 1
Expand Down
42 changes: 42 additions & 0 deletions .travis/validate_commit_message.py
@@ -0,0 +1,42 @@
import re
import requests
import subprocess
import sys

KEYWORDS = ['fixes', 'closes', 're', 'ref']
NO_ISSUE = '#noissue'
STATUSES = ['NEW', 'ASSIGNED', 'POST']

sha = sys.argv[1]
message = subprocess.check_output(['git', 'log', '--format=%B', '-n 1', sha]).decode('utf-8')


def check_status(issue):
response = requests.get('https://pulp.plan.io/issues/{}.json'.format(issue))
response.raise_for_status()
bug_json = response.json()
status = bug_json['issue']['status']['name']
if status not in STATUSES:
sys.exit("Error: issue #{issue} has invalid status of {status}. Status must be one of "
"{statuses}.".format(issue=issue, status=status, statuses=", ".join(STATUSES)))


print("Checking commit message for {sha}.".format(sha=sha[0:7]))

# validate the issue attached to the commit
if NO_ISSUE in message:
print("Commit {sha} has no issue attached. Skipping issue check".format(sha=sha[0:7]))
else:
regex = r'(?:{keywords})[\s:]+#(\d+)'.format(keywords=('|').join(KEYWORDS))
pattern = re.compile(regex)

issues = pattern.findall(message)

if issues:
for issue in pattern.findall(message):
check_status(issue)
else:
sys.exit("Error: no attached issues found for {sha}. If this was intentional, add "
" '{tag}' to the commit message.".format(sha=sha[0:7], tag=NO_ISSUE))

print("Commit message for {sha} passed.".format(sha=sha[0:7]))
8 changes: 6 additions & 2 deletions docs/contributing/git.rst
Expand Up @@ -74,9 +74,13 @@ To update the issue's state to MODIFIED and set the %done to 100, use
fixes #123
closes #123

You can also reference multiple issues in a commit::
To reference multiple issues in a commit use a separate line for each one::

fixes #123, #124
fixes #123
fixes #124

We strongly suggest that each commit is attached to an issue in Redmine. However, if you must create
a commit for which there is no issue, add the tag ``#noissue`` to the commit's message.

Putting this all together, the following is an example of a good commit message::

Expand Down