blob: d703b6ac4be22eeef8bf93f101f9548cebfbc36a [file] [log] [blame]
Luigi Santivetti33376db2020-10-17 00:18:03 +01001#!/bin/bash
2#
3# change-merged hook
4#
5# Copyright 2020 Luigi Santivetti <luigi.santivetti@gmail.com>
6
7# Permission is hereby granted, free of charge, to any person obtaining a
8# copy of this software and associated documentation files (the "Software"),
9# to deal in the Software without restriction, including without limitation
10# the rights to use, copy, modify, merge, publish, distribute, sublicense,
11# and/or sell copies of the Software, and to permit persons to whom the
12# Software is furnished to do so, subject to the following conditions:
13
14# The above copyright notice and this permission notice (including the next
15# paragraph) shall be included in all copies or substantial portions of the
16# Software.
17
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21# ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25# change-merged
26#
27# --change <change id>
28# --change-url <change url>
29# --change-owner <change owner>
30# --change-owner-username <username>
31# --project <project name>
32# --branch <branch>
33# --topic <topic>
34# --submitter <submitter>
35# --submitter-username <username>
36# --commit <sha1>
37# --newrev <sha1>
38#
39# RATIONALE: change-merged can propagate one or more changes landing into
40# Gerrit to an external mirror. Be noted, this is an async hook that runs
41# in the background.
42#
43# ` remote-update hook ` TODO
44# ` `
45# ` `
46# (1) merge ` (2) push ` (3) push
47# +--------+ +--------+ +--------+
48# | Gerrit | ··········> | Gerrit | ··········> | Mirror | ··········>
49# +--------+ +--------+ +--------+
50# ` `
51# ` `
52# ` `
53# ` `
54
55LOG_FILE=${HOOKS_LOG_DIR:-/tmp}
56if [ ! -w "$LOG_FILE" ]; then
57 LOG_FILE="/dev/null" # avoid permission denied
58else
59 LOG_FILE="$LOG_FILE/hooks.change-merged-$(date +'%d%m%Y%H%M%S').txt"
60fi
61
62# Host service where replication mirrors and deploy engine live
63HOOK_HOST=${HOOKS_REMOTE_HOST:-}
64if [ ! -n "$HOOK_HOST" ]; then
65 echo " ****** warning: no host, skip hook" &> ${LOG_FILE}
66 exit 1
67fi
68
69# User allowed t othe target host to push and eventually deploy changes
70HOOK_USER=${HOOKS_REMOTE_USER:-}
71if [ ! -n "$HOOK_USER" ]; then
72 echo " ****** warning: no user, skip hook" &> ${LOG_FILE}
73 exit 1
74fi
75
76# Directory where this hook expects the project mirror to be located
77HOOK_PATH=${HOOKS_REMOTE_PATH:-}
78if [ ! -n "$HOOK_PATH" ]; then
79 echo " ****** warning: no path, skip hook" &> ${LOG_FILE}
80 exit 1
81fi
82
83# Alias for the remote tracking a given mirror
84GERRIT_R=${HOOKS_REMOTE_ALIAS:-}
85if [ ! -n "$GERRIT_R" ]; then
86 echo " ****** warning: no remote alias, skip hook" &> ${LOG_FILE}
87 exit 1
88fi
89
90SSH_RSA_ID=${HOOKS_REMOTE_RSAID:-}
91if [ ! -n "$SSH_RSA_ID" ]; then
92 echo " ****** error: no rsa id file found" &> ${LOG_FILE}
93 exit 1
94fi
95
96SSH_PORT=${HOOKS_REMOTE_PORT:-22}
97if [ ! -n "$SSH_PORT" ]; then
98 echo " ****** warning: no ssh port, default to 22" &> ${LOG_FILE}
99fi
100
101GERRIT_PORT=${HOOKS_GERRIT_PORT:-29418}
102if [ ! -n "$GERRIT_PORT" ]; then
103 echo " ****** warning: no Gerrit port, default to 29418" &> ${LOG_FILE}
104fi
105
106GERRIT_HOST=${HOOKS_GERRIT_HOST:-}
107if [ ! -n "$GERRIT_HOST" ]; then
108 echo " ****** warning: no Gerrit host, skip notify" &> ${LOG_FILE}
109fi
110
111DEPLOY_EXEC=${HOOKS_DEPLOY_EXEC:-}
112if [ ! -n "${DEPLOY_EXEC}" ]; then
113 echo " ****** warning: no deploy exec, skip deploy" &> ${LOG_FILE}
114fi
115
116/bin/bash <(/bin/cat <<EOF
117set -x
118args='${*}'
119
120declare -A CHANGE=(
121 [change]=""
122 [change-url]=""
123 [change-owner]=""
124 [change-owner-username]=""
125 [project]=""
126 [branch]=""
127 [topic]=""
128 [submitter]=""
129 [submitter-username]=""
130 [commit]=""
131 [newrev]=""
132)
133
134while read -a line; do
135 for K in \${!CHANGE[@]}; do
136 if [ "\${line[0]}" == "--\$K" ]; then
137 CHANGE[\$K]="\${line[@]:1}"
138 break
139 fi
140 done
141done <<< "\$(echo -e "\${args// --/\\\\n--}")"
142
143SSH_COMMAND="ssh"
144SSH_COMMAND+=" -o StrictHostKeyChecking=no"
145SSH_COMMAND+=" -o UserKnownHostsFile=/dev/null"
146SSH_COMMAND+=" -i $SSH_RSA_ID"
147
148function gerrit_cli
149{
150 \$SSH_COMMAND -p $GERRIT_PORT \${CHANGE[submitter-username]}@$GERRIT_HOST gerrit \${@}
151}
152
153remote_url="ssh://$HOOK_USER@$HOOK_HOST:$HOOK_PATH/\${CHANGE[project]}.git"
154
155# Does Gerrit have \\\$git_dir remote set up?
156git remote get-url "$GERRIT_R" | grep -q -- "\$remote_url"
157if [ "\$?" -ne 0 ]; then
158 echo >&2 " ****** error: \${CHANGE[project]} remote not found: $GERRIT_R"
159 echo >&2 " ****** error: \${CHANGE[branch]} not pushed, skip hook"
160 exit 1
161fi
162
163# Get patchset info
164NUMBERS=\$(gerrit_cli query \${CHANGE[commit]} --patch-sets | grep -- number)
165
166# Get patch number and patchset number
167patchnum=\$(printf "%s\n" "\$NUMBERS" | head -n1 | cut -f 2 -d ':')
168patchset=\$(printf "%s\n" "\$NUMBERS" | tail -n1 | cut -f 2 -d ':')
169
170# Trim whitespaces
171patchnum=\${patchnum//\ /}
172patchset=\${patchset//\ /}
173
174GIT_SSH_COMMAND="\$SSH_COMMAND"
175GIT_SSH_COMMAND+=" -p $SSH_PORT"
176GIT_SSH_COMMAND="\$GIT_SSH_COMMAND" git push --follow-tags $GERRIT_R refs/heads/*:refs/heads/*
177if [ "\$?" -ne 0 ]; then
178 echo >&2 " ****** error: failed to push \${CHANGE[branch]}"
179 gerrit_cli review -m '"Gerrit failed to replicate this change ¯\\\\_(ツ)_/¯"' \$patchnum,\$patchset
180 exit 1
181fi
182
183echo " ****** success: \${CHANGE[branch]} pushed to $GERRIT_R"
184gerrit_cli review -m '"Gerrit has successfully replicated this change \\\\o/"' \$patchnum,\$patchset
185
186if [ -n "$DEPLOY_EXEC" ]; then
187
188 # If going to deploy, breathe
189 sleep 1
190
191 # Invoke deploy script
192 \$SSH_COMMAND -p $SSH_PORT $HOOK_USER@$HOOK_HOST "${DEPLOY_EXEC} \${args[@]}"
193 if [ \$? -ne 0 ]; then
194 gerrit_cli review -m '"Gerrit failed to deploy this change ¯\\\\_(ツ)_/¯"' \$patchnum,\$patchset
195 exit 1
196 else
197 gerrit_cli review -m '"Gerrit has successfully deployed this change \\\\o/"' \$patchnum,\$patchset
198 exit 0
199 fi
200else
201 gerrit_cli review -m '"Gerrit has skipped deploying this change ¯\\\\_(ツ)_/¯"' \$patchnum,\$patchset
202 exit 0
203fi
204set +x
205EOF
206 ) &> ${LOG_FILE}; RET=$?
207
luigi04e7d1d2020-11-08 17:25:03 +0000208# Keep the log if the hook has failed only
Luigi Santivetti33376db2020-10-17 00:18:03 +0100209[ "$RET" -ne 0 ] || rm -f ${LOG_FILE}