[PATCHv4, really works] pre-push hook checking bugzilla IDs on rhelX branches

Vratislav Podzimek vpodzime at redhat.com
Fri Jan 31 10:57:16 UTC 2014


Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 docs/commit-log.txt                  |  5 +++
 scripts/githooks/check_commit_msg.sh | 76 +++++++++++++++++++++++++++++++++
 scripts/githooks/pre-push            | 83 ++++++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+)
 create mode 100755 scripts/githooks/check_commit_msg.sh
 create mode 100755 scripts/githooks/pre-push

diff --git a/docs/commit-log.txt b/docs/commit-log.txt
index 7671f71..2e3f227 100644
--- a/docs/commit-log.txt
+++ b/docs/commit-log.txt
@@ -56,3 +56,8 @@ following are rules to follow when committing a change to the git repo:
    First, it verifies that the bug referenced is a RHEL bug and in correct
    states.  Second, it adds the appropriate Resolves/Related/Conflicts line
    to the RPM spec file changelog.
+
+It is recommended to use the pre-push hook checking commit messages for RHEL bug
+numbers and checking the referenced bugs for all the necessary acks. To make it
+work, just copy the scripts/githooks/pre-push and
+scripts/githooks/check_commit_msg.sh scripts to the .git/hooks/ directory.
diff --git a/scripts/githooks/check_commit_msg.sh b/scripts/githooks/check_commit_msg.sh
new file mode 100755
index 0000000..a14a390
--- /dev/null
+++ b/scripts/githooks/check_commit_msg.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+#
+# Check whether the given commit has a valid BZ ID reference for the given
+# release.
+#
+# $1 -- release number
+# $2 -- commit hash
+#
+
+exec 1>&2
+
+bzcmd="bugzilla"
+release=${1}
+commit=${2}
+msg="$(git show -s --pretty='%s%n%b' ${commit})"
+summary="$(git show -s --pretty='%s%n%b' ${commit}|head -n 1)"
+
+## helper functions ##
+# Check the bz to see if it has an ack for this release. If the branch is
+# a local branch, just warn. If it is the primary branch, block the commit.
+bz_has_ack() {
+    bug=$1
+    flags=$(${bzcmd} query --bug_id=${bug} --outputformat="%{flags}")
+
+    ack_pattern="rhel-${release}\.[[:digit:]]+\.[[:digit:]]+\+"
+    if [[ ! "$flags" =~ $ack_pattern ]]; then
+        echo "*** BZ ${bug} is missing acks: ${flags}"
+
+        return 1
+    fi
+    return 0
+}
+
+echo "${summary}" | grep -i '^new version' > /dev/null
+if [ $? -eq 0 ]; then
+    # "New version" commit doesn't need a BZ ID
+    exit 0
+fi
+
+for word in ${summary} ; do
+    echo "${word}" | grep -q -E "^.*(#[0-9]+).*"
+    if [ $? -eq 0 ]; then
+        bug="$(echo "${word}" | sed -e 's/^(#//g' -e 's/).*$//g')"
+        ${bzcmd} query --bug_id=${bug} --outputformat="%{product}" | grep -q "^Red Hat Enterprise Linux.*"
+        if [ $? -ne 0 ]; then
+            echo "*** BZ ${bug} is not a RHEL bug."
+            exit 1
+        fi
+        bz_has_ack ${bug}
+        exit $?
+    fi
+done
+
+last=$(($(echo "${msg}" |wc -l) - 2))
+if [ ${last} -gt 0 ]; then
+    echo "${msg}" | tail -n ${last} | grep -v "^#" |
+    grep -E "^(Resolves|Related|Conflicts): rhbz#[0-9]+$" |
+    while read line ; do
+        bug="$(echo ${line} | cut -d '#' -f 2)"
+        ${bzcmd} query --bug_id=${bug} --outputformat="%{product}" | grep -q "^Red Hat Enterprise Linux.*"
+        if [ $? -ne 0 ]; then
+            echo "*** BZ ${bug} is not a RHEL bug."
+            exit 1
+        fi
+        bz_has_ack ${bug}
+        # exit from the loop (piping to while creates a subprocess???)
+        exit $?
+    done
+
+    # exit from the script with the code from the loop
+    exit $?
+else
+    # nothing found
+    echo "*** Commit ${commit} doesn't have bugzilla ID specified ***" >&2
+    exit 1
+fi
diff --git a/scripts/githooks/pre-push b/scripts/githooks/pre-push
new file mode 100755
index 0000000..e8111a0
--- /dev/null
+++ b/scripts/githooks/pre-push
@@ -0,0 +1,83 @@
+#!/bin/bash
+#
+# pre-push hook that checks that all commits that are about to be pushed have
+# the bugzilla ID specified and the bug reports have all the necessary acks.
+#
+
+exec 1>&2
+
+# git gives us these on STDIN
+read more_args
+local_ref=$(echo ${more_args}|cut -d' ' -f1)
+
+echo "*** Checking commits that are about to be pushed" >&2
+
+## initialization ##
+remote="${1}"
+ACK_FATAL=0
+branch_name=$(echo "${local_ref}" | cut -d'/' -f3)
+branch_pattern="^rhel([[:digit:]])-(.*)"
+if [[ ! "$branch_name" =~ $branch_pattern ]]; then
+   exit 0
+fi
+release=${BASH_REMATCH[1]}
+
+# Is this a local branch, or the primary branch?
+if [ "${BASH_REMATCH[2]}" == "branch" ]; then
+    # Make a missing ack block the commit
+    ACK_FATAL=0
+else
+    # Missing acks are just warnings
+    ACK_FATAL=1
+fi
+
+if [ -f "${HOME}/.rhbzauth" ]; then
+    . "${HOME}/.rhbzauth"
+fi
+
+bzcmd="bugzilla"
+if [ ! -z "${RHBZ_USER}" ]; then
+   if [ ! -z "${RHBZ_PASSWORD}" ]; then
+       bzcmd_login="${bzcmd} --user=${RHBZ_USER} --password=${RHBZ_PASSWORD} login"
+   else
+       bzcmd_login="${bzcmd} --user=${RHBZ_USER} login"
+   fi
+else
+    bzcmd_login="bugzilla"
+fi
+
+commits=$(git log --pretty='%H' ${remote}/${branch_name}..${branch_name})
+if [ $? != 0 ]; then
+    if [ -n ${NEW_BRANCH} ]; then
+        exit 0
+    else
+        echo "*** Cannot find the remote branch ***"
+        echo 'Set the $NEW_BRANCH variable to an nonempty string to allow this push'
+        exit 1
+    fi
+fi
+
+${bzcmd} >/dev/null 2>&1
+if [ $? -eq 127 ]; then
+    echo "*** 'yum install python-bugzilla' to validate bug references."
+
+    msg="$(mktemp $(pwd)/commit.msg.XXXXXXXXXX)"
+    cp "${1}" "${msg}"
+    echo
+    echo "Aborted commit message written to: $(basename ${msg})"
+    exit 1
+else
+    ${bzcmd_login} >/dev/null
+fi
+
+## main ##
+# fork separate process for every commit, querying bugzilla takes time
+num_commits=$(echo ${commits}|wc -w)
+echo ${commits}|xargs -n1 --max-procs=${num_commits} .git/hooks/check_commit_msg.sh ${release}
+xargs_ret=$?
+if [ ${ACK_FATAL} == "0" ]; then
+    test ${xargs_ret} -eq 0
+    exit $?
+else
+    exit 0
+fi
-- 
1.8.5.3



More information about the anaconda-patches mailing list