Add modified version of the slack webhook for discord
authorNeil Muller <drnlmuller@gmail.com>
Mon, 1 Feb 2021 10:39:06 +0000 (12:39 +0200)
committerNeil Muller <drnlmuller@gmail.com>
Mon, 1 Feb 2021 13:02:57 +0000 (15:02 +0200)
Use discord 'slack compatible' endpoint to simplify supporting discord
notifications.

discord [new file with mode: 0755]
post-receive

diff --git a/discord b/discord
new file mode 100755 (executable)
index 0000000..a599869
--- /dev/null
+++ b/discord
@@ -0,0 +1,239 @@
+#!/bin/bash
+#
+# Discord hook using discord's 'slack compatible' endpoint
+#
+# 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_discord () {
+  echo "Required config settings:"
+  echo " git config hooks.discord.webhook-url 'https://discord.com/api/webhooks/...'"
+  echo " git config hooks.discord.show-only-last-commit 'true' #optional"
+  echo " git config hooks.discord.username 'git' #optional"
+  echo " git config hooks.discord.repo-nice-name 'MyRepo' #optional"
+  echo
+  echo " The webhook url shoud be that returned by the create step - the notifier"
+  echo "   will add the required parameters to hit the slack-compatible endpoint"
+
+}
+
+function notify_discord() {
+  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.discord.repo-nice-name || git config hooks.irc.prefix || git config hooks.emailprefix || echo "$repo")
+  onlylast=`git config --get hooks.discord.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
+    reporoot=`git config --get hooks.discord.repos-root`
+
+    urlformat=
+
+    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/\+/&#43;/mg')
+
+  webhook_url=$(git config --get hooks.discord.webhook-url)
+  username=$(git config --get hooks.discord.username)
+
+  if [ -z "$webhook_url" ]; then
+    echo "ERROR: config settings not found"
+    help
+    exit 1
+  fi
+
+  webhook_url="$webook_url/slack"
+
+  payload="{${msg}, "
+
+  if [ -n "$username" ]; then
+    payload="$payload, \"username\": \"$username\""
+  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
+}
index 3aeae3572f0315bbad6453a8416b2f0705d74134..46cd464bedc67afc9a1f0243c0bc41d9778da14b 100755 (executable)
@@ -4,20 +4,26 @@ HOOKDIR=$(dirname $0)
 # Load functions
 . $HOOKDIR/irker
 . $HOOKDIR/slack
+. $HOOKDIR/discord
 
 
 channels=$(git config --get irker.channels)
 
-webhook_url=$(git config --get hooks.slack.webhook-url)
+slack_url=$(git config --get hooks.slack.webhook-url)
+
+discord_url=$(git config --get hooks.discord.webhook-url)
 
 while read line; do
     set -- $line
     if [ -n "$channels" ]; then
         notify_irker $*
      fi
-     if [ -n "$webhook_url" ]; then
+     if [ -n "$slack_url" ]; then
         notify_slack $*
      fi
+     if [ -n "$discord_url" ]; then
+        notify_discord $*
+     fi
      RET=$?
 done
 exit $RET