#!/bin/sh
# zone-serial-number-hook - Check for missing serial bumps
#
# Written in 2020 by Lucas
#
# To the extent possible under law, the author(s) have dedicated all
# copyright and related and neighboring rights to this software to the
# public domain worldwide. This software is distributed without any
# warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication
# along with this software. If not, see
# <http://creativecommons.org/publicdomain/zero/1.0/>.

# Requires:
# - POSIX sh
# - bc
# - git
# - ldns-utils

# Install instructions:
#
#	cp zone-serial-number-hook "$myrepo/.git/hooks/pre-commit"
#	chmod +x "$myrepo/.git/hooks/pre-commit"

bc_cmp()
{
	_X=$1
	_OP=$2
	_Y=$3

	_rc=$(bc <<EOF
define t(x, y){
	if (x $_OP y) {
		return(0)
	}
	return(1)
}
t($_X, $_Y)
EOF
)
	return $_rc
}

get_serial()
{
	git show "$1" 2>/dev/null | ldns-read-zone -E SOA | {
		read -r _name _ttl _class _rrtype _rname _mname _serial _rest
		printf "%s\n" "${_serial:-0}"
	}
}

if git rev-parse --verify HEAD >/dev/null 2>&1; then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	against=$(git hash-object -t tree /dev/null)
fi

# Zonefiles names are matched against hooks.zonefile_regex option.
# Defaults to `\.zone$`.
zonefile_regex=$(git config --default '\.zone$' hooks.zonefileregex)

needs_serial_bump=$(git diff-index --name-only --cached "$against" |
    grep -E -- "$zonefile_regex" | {
	rc=0
	while IFS= read -r filename; do
		old=$(get_serial "$against:$filename")
		new=$(get_serial ":$filename")
		if bc_cmp "$new" "<=" "$old"; then
			printf "%s\n" "$filename"
			rc=1
		fi
	done
	return $rc
})

rc=$?
if [ $rc -ne 0 ]; then
	# send all output to standard error
	exec >&2
	printf "The following zonefiles require a serial bump:\n"
	printf "- %s\n" $needs_serial_bump
fi
exit $rc
