blob: d703b6ac4be22eeef8bf93f101f9548cebfbc36a [file] [log] [blame]
#!/bin/bash
#
# change-merged hook
#
# Copyright 2020 Luigi Santivetti <luigi.santivetti@gmail.com>
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# change-merged
#
# --change <change id>
# --change-url <change url>
# --change-owner <change owner>
# --change-owner-username <username>
# --project <project name>
# --branch <branch>
# --topic <topic>
# --submitter <submitter>
# --submitter-username <username>
# --commit <sha1>
# --newrev <sha1>
#
# RATIONALE: change-merged can propagate one or more changes landing into
# Gerrit to an external mirror. Be noted, this is an async hook that runs
# in the background.
#
# ` remote-update hook ` TODO
# ` `
# ` `
# (1) merge ` (2) push ` (3) push
# +--------+ +--------+ +--------+
# | Gerrit | ··········> | Gerrit | ··········> | Mirror | ··········>
# +--------+ +--------+ +--------+
# ` `
# ` `
# ` `
# ` `
LOG_FILE=${HOOKS_LOG_DIR:-/tmp}
if [ ! -w "$LOG_FILE" ]; then
LOG_FILE="/dev/null" # avoid permission denied
else
LOG_FILE="$LOG_FILE/hooks.change-merged-$(date +'%d%m%Y%H%M%S').txt"
fi
# Host service where replication mirrors and deploy engine live
HOOK_HOST=${HOOKS_REMOTE_HOST:-}
if [ ! -n "$HOOK_HOST" ]; then
echo " ****** warning: no host, skip hook" &> ${LOG_FILE}
exit 1
fi
# User allowed t othe target host to push and eventually deploy changes
HOOK_USER=${HOOKS_REMOTE_USER:-}
if [ ! -n "$HOOK_USER" ]; then
echo " ****** warning: no user, skip hook" &> ${LOG_FILE}
exit 1
fi
# Directory where this hook expects the project mirror to be located
HOOK_PATH=${HOOKS_REMOTE_PATH:-}
if [ ! -n "$HOOK_PATH" ]; then
echo " ****** warning: no path, skip hook" &> ${LOG_FILE}
exit 1
fi
# Alias for the remote tracking a given mirror
GERRIT_R=${HOOKS_REMOTE_ALIAS:-}
if [ ! -n "$GERRIT_R" ]; then
echo " ****** warning: no remote alias, skip hook" &> ${LOG_FILE}
exit 1
fi
SSH_RSA_ID=${HOOKS_REMOTE_RSAID:-}
if [ ! -n "$SSH_RSA_ID" ]; then
echo " ****** error: no rsa id file found" &> ${LOG_FILE}
exit 1
fi
SSH_PORT=${HOOKS_REMOTE_PORT:-22}
if [ ! -n "$SSH_PORT" ]; then
echo " ****** warning: no ssh port, default to 22" &> ${LOG_FILE}
fi
GERRIT_PORT=${HOOKS_GERRIT_PORT:-29418}
if [ ! -n "$GERRIT_PORT" ]; then
echo " ****** warning: no Gerrit port, default to 29418" &> ${LOG_FILE}
fi
GERRIT_HOST=${HOOKS_GERRIT_HOST:-}
if [ ! -n "$GERRIT_HOST" ]; then
echo " ****** warning: no Gerrit host, skip notify" &> ${LOG_FILE}
fi
DEPLOY_EXEC=${HOOKS_DEPLOY_EXEC:-}
if [ ! -n "${DEPLOY_EXEC}" ]; then
echo " ****** warning: no deploy exec, skip deploy" &> ${LOG_FILE}
fi
/bin/bash <(/bin/cat <<EOF
set -x
args='${*}'
declare -A CHANGE=(
[change]=""
[change-url]=""
[change-owner]=""
[change-owner-username]=""
[project]=""
[branch]=""
[topic]=""
[submitter]=""
[submitter-username]=""
[commit]=""
[newrev]=""
)
while read -a line; do
for K in \${!CHANGE[@]}; do
if [ "\${line[0]}" == "--\$K" ]; then
CHANGE[\$K]="\${line[@]:1}"
break
fi
done
done <<< "\$(echo -e "\${args// --/\\\\n--}")"
SSH_COMMAND="ssh"
SSH_COMMAND+=" -o StrictHostKeyChecking=no"
SSH_COMMAND+=" -o UserKnownHostsFile=/dev/null"
SSH_COMMAND+=" -i $SSH_RSA_ID"
function gerrit_cli
{
\$SSH_COMMAND -p $GERRIT_PORT \${CHANGE[submitter-username]}@$GERRIT_HOST gerrit \${@}
}
remote_url="ssh://$HOOK_USER@$HOOK_HOST:$HOOK_PATH/\${CHANGE[project]}.git"
# Does Gerrit have \\\$git_dir remote set up?
git remote get-url "$GERRIT_R" | grep -q -- "\$remote_url"
if [ "\$?" -ne 0 ]; then
echo >&2 " ****** error: \${CHANGE[project]} remote not found: $GERRIT_R"
echo >&2 " ****** error: \${CHANGE[branch]} not pushed, skip hook"
exit 1
fi
# Get patchset info
NUMBERS=\$(gerrit_cli query \${CHANGE[commit]} --patch-sets | grep -- number)
# Get patch number and patchset number
patchnum=\$(printf "%s\n" "\$NUMBERS" | head -n1 | cut -f 2 -d ':')
patchset=\$(printf "%s\n" "\$NUMBERS" | tail -n1 | cut -f 2 -d ':')
# Trim whitespaces
patchnum=\${patchnum//\ /}
patchset=\${patchset//\ /}
GIT_SSH_COMMAND="\$SSH_COMMAND"
GIT_SSH_COMMAND+=" -p $SSH_PORT"
GIT_SSH_COMMAND="\$GIT_SSH_COMMAND" git push --follow-tags $GERRIT_R refs/heads/*:refs/heads/*
if [ "\$?" -ne 0 ]; then
echo >&2 " ****** error: failed to push \${CHANGE[branch]}"
gerrit_cli review -m '"Gerrit failed to replicate this change ¯\\\\_(ツ)_/¯"' \$patchnum,\$patchset
exit 1
fi
echo " ****** success: \${CHANGE[branch]} pushed to $GERRIT_R"
gerrit_cli review -m '"Gerrit has successfully replicated this change \\\\o/"' \$patchnum,\$patchset
if [ -n "$DEPLOY_EXEC" ]; then
# If going to deploy, breathe
sleep 1
# Invoke deploy script
\$SSH_COMMAND -p $SSH_PORT $HOOK_USER@$HOOK_HOST "${DEPLOY_EXEC} \${args[@]}"
if [ \$? -ne 0 ]; then
gerrit_cli review -m '"Gerrit failed to deploy this change ¯\\\\_(ツ)_/¯"' \$patchnum,\$patchset
exit 1
else
gerrit_cli review -m '"Gerrit has successfully deployed this change \\\\o/"' \$patchnum,\$patchset
exit 0
fi
else
gerrit_cli review -m '"Gerrit has skipped deploying this change ¯\\\\_(ツ)_/¯"' \$patchnum,\$patchset
exit 0
fi
set +x
EOF
) &> ${LOG_FILE}; RET=$?
# Keep the log if the hook has failed only
[ "$RET" -ne 0 ] || rm -f ${LOG_FILE}