#!/bin/bash

# Announce a git branch

die() {
	echo "$@" >> /dev/stderr
	exit 1
}

helpme() {
	die "Usage: $0 [oldref] [newref] [remote] [branch] [--force] [--cc] [--review] [--tag tag]"
}

# Note: getopt requires -o '' or else it won't process positional arguments
# correctly!
TEMP=$(getopt -o '' --long 'cc,force,debug,review,tag:' -n "$0" -- "$@")
test $? -eq 0 || helpme

eval set -- "$TEMP"
unset TEMP

force=0
debug=0
cc=
verb="announce"
tags=()
while true; do
	case "$1" in
	'--force')	force=1; shift; continue;;
	'--debug')	debug=1; shift; continue;;
	'--cc')		cc=1; shift; continue;;
	'--review')	verb="review"; shift; continue;;
	'--tag')	tags+=("$2"); shift; shift; continue;;
	'--')		shift; break;;
	*)		helpme;;
	esac
done

oldref="$1"
newref="$2"
remote="$3"
branch="$4"

if [ -z "${oldref}" ]; then
	oldref="$(git branch-remote)" || exit 1
fi
true "${newref:=HEAD}"
true "${remote:=korg}"
true "${branch:=for-next}"

code_submit_tgt="$(git config user.codeSubmissionTarget)"
test -n "${code_submit_tgt}" || \
	die "${PWD}: code submission target not configured."

# Does the oldref exist?
git rev-list -n 0 "${oldref}" > /dev/null 2>&1 || \
	die "${oldref}: starting git reference not found."

# Make sure there's a series of commits between oldref and newref.
nr_commits="$(git rev-list "${oldref}..${newref}" | wc -l)"
# echo "${oldref}..${newref}; nr_commits = $nr_commits" > /dev/stderr
test "${nr_commits}" -gt 0 || \
	die "${oldref}..${newref}: Must have at least one commit."

# Figure out the short name and the url of the remote repo.
git ls-remote "${remote}" > /dev/null 2>&1 || die "${remote}: remote repo unknown."
repo="$(basename "$(git remote get-url "${remote}")" | sed -e 's/\.git//g')"
origin_url="$(git remote get-url "${remote}")"

# Figure out the commit id for the newref (or the commit the tag points
# to, if it's a tag).
longid="$(git rev-list -n 1 "${newref}")"
shortid="$(git rev-parse --short "${longid}")"
test -n "${longid}" || die "${newref}: ending git reference not found."

filter_commit() {
	local commit_id="$1"

	sed -e 's@refs/heads/@@g' | \
	awk -v commit="${commit_id}" \
	'BEGIN{ret=1;}{if ($1 == commit) {print $2; ret=0; exit;}}END{exit(ret);}'
}

# Let's see if the default branch has the referenced commit?
branch="$(git ls-remote "${remote}" "refs/heads/${branch}" | \
	filter_commit "${longid}")"
# Nope.  Let's see if any of them have it.
test -z "${branch}" && branch="$(git ls-remote --heads "${remote}" | \
	filter_commit "${longid}")"
test -n "${branch}" || die "${newref}: couldn't find a remote branch with this reference."

# Check each commit for RVB and SOB.
git checkpatch "${oldref}..${newref}"
test $? -ne 0 && test "${force}" -eq 0 && exit 1

if [ -n "${cc}" ]; then
	echo "Cc: $(git contributors --delimiter ', ' "${oldref}..${newref}")"
fi

# Compute the ANNOUNCE tag contents.
announce="[ANNOUNCE"
for ((i = 0; i < ${#tags[@]}; i++)); do
	announce="${announce} ${tags[i]}"
done
announce="${announce}]"

# Ok, emit announcement message.
review_message() {
	cat << ENDL
Subject: ${announce} ${repo}: ${branch} updated to ${shortid}

Hi folks,

The ${branch} branch of the ${repo} repository at:

	${origin_url}

has just been updated for your review.

This code snapshot has been rebased against recent upstream, freshly
QA'd, and is ready for people to examine.  For veteran readers, the new
snapshot can be diffed against the previous snapshot; and for new
readers, this is a reasonable place to begin reading.  For the best
experience, it is recommended to pull this branch and walk the commits
instead of trying to read any patch deluge.

The new head of the ${branch} branch is commit:

ENDL
}

announce_message() {
	cat << ENDL
Subject: ${announce} ${repo}: ${branch} updated to ${shortid}

Hi folks,

The ${branch} branch of the ${repo} repository at:

	${origin_url}

has just been updated.

Patches often get missed, so please check if your outstanding patches
were in this update. If they have not been in this update, please
resubmit them to ${code_submit_tgt} so they can be picked up in
the next update.

The new head of the ${branch} branch is commit:

ENDL
}

"${verb}_message"

git log --oneline -n 1 "${oldref}..${newref}" | cat -

echo
if [ "${nr_commits}" -eq 1 ]; then
	echo "${nr_commits} new commit:"
else
	echo "${nr_commits} new commits:"
fi
echo

git shortlog --format="[%h] %s" "${oldref}..${newref}" | cat -

echo Code Diffstat:
echo
git diff --stat --summary -C -M "${oldref}..${newref}" | cat -
