Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
gitolite update hooks to reject CRLF line endings and require formatted commit messages
#!/bin/bash
#
# see https://github.com/kahseng/redmine_gitolite_hook/blob/master/README.rdoc
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated. It is passed arguments in through
# stdin in the form
# <oldrev> <newrev> <refname>
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
REDMINE_SERVER=https://www.example.com/redmine
FETCH_URL=sys/fetch_changesets
APIKEY=YOUR_REDMINE_WS_API_KEY
# Project identifier defaults to repo name, but can be mapped
PROJECT="$GL_REPO"
MAP=( "foo:foo2"
"bar:baz" )
# Above can be overridden in ~/.redmine file
if [ -f ~/.redmine ]; then
. ~/.redmine
fi
for repomap in ${MAP[@]}; do
REPO=${repomap%%:*}
_PROJECT=${repomap#*:}
if [ "$GL_REPO" = "$REPO" ]; then
PROJECT="$_PROJECT"
break
fi
done
echo "Updating redmine project for $GL_REPO: $PROJECT"
lockfile=/tmp/redmine-update-${PROJECT//\//-}
if [ -f $lockfile ]; then
echo "$PROJECT is already being updated.."
echo "$PROJECT is already being updated.." >> /tmp/redmine-update.log
exit
fi
update_redmine() {
touch $lockfile
curl -k -s "$REDMINE_SERVER/$FETCH_URL?id=$PROJECT&key=$APIKEY" > /dev/null
rm $lockfile
echo $(date) Update $PROJECT completed >> /tmp/redmine-update.log
}
update_redmine &
disown -h
#!/bin/bash
$GL_BINDIR/hooks/update-reject-crlf $@ || exit 1
$GL_BINDIR/hooks/update-require-issue $@ || exit 1
exit 0
#!/bin/bash
#
# An "update" hook which rejects any update containing CRLF.
#
# Author: Gerhard Gappmeier, ascolab GmbH
# Author: Colin Mollenhour
#
# This script is based on the update.sample in git/contrib/hooks.
# You are free to use this script for whatever you want.
#
BINARY_REGEX='\.(pdb|dll|exe|png|gif|jpg|mwb|zip|tgz|gz|bz2|7z|rar|swf|fla|jar|mo|ttf|foo|mp3|icc|pdf|bmp|wmf|otf|eot|woff|phar|ico)$'
NO_EXTENSION_REGEX='/\w+$'
OVERRIDE_REGEX='Contains CRLF'
refname="$1"
oldrev="$2"
newrev="$3"
BADREV="0000000000000000000000000000000000000000"
[ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ] && \
{ echo "Usage: $0 <ref> <oldrev> <newrev>" >&2; exit 1; }
# Skip checks on branch deletions
[ "$newrev" = "$BADREV" ] && exit 0
# Skip checks on tag pushes
[[ $refname =~ ^refs\/tags\/ ]] && exit 0
FIRST=""
ERRORS=""
CR=$(printf "\r")
# Enable case-insensitive matching for file extensions
shopt -s nocasematch
for rev in $(git rev-list --reverse "$newrev" $(git for-each-ref --format='%(refname)' "refs/heads/*" | sed 's/^/\^/'))
do
# skip when commit mesage contains override
MESSAGE=$(git show -s --format=format:"%s" $rev)
[[ $MESSAGE =~ $OVERRIDE_REGEX ]] && continue
IS_BAD=0
while read old_mode new_mode old_sha1 new_sha1 status name
do
# skip lines showing parent commit and deletions
[[ -z "$new_sha1" ]] || [ "$new_sha1" = "$BADREV" ] && continue
# don't do a CRLF check for binary files
[[ $name =~ $BINARY_REGEX ]] && continue
# Skip pngs and executables without extensions
if [[ $name =~ $NO_EXTENSION_REGEX ]]; then
tmp=$(mktemp -t git-crlf.XXXXXXX)
git cat-file blob $new_sha1 > $tmp
<$tmp head -n 1 | grep -Fq "PNG" && { rm -f $tmp; continue; }
file $tmp | grep -Fq "executable" && { rm -f $tmp; continue; }
rm -f $tmp
fi
# check for CRLF
if git cat-file blob $new_sha1 | grep -Eq "$CR$"; then
if [ "$FIRST" = "" ]; then FIRST=$rev; fi
if [ $IS_BAD -eq 0 ]; then IS_BAD=1; ERRORS="${ERRORS}CRLF DETECTED IN ${rev:0:7}:\n"; fi
ERRORS="${ERRORS} $name\n"
fi
done < <(git diff-tree -r "$rev")
done
if [ "$FIRST" != "" ]; then
echo "###################################################################"
echo "# One or more files contained CRLF (Windows) line endings which are"
echo "# not allowed. Activate the autocrlf feature and/or change the line"
echo "# endings to LF before committing and before trying to push. You "
echo "# will have to amend your existing commits to not contain CRLF. "
echo "# \"git config core.autocrlf true\" to activate CRLF conversion."
echo "# \"git commit --amend\" to change your most recent commit."
echo "# \"git rebase -i ${FIRST:0:7}^\" to change all commits."
echo "###################################################################"
echo -e "$ERRORS"
exit 1
fi
#!/bin/bash
#
# An "update" hook which rejects any update with poor commit messages.
#
# Author: Colin Mollenhour
#
ISSUE_REGEX='\s*(refs|references|ticket|issue|feature|bug|task|fixes|closes|fixed) \#([0-9]+)[.:,]?\s*'
NO_ISSUE_REGEX='noref'
NO_ISSUE_GL_USER_REGEX='^(www-data)$'
NO_ISSUE_AUTHOR_EMAIL_REGEX='^(colin@.*mollenhour\.com|matt\.davenport@bss-llc\.com)$'
DEVELOP_MESSAGE_REGEX="into '?develop'?|develop'? into"
DEVELOP_REFNAME_REGEX='develop$'
MYSQL='mysql'
# Add authentication or put authentication in ~/.my.cnf
#MYSQL="$MYSQL -u redmine -pPASSWORD"
refname="$1"
oldrev="$2"
newrev="$3"
#echo "DEBUG - refname: $1, oldrev: $2, newrev: $3"
sep="---------------------------------------------"
function die { echo -e "$1" 1>&2; exit 1; }
[ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ] && \
die "Usage: $0 <ref> <oldrev> <newrev>"
[ -z "$GL_USER" ] && \
die "Gitolite user is not defined."
# Skip checks on branch deletions
[ "$newrev" = "0000000000000000000000000000000000000000" ] && exit 0
# Skip checks on tag pushes
[[ $refname =~ ^refs\/tags\/ ]] && exit 0
function reject {
die "
Your commit message was rejected for the following reason:
$1
$sep
$SHORT: $MESSAGE
$sep
HINT: Use 'git commit --amend' to modify your last commit or 'git rebase -i $SHORT^' to
modify all commits up to and including the offending one.
"
}
for REF in $(git rev-list --reverse "$newrev" $(git for-each-ref --format='%(refname)' "refs/heads/*" | sed 's/^/\^/')); do
SHORT=${REF:0:7}
MESSAGE=$(git show -s --format=format:"%s%+b" $REF | tr '\n' ' ')
AUTHOR_EMAIL=$(git show -s --format=format:"%ae" $REF)
shopt -s nocasematch
# Make sure the author email is populated
[ -z $AUTHOR_EMAIL ] && \
reject "You must configure your name and email address."
# Make sure that the log message contains some text.
[[ $MESSAGE =~ [a-zA-Z0-9]+ ]] || \
reject "You must supply a descriptive commit message."
# Allow an issue reference to be omitted if "noref" is added to message
if [[ $MESSAGE =~ $NO_ISSUE_REGEX ]]; then
[ -z $NO_ISSUE_GL_USER_REGEX ] && [ -z $NO_ISSUE_AUTHOR_EMAIL_REGEX ] && \
continue
[ -n $NO_ISSUE_GL_USER_REGEX ] && [[ $GL_USER =~ $NO_ISSUE_GL_USER_REGEX ]] && \
continue
[ -n $NO_ISSUE_AUTHOR_EMAIL_REGEX ] && [[ $AUTHOR_EMAIL =~ $NO_ISSUE_AUTHOR_EMAIL_REGEX ]] && \
continue
fi
# Reject merging develop into other branches
[[ $MESSAGE =~ $DEVELOP_MESSAGE_REGEX ]] && \
[[ ! $refname =~ $DEVELOP_REFNAME_REGEX ]] && \
reject "Develop branch may not be merged into other branches."
# Skip merge commits and commits that do nothing
NUMPARENTS=$(git cat-file -p $REF | grep '^parent ' | wc -l)
[ $NUMPARENTS -gt 1 -o "$(git diff --stat $REF $REF^)" == "" ] && \
continue
# Make sure that the log message references a Redmine issue.
[[ $MESSAGE =~ $ISSUE_REGEX ]] || \
reject "You must specify a Redmine issue number matching the following pattern:\n$ISSUE_REGEX\nExample: Issue #123, Refs #123, Fixes #123"
# Make sure the referenced issue actually exists
REDMINE_ISSUE=${BASH_REMATCH[2]}
REDMINE_ISSUE_EXISTS=$(${MYSQL} -N redmine -e "SELECT COUNT(*) FROM issues I WHERE I.id = ${REDMINE_ISSUE};")
[[ ${REDMINE_ISSUE_EXISTS} -ne 0 ]] || \
reject "Issue #${REDMINE_ISSUE} does not exist."
# Check message length, ignoring issue refs
MSGNOREF=${MESSAGE/${BASH_REMATCH[0]}}
[[ ${#MSGNOREF} -gt 10 ]] || \
reject "Your commit message \"$MSGNOREF\" is too short. Be more descriptive."
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment