--- /dev/null
+#!/bin/bash
+#
+# Slack (slack.com) notification post-receive hook.
+#
+# Based on: https://github.com/joemiller/git-hooks Campfire notification post-receive hook. Author: Joe Miller
+# (http://joemiller.me)
+#
+# Based on post-receive.irc by Mikael Fridh <frimik@gmail.com> https://gist.github.com/1821358
+#
+
+function help() {
+ echo "Required config settings:"
+ echo " git config hooks.slack.webhook-url 'https://hooks.slack.com/services/...'"
+ echo " git config hooks.slack.channel 'general'"
+ echo " git config hooks.slack.show-only-last-commit 'true' #optional"
+ echo " git config hooks.slack.username 'git' #optional"
+ echo " git config hooks.slack.icon-url 'http://imgur/icon.png' #optional"
+ echo " git config hooks.slack.icon-emoji ':twisted_rightwards_arrows:' #optional"
+ echo " git config hooks.slack.repo-nice-name 'MyRepo' #optional"
+ echo " git config hooks.slack.repos-root '/path/to/repos' #optional"
+ echo " git config hooks.slack.changeset-url-pattern 'http://yourserver/%repo_path%/changeset/%rev_hash
+%' #optional"
+ echo " git config hooks.slack.compare-url-pattern 'http://yourserver/%repo_path%/changeset/%old_rev_ha
+sh%..%new_rev_hash%' #optional"
+}
+
+function notify_slack() {
+ oldrev=$(git rev-parse $1)
+ newrev=$(git rev-parse $2)
+ refname="$3"
+
+ # --- Interpret
+ # 0000->1234 (create)
+ # 1234->2345 (update)
+ # 2345->0000 (delete)
+ if expr "$oldrev" : '0*$' >/dev/null
+ then
+ change_type="create"
+ else
+ if expr "$newrev" : '0*$' >/dev/null
+ then
+ change_type="delete"
+ else
+ change_type="update"
+ fi
+ fi
+
+ # --- Get the revision types
+ newrev_type=$(git cat-file -t $newrev 2> /dev/null)
+ oldrev_type=$(git cat-file -t "$oldrev" 2> /dev/null)
+ case "$change_type" in
+ create|update)
+ rev="$newrev"
+ rev_type="$newrev_type"
+ ;;
+ delete)
+ rev="$oldrev"
+ rev_type="$oldrev_type"
+ ;;
+ esac
+
+ # The revision type tells us what type the commit is, combined with
+ # the location of the ref we can decide between
+ # - working branch
+ # - tracking branch
+ # - unannoted tag
+ # - annotated tag
+ case "$refname","$rev_type" in
+ refs/tags/*,commit)
+ # un-annotated tag
+ refname_type="tag"
+ short_refname=${refname##refs/tags/}
+ ;;
+ refs/tags/*,tag)
+ # annotated tag
+ refname_type="annotated tag"
+ short_refname=${refname##refs/tags/}
+ # change recipients
+ if [ -n "$announcerecipients" ]; then
+ recipients="$announcerecipients"
+ fi
+ ;;
+ refs/heads/*,commit)
+ # branch
+ refname_type="branch"
+ short_refname=${refname##refs/heads/}
+ ;;
+ refs/remotes/*,commit)
+ # tracking branch
+ refname_type="tracking branch"
+ short_refname=${refname##refs/remotes/}
+ echo >&2 "*** Push-update of tracking branch, $refname"
+ echo >&2 "*** - no notification generated."
+ return 0
+ ;;
+ *)
+ # Anything else (is there anything else?)
+ echo >&2 "*** Unknown type of update to $refname ($rev_type)"
+ echo >&2 "*** - no notification generated"
+ return 0
+ ;;
+ esac
+ # plural suffix, default "", changed to "s" if commits > 1
+ s=""
+
+ # Repo name, either Gitolite or normal repo.
+ if [ -n "$GL_REPO" ]; then
+ # it's a gitolite repo
+ repodir=$(basename `pwd`)
+ repo=$GL_REPO
+ else
+ repodir=$(basename `pwd`)
+ if [ "$repodir" == ".git" ]; then
+ repodir=`dirname $PWD`
+ repodir=`basename $repodir`
+ fi
+ repo=${repodir%.git}
+ fi
+
+ repoprefix=$(git config hooks.slack.repo-nice-name || git config hooks.irc.prefix || git config hooks.emailprefix || echo "$repo")
+ onlylast=`git config --get hooks.slack.show-only-last-commit`
+ onlylast=$onlylast && [ -n "$onlylast" ]
+
+ # Get the user information
+ # If $GL_USER is set we're running under gitolite.
+ if [ -n "$GL_USER" ]; then
+ user=$GL_USER
+ else
+ user=$USER
+ fi
+
+ case ${change_type} in
+ "create")
+ header="New ${refname_type} *${short_refname}* has been created in ${repoprefix}"
+ single_commit_suffix="commit"
+ ;;
+ "delete")
+ header="$(tr '[:lower:]' '[:upper:]' <<< ${refname_type:0:1})${refname_type:1} *$short_refname* has been deleted from ${repoprefix}"
+ single_commit_suffix="commit"
+ ;;
+ "update")
+ num=$(git log --pretty=oneline ${1}..${2}|wc -l|tr -d ' ')
+ branch=${3/refs\/heads\//}
+
+ if [ ${num} -gt 1 ]; then
+ header="${num} new commits *pushed* to *${short_refname}* in ${repoprefix}"
+ single_commit_suffix="one"
+ s="s"
+ else
+ header="A new commit has been *pushed* to *${short_refname}* in ${repoprefix}"
+ single_commit_suffix="one"
+ fi
+
+ ;;
+ *)
+ # most weird ... this should never happen
+ echo >&2 "*** Unknown type of update to $refname ($rev_type)"
+ echo >&2 "*** - notifications will probably screw up."
+ ;;
+ esac
+ if $onlylast && [[ "${change_type}" != "delete" ]]; then
+ header="$header, showing last $single_commit_suffix:"
+ fi
+
+
+ if [[ "${change_type}" != "delete" && "${refname_type}" == "branch" ]]; then
+ changeseturlpattern=`git config --get hooks.slack.changeset-url-pattern`
+ compareurlpattern=`git config --get hooks.slack.compare-url-pattern`
+ reporoot=`git config --get hooks.slack.repos-root`
+
+ urlformat=
+ if [ -n "$changeseturlpattern" -a -n "$reporoot" ]; then
+ if [[ $PWD == ${reporoot}* ]]; then
+ repopath=$PWD
+ base=`basename $PWD`
+ if [ "$base" == ".git" ]; then
+ repopath=`dirname $repopath`
+ fi
+ idx=`echo $reporoot | wc -c | tr -d ' '`
+ repopath=`echo $repopath | cut -c$idx-`
+ urlformat=`echo $changeseturlpattern | sed "s|%repo_path%|$repopath|g" | sed "s/%rev_hash%/%H/g"`
+
+ if [ -n "$compareurlpattern" ]; then
+ comparelink=`echo $compareurlpattern | sed "s|%repo_path%|$repopath|g" | sed "s|%old_rev_hash%|$oldrev|g" | sed "s|%new_rev_hash%|$newrev|g"`
+ header=`echo $header | sed -e "s|\([a-zA-Z0-9]\{1,\} new commit[s]\{0,1\}\)|\<$comparelink\|\\1\>|"`
+ fi
+ else
+ echo >&2 "$PWD is not in $reporoot. Not creating hyperlinks."
+ fi
+ fi
+
+ formattedurl=""
+ if [ -n "$urlformat" ]; then
+ formattedurl="<${urlformat}|%h> "
+ fi
+
+
+ nl="\\\\n"
+
+ if [[ "${change_type}" == "update" ]]; then
+ start="${1}"
+ else
+ start="HEAD"
+ fi
+
+ end="${2}"
+
+ # merge `git log` output with $header
+ if $onlylast; then
+ countarg="-n 1"
+ else
+ countarg=""
+ fi
+
+ # Process the log and escape double quotes; assuming for now that committer names don't have five semicolons in them
+ log_out=$( git log --pretty=format:"%cN;;;;;${formattedurl}%s" $countarg ${start}..${end} \
+ | sed -e 's/\\/\\\\/g' \
+ | sed -e 's/"/\\"/g' \
+ | sed -e 's/\(.*\);;;;;\(.*\)/{"title":"\1","value":"\2","short":false},/' )
+
+ fields=${log_out%?}
+
+ attachments="[{ \"fallback\" : \"${header}\", \"color\" : \"good\", \"fields\" : [${fields}]}]"
+ fi
+
+ if [ -n "${attachments}" ] && [[ "${attachments}" != "" ]]; then
+ msg=$(echo -e "\"text\":\"${header}\", \"attachments\" : $attachments")
+ else
+ msg=$(echo -e "\"text\":\"${header}\"")
+ fi
+
+ # slack API uses \n substitution for newlines
+ # msg=$(echo "${msg}" | perl -p -e 's/\+/+/mg')
+
+ webhook_url=$(git config --get hooks.slack.webhook-url)
+ channel=$(git config --get hooks.slack.channel)
+ username=$(git config --get hooks.slack.username)
+ iconurl=$(git config --get hooks.slack.icon-url)
+ iconemoji=$(git config --get hooks.slack.icon-emoji)
+
+ if [ -z "$webhook_url" ] || [ -z "$channel" ]; then
+ echo "ERROR: config settings not found"
+ help
+ exit 1
+ fi
+
+ payload="{${msg}, \"channel\": \"#$channel\""
+
+ if [ -n "$username" ]; then
+ payload="$payload, \"username\": \"$username\""
+ fi
+
+ if [ -n "$iconurl" ]; then
+ payload="$payload, \"icon_url\": \"$iconurl\""
+ elif [ -n "$iconemoji" ]; then
+ payload="$payload, \"icon_emoji\": \"$iconemoji\""
+ fi
+
+ payload="$payload}"
+
+ if [ -n "$DEBUG" ]; then
+ echo "POST $webhook_url"
+ echo "payload=$payload"
+ return
+ fi
+
+ curl -s \
+ -d "payload=$payload" \
+ "$webhook_url" \
+ >/dev/null
+}
+
+webhook_url=$(git config --get hooks.slack.webhook-url)
+
+while read line; do
+ set -- $line
+ if [ -n "$webhook_url" ]; then
+ notify_slack $*
+ fi
+
+ RET=$?
+done
+
+exit $RET