#!/bin/bash # # Git post-receive hook to update Patchwork patches after Git pushes # # Copyright © 2010 martin f. krafft # Released under the GNU General Public License v2 or later. set -eu #TODO: the state map should really live in the repo's git-config # Use semicolon as separator to allow for state names with spaces STATE_MAP="refs/heads/master:Accepted;refs/heads/master-next:Master Next;refs/heads/ross/mut:Master Under Test;refs/heads/morty:morty-master;refs/heads/pyro:pyro-master;refs/heads/rocko:rocko-master" # # ignore all commits already present in these refs # e.g., # EXCLUDE="refs/heads/upstream refs/heads/other-project" # EXCLUDE="" PWDIR=/usr/local/patchwork/patchwork if [ -d "$PWDIR" ]; then if [ ! -w "$PWDIR/post-receive_logs" ]; then echo "E: Post-receive hook has no write permissions in patchwork path." >&2 exit 1 fi else echo "E: Invalid patchwork path in post-receive hook" >&2 exit 1 fi do_exit=0 trap "do_exit=1" INT # Create a folder for the post-receive hook logs ERR_LOG_FILE=$PWDIR/post-receive_logs/post_receive.log if [ ! -f "$ERR_LOG_FILE" ]; then mkdir -p "`dirname \"$ERR_LOG_FILE\"`" 2>/dev/null fi get_patchwork_hash() { local hash hash="$(git -C $2 show -C $1 | python $PWDIR/parser.py --hash)" echo $hash test -n "$hash" } get_patch_id() { local id id=$($PWDIR/bin/pwclient info -h $1 2>>$ERR_LOG_FILE \ | sed -rne 's,- id[[:space:]]*: ,,p') echo $id test -n "$id" } set_patch_state() { $PWDIR/bin/pwclient update -s $2 -c $3 $1 2>>$ERR_LOG_FILE } get_patch_state() { state=$($PWDIR/bin/pwclient info $1 2>>$ERR_LOG_FILE \ | sed -rne 's,- state[[:space:]]*: ,,p') echo $state test -n "$state" } update_patches() { local cnt; cnt=0 local workdir; workdir=$4 local revparse; local revs; if [ -z "${EXCLUDE}" ]; then revparse="rev-parse" else revparse="rev-parse --not "${EXCLUDE}"" fi revs=$(git -C "$workdir" "$revparse" | git -C "$workdir" rev-list --stdin --no-merges --reverse "${1}".."${2}") IFS=$'\n'; for rev in $revs; do if [ X"$do_exit" = X"1" ]; then echo "$(date) I: exiting..." >> $ERR_LOG_FILE 2>/dev/null break fi hash=$(get_patchwork_hash "$rev" "$workdir") \ || { echo "$(date) E: failed to hash rev $rev." >> $ERR_LOG_FILE 2>/dev/null; continue; } id=$(get_patch_id $hash) \ || { echo "$(date) E: failed to find patch for rev $rev." >> $ERR_LOG_FILE 2>/dev/null; continue; } state="" state=$(get_patch_state "$id") \ || { echo "$(date) E: failed to find current state for patch ID-$id." >> $ERR_LOG_FILE 2>/dev/null; } if [ "$state" = "Accepted" ]; then echo "$(date) I: Skipping patch ID-$id because already is in \"Accepted\" state." >> $ERR_LOG_FILE 2>/dev/null; continue; fi reason="$(set_patch_state $id $3 $rev)" \ || { echo "$(date) E: failed to update patch ID-$id${reason:+: $reason}." >> $ERR_LOG_FILE- 2>/dev/null; continue; } echo "$(date) I: patch ID-$id updated to state \"$3\" using commit $rev." >> $ERR_LOG_FILE 2>/dev/null cnt=$(($cnt + 1)) done echo -e "$(date) I: $cnt patch(es) updated to state \"$3\"." >> $ERR_LOG_FILE 2>/dev/null } while read oldrev newrev refname workdir; do found=0 IFS=';' for i in $STATE_MAP; do key="${i%:*}" IFS=' ' if [ "$key" = "$refname" ]; then echo -e "\n$(date) I: Started patch-update attempt from commit $oldrev to commit $newrev." >> $ERR_LOG_FILE 2>/dev/null update_patches $oldrev $newrev "${i#*:}" $workdir found=1 break fi done if [ $found -eq 0 ]; then echo "$(date) E: STATE_MAP has no mapping for branch $refname" >> $ERR_LOG_FILE 2>/dev/null fi done