Fix syntax errors
[gitolite-hooks.git] / discord
1 #!/bin/bash
2 #
3 # Discord hook using discord's 'slack compatible' endpoint
4 #
5 # Based on: https://github.com/joemiller/git-hooks Campfire notification post-receive hook. Author: Joe Miller
6 # (http://joemiller.me)
7 #
8 # Based on post-receive.irc by Mikael Fridh <frimik@gmail.com> https://gist.github.com/1821358
9 #
10
11 function help_discord () {
12   echo "Required config settings:"
13   echo " git config hooks.discord.webhook-url 'https://discord.com/api/webhooks/...'"
14   echo " git config hooks.discord.show-only-last-commit 'true' #optional"
15   echo " git config hooks.discord.username 'git' #optional"
16   echo " git config hooks.discord.repo-nice-name 'MyRepo' #optional"
17   echo
18   echo " The webhook url shoud be that returned by the create step - the notifier"
19   echo "   will add the required parameters to hit the slack-compatible endpoint"
20
21 }
22
23 function notify_discord() {
24   oldrev=$(git rev-parse $1)
25   newrev=$(git rev-parse $2)
26   refname="$3"
27
28   # --- Interpret
29   # 0000->1234 (create)
30   # 1234->2345 (update)
31   # 2345->0000 (delete)
32   if expr "$oldrev" : '0*$' >/dev/null
33   then
34     change_type="create"
35   else
36     if expr "$newrev" : '0*$' >/dev/null
37     then
38       change_type="delete"
39     else
40       change_type="update"
41     fi
42   fi
43
44   # --- Get the revision types
45   newrev_type=$(git cat-file -t $newrev 2> /dev/null)
46   oldrev_type=$(git cat-file -t "$oldrev" 2> /dev/null)
47   case "$change_type" in
48     create|update)
49       rev="$newrev"
50       rev_type="$newrev_type"
51       ;;
52     delete)
53       rev="$oldrev"
54       rev_type="$oldrev_type"
55       ;;
56   esac
57
58   # The revision type tells us what type the commit is, combined with
59   # the location of the ref we can decide between
60   #  - working branch
61   #  - tracking branch
62   #  - unannoted tag
63   #  - annotated tag
64   case "$refname","$rev_type" in
65     refs/tags/*,commit)
66       # un-annotated tag
67       refname_type="tag"
68       short_refname=${refname##refs/tags/}
69       ;;
70     refs/tags/*,tag)
71       # annotated tag
72       refname_type="annotated tag"
73       short_refname=${refname##refs/tags/}
74       # change recipients
75       if [ -n "$announcerecipients" ]; then
76         recipients="$announcerecipients"
77       fi
78       ;;
79     refs/heads/*,commit)
80       # branch
81       refname_type="branch"
82       short_refname=${refname##refs/heads/}
83       ;;
84     refs/remotes/*,commit)
85       # tracking branch
86       refname_type="tracking branch"
87       short_refname=${refname##refs/remotes/}
88       echo >&2 "*** Push-update of tracking branch, $refname"
89       echo >&2 "***  - no notification generated."
90       return 0
91       ;;
92     *)
93       # Anything else (is there anything else?)
94       echo >&2 "*** Unknown type of update to $refname ($rev_type)"
95       echo >&2 "***  - no notification generated"
96       return 0
97       ;;
98   esac
99   # plural suffix, default "", changed to "s" if commits > 1
100   s=""
101
102   # Repo name, either Gitolite or normal repo.
103   if [ -n "$GL_REPO" ]; then
104     # it's a gitolite repo
105     repodir=$(basename `pwd`)
106     repo=$GL_REPO
107   else
108     repodir=$(basename `pwd`)
109     if [ "$repodir" == ".git" ]; then
110       repodir=`dirname $PWD`
111       repodir=`basename $repodir`
112     fi
113     repo=${repodir%.git}
114   fi
115
116   repoprefix=$(git config hooks.discord.repo-nice-name || git config hooks.irc.prefix || git config hooks.emailprefix || echo "$repo")
117   onlylast=`git config --get hooks.discord.show-only-last-commit`
118   onlylast=$onlylast && [ -n "$onlylast" ]
119
120   # Get the user information
121   # If $GL_USER is set we're running under gitolite.
122   if [ -n "$GL_USER" ]; then
123     user=$GL_USER
124   else
125     user=$USER
126   fi
127
128   case ${change_type} in
129     "create")
130       header="New ${refname_type} *${short_refname}* has been created in ${repoprefix}"
131       single_commit_suffix="commit"
132       ;;
133     "delete")
134       header="$(tr '[:lower:]' '[:upper:]' <<< ${refname_type:0:1})${refname_type:1} *$short_refname* has been deleted from ${repoprefix}"
135       single_commit_suffix="commit"
136       ;;
137     "update")
138       num=$(git log --pretty=oneline ${1}..${2}|wc -l|tr -d ' ')
139       branch=${3/refs\/heads\//}
140
141       if [ ${num} -gt 1 ]; then
142         header="${num} new commits *pushed* to *${short_refname}* in ${repoprefix}"
143         single_commit_suffix="one"
144         s="s"
145       else
146         header="A new commit has been *pushed* to *${short_refname}* in ${repoprefix}"
147         single_commit_suffix="one"
148       fi
149
150       ;;
151     *)
152       # most weird ... this should never happen
153       echo >&2 "*** Unknown type of update to $refname ($rev_type)"
154       echo >&2 "***  - notifications will probably screw up."
155       ;;
156   esac
157   if $onlylast && [[ "${change_type}" != "delete" ]]; then
158     header="$header, showing last $single_commit_suffix:"
159   fi
160
161
162   if [[ "${change_type}" != "delete" && "${refname_type}" == "branch" ]]; then
163     reporoot=`git config --get hooks.discord.repos-root`
164
165     urlformat=
166
167     formattedurl=""
168     if [ -n "$urlformat" ]; then
169       formattedurl="<${urlformat}|%h> "
170     fi
171
172
173     nl="\\\\n"
174
175     if [[ "${change_type}" == "update" ]]; then
176       start="${1}"
177     else
178       start="HEAD"
179     fi
180
181     end="${2}"
182
183     # merge `git log` output with $header
184     if $onlylast; then
185       countarg="-n 1"
186     else
187       countarg=""
188     fi
189
190     # Process the log and escape double quotes; assuming for now that committer names don't have five semicolons in them
191     log_out=$( git log --pretty=format:"%cN;;;;;${formattedurl}%s" $countarg ${start}..${end} \
192              | sed -e 's/\\/\\\\/g' \
193              | sed -e 's/"/\\"/g' \
194              | sed -e 's/\(.*\);;;;;\(.*\)/{"title":"\1","value":"\2","short":false},/' )
195
196     fields=${log_out%?}
197
198     attachments="[{ \"fallback\" : \"${header}\", \"color\" : \"good\", \"fields\" : [${fields}]}]"
199   fi
200
201   if [ -n "${attachments}" ] && [[ "${attachments}" != "" ]]; then
202     msg=$(echo -e "\"text\":\"${header}\", \"attachments\" : $attachments")
203   else
204     msg=$(echo -e "\"text\":\"${header}\"")
205   fi
206
207   # slack API uses \n substitution for newlines
208   # msg=$(echo "${msg}" | perl -p -e 's/\+/&#43;/mg')
209
210   webhook_url=$(git config --get hooks.discord.webhook-url)
211   username=$(git config --get hooks.discord.username)
212
213   if [ -z "$webhook_url" ]; then
214     echo "ERROR: config settings not found"
215     help
216     exit 1
217   fi
218
219   webhook_url="$webhook_url/slack"
220
221   payload="{${msg}"
222
223   if [ -n "$username" ]; then
224     payload="$payload, \"username\": \"$username\""
225   fi
226
227   payload="$payload}"
228
229   if [ -n "$DEBUG" ]; then
230     echo "POST $webhook_url"
231     echo "payload=$payload"
232     return
233   fi
234
235   curl -s \
236       -d "payload=$payload" \
237       "$webhook_url" \
238       >/dev/null
239 }