From: Neil Muller Date: Mon, 9 Mar 2020 13:11:59 +0000 (+0200) Subject: Add slack hook X-Git-Url: https://git.ctpug.org.za/?a=commitdiff_plain;h=4ffd5e46ac227a7bfec52537ad8213b0c3ba4471;p=gitolite-hooks.git Add slack hook --- diff --git a/slack b/slack new file mode 100644 index 0000000..e83153c --- /dev/null +++ b/slack @@ -0,0 +1,284 @@ +#!/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 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