#!/bin/bash
# Author: Daniel Mohr
# Date: 2022-06-26
#
# This script should run as gitolite trigger at 'POST_GIT'.
# It will add a server timestamping signed with a gpg key on the default branch.
#
# It tries first to read the gpg key id from '$HOME/.server_timestamping.cfg'.
# If the file does not exists, this script creates a gpg key and stores it id
# in the file '$HOME/.server_timestamping.cfg'.
#
# If necessary, in the commited repository the branch 'server_timestamping'
# is created. The default branch (HEAD) is merged to the branch
# 'server_timestamping' and an empty, gpg signed commit is done.

# command line parameters and environment are desribed on:
# https://gitolite.com/gitolite/triggers.html

# run trigger from gitolite account command line:
# GL_LOGFILE="$HOME/.gitolite/logs/gitolite-2022-06.log" GL_REPO_BASE="$HOME/repositories" GL_REPO="foo/foo" /usr/share/gitolite3/triggers/server_timestamping POST_GIT foo/foo testuser W any git-receive-pack

#set -e

runtime=$(date +%Y-%m-%d.%H:%M:%S)

if [ $# -gt 0 ]; then
    # check command line parameters
    trigger=$1
else
    exit 1
fi

if [ "$trigger" != "POST_GIT" ]; then
    # check first command line parameter
    exit 1
fi

if [ "$6" != "git-receive-pack" ]; then
    exit 0
fi

echo -e "$runtime\t$$\tdo server_timestamping $(date -Iseconds)" >> "$GL_LOGFILE"

# check gpg key available
configfile=$HOME/.server_timestamping.cfg
if [ -f "$configfile" ]; then
    gpgkey=$(cat "$configfile")
    gpg --list-keys "$gpgkey" || exit 1
else
    echo -e "$runtime\t$$\tno gpg key availabe, create one" >> "$GL_LOGFILE"
    gpgkey=$(gpg --batch --quick-generate-key --passphrase '' "$USER@$(hostname)" future-default default never 2>&1 | grep "marked as ultimately trusted" | cut -d " " -f 3)
    echo "$gpgkey" > "$configfile"
fi

# check gpg key available
gpg --list-keys "$gpgkey" || exit 1

# POST_GIT a/bar testuser W any git-receive-pack
# $HOME
# $GL_REPO_BASE
# $GL_REPO
# $GL_LOGFILE
# $GL_USER
repopath=$GL_REPO_BASE/$GL_REPO.git

tmpdir=$(mktemp --directory)

# Unfortunately, since we do not know how many commits were done,
# we have to get the full history.
# Maybe we should use a better tmpdir to allow hardlinking (--local).
# Further, we can skip the working tree (--no-checkout).
git clone --no-checkout "$repopath" "$tmpdir"

# check if last commit was on default branch (HEAD)
#allbranches=$(git branch --all --sort=creatordate --format "%(refname)")
lastcommittedbranch=$(cd "$tmpdir" && git branch --list --all --sort=creatordate --format "%(refname)" | tail -n 1)
headbranch=$(cd "$tmpdir" && git branch --list --all --sort=creatordate --format "%(refname)" | grep heads)
echo "$lastcommittedbranch" | grep --quiet "$(basename "$headbranch")" && res=1 || res=0
if [ $res == 0 ]; then
    # the last commit was not done to default branch (HEAD)
    rm -rf "$tmpdir"
    echo -e "$runtime\t$$\tdo not server_timestamping on branch $lastcommittedbranch" >> "$GL_LOGFILE"
    exit 0
fi

(cd "$tmpdir" && git config user.name "$USER")
(cd "$tmpdir" && git config user.email "$USER@$(hostname)")
(cd "$tmpdir" && git config user.signingkey "$gpgkey")
(cd "$tmpdir" && git config commit.gpgSign 1)

(cd "$tmpdir" && git branch --list --all | grep --quiet server_timestamping) && res=1 || res=0

if [ $res == 0 ]; then
    echo -e "$runtime\t$$\tcreate branch server_timestamping in $repopath" >> "$GL_LOGFILE"
    (cd "$tmpdir" && git branch --quiet server_timestamping)
fi
# Unfortunately, 'git checkout' creates a working tree.
(cd "$tmpdir" && git checkout server_timestamping)
(cd "$tmpdir" && git merge --no-commit --quiet remotes/origin/HEAD)
(cd "$tmpdir" && git commit --allow-empty -m "signing commit")
if [ $res == 0 ]; then
    (cd "$tmpdir" && git push --set-upstream origin server_timestamping)
else
    (cd "$tmpdir" && git push)
fi

rm -rf "$tmpdir"

#env > /data/gitolite/e1
#echo $* > /data/gitolite/e2

echo -e "$runtime\t$$\tdid server_timestamping in $repopath" >> "$GL_LOGFILE"