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