CFEngine SVN pre-commit hook
2012-07-11I use CFEngine on my personal site to manage my configuration. I have an SVN repo on one box that I can push configuration changes to, and then from there, the changes get pushed out to all of my boxes.
One problem that I encountered is that changes to my CFEngine configurations that had syntax errors would be pushed out to all of my machines, and cause them to fallback to the failsafe configuration, which is less than ideal.
My solution was to write a pre-commit hook for my SVN repo that would prevent me from checking anything in that would break my configuration.
#!/bin/bash REPOS=$1 TXN=$2 LOG="/home/svn/commit.log" CHANGES=0 if [[ "$1" = "" && "$2" = "" ]]; then echo "Most be called as $0 REPOS TXN" >> "$LOG" exit 1 fi AWK="/bin/awk" GREP="/bin/grep" RM="/bin/rm" ECHO="/bin/echo" SED="/bin/sed" SVN="/usr/bin/svn" SVNLOOK="/usr/bin/svnlook" SVN_URL="file:///home/svn/cfengine/trunk" CF_PROMISES="/usr/sbin/cf-promises" PROMISEDIR="/home/svn/.cfagent/inputs/" MODULESIDR="/home/svn/.cfagent/modules/" "${ECHO}" "REPOS ${REPOS}" >> "$LOG" "${ECHO}" "TXN ${TXN}" >> "$LOG" "${ECHO}" "Checking out working copy from $REPOS ...." >> "$LOG" "${SVN}" co --depth immediates "${SVN_URL}/cf-agent_policies" "${PROMISEDIR}" > /dev/null if [[ $? -ne 0 ]]; then "${ECHO}" "Failed to get fresh working copy" >> "$LOG" exit 1 fi "${SVN}" co --depth immediates "${SVN_URL}/cf-agent_modules" "${MODULESIDR}" > /dev/null if [[ $? -ne 0 ]]; then "${ECHO}" "Failed to get fresh working copy" >> "$LOG" exit 1 fi # Figure out what directories have changed using svnlook. FILES=`${SVNLOOK} changed ${REPOS} -t ${TXN} | ${AWK} '{ print $2 }'` > /dev/null for FILE in $FILES; do "${ECHO}" "file changed ${FILE}" >> "${LOG}" if [[ $("${ECHO}" "${FILE}" | ${GREP} cfengine/trunk) != "" ]]; then if [[ $("${ECHO}" "${FILE}" | ${GREP} generic_cf-agent_policies) != "" ]]; then if [[ $("${ECHO}" "${FILE}" | "${SED}" -e 's/home\/svn\/cfengine\/trunk\/cf-agent_policies\///g') != "" ]]; then CHANGES=1 "${SVNLOOK}" cat "${REPOS}" "${FILE}" -t "${TXN}" > ${PROMISEDIR}/$("${ECHO}" "${FILE}" | "${SED}" -e 's/home\/cfengine\/trunk\/cf-agent_policies\///g') fi fi fi done if [[ ${CHANGES} -eq 0 ]]; then exit 0 fi "${CF_PROMISES}" --dry-run > /dev/null if [[ $? -ne 0 ]]; then "${ECHO}" "Syntax error! Aborting commit!" >> "${LOG}" "${RM}" -rf "${PROMISEDIR}" "${RM}" -rf "${MODULESIDR}" exit 1 fi "${RM}" -rf "${PROMISEDIR}" "${RM}" -rf "${MODULESIDR}"
This should be the pre-commit file in the hooks directory of your SVN repo. If that file exits with a non-zero code, the commit will fail. The file must be executable by the svn user.