Externalización gráfica de servidor Git propio con stagit

23 de noviembre de 2020 • fjbalon

A veces es agradable navegar por el registro del historial de git en un navegador web o en algún otro programa sin tener que mirar el repositorio local. Es además una forma de mantener un registro de los repositorios que sean públicos, a modo de currículum o expositor de código. Si además se cumple el requisito personal de cumplir con una regla o una filosofía minimalista, de web estática en este caso y libre, aún mejor.

Para ello uso el impecable stagit, que es un generador de pagínas estáticas para git desarrollado por codemadness.org. Su uso es simple. Manualmente consta de dos partes, que son la creación de directorios html (que deben ser accesibles mediante servidor web) y su enlace con el directorio del servidor git:

mkdir -p /srv/git/htmlrepo1 && cd /srv/git/htmlrepo1
stagit /git/gitrepo1

Y la formación del índice y el htmlroot:

cd /srv/git
stagit-index /git/gitrepo1 /git/gitrepo2 /git/gitrepo3 > index.html

Ejemplos de resultados son templier.es/git, codemadness.org/git o git.suckless.org.

Automatización de actualización de repositorios

Para automatizar la actualización del directorio en función de los cambios de push añadimos a htmlroot (/srv/git) el script:

# /srv/git/create.sh 
reposdir="/git"
curdir="$(pwd)"

stagit-index "${reposdir}/"*/ > "${curdir}/index.html"

for dir in "${reposdir}/"*/; do
        # strip .git suffix.
        r=$(basename "${dir}")
        d=$(basename "${dir}" ".git")
        printf "%s... " "${d}"

        mkdir -p "${curdir}/${d}"
        cd "${curdir}/${d}" || continue
        stagit -c ".cache" -u "/git/$d/" "${reposdir}/${r}"

        # symlinks
        ln -sf log.html index.html
        ln -sf ../style.css style.css
        ln -sf ../logo.png logo.png
        ln -sf ../favicon.png favicon.png

        echo "done"
done

Por supuesto, el script anterior debe contar con permisos de ejecución; y el directorio htmlroot debe tener permisos adecuados para su manipulación, que siendo en este caso el usuario git el que genere de nuevo los HTML, debería éste tener permisos totales.

Además, por cada repositorio del servidor debemos añadir el hook post-receive tal que:

#!/bin/sh
# /git/code.git/hooks/post-receive 

export LC_CTYPE="en_US.UTF-8"

name="$1"
if test "${name}" = ""; then
        name=$(basename "$(pwd)")
fi

reposdir="/git"
dir="${reposdir}/${name}"
htmldir="/srv/git"
stagitdir="/"
destdir="${htmldir}${stagitdir}"
cachefile=".htmlcache"

if ! test -d "${dir}"; then
        echo "${dir} does not exist" >&2
        exit 1
fi
cd "${dir}" || exit 1

force=0
while read -r old new ref; do
        test "${old}" = "0000000000000000000000000000000000000000" && continue
        test "${new}" = "0000000000000000000000000000000000000000" && continue

        hasrevs=$(git rev-list "${old}" "^${new}" | sed 1q)
        if test -n "${hasrevs}"; then
                force=1
                break
        fi
done

r=$(basename "${name}")
d=$(basename "${name}" ".git")
printf "[%s] stagit HTML pages... " "${d}"

mkdir -p "${destdir}/${d}"
cd "${destdir}/${d}" || exit 1

if test "${force}" = "1"; then
        rm -f "${cachefile}"
        rm -rf "commit"
fi

stagit-index "${reposdir}/"*/ > "${destdir}/index.html"
stagit -c "${cachefile}" -u "/git/$d/" "${reposdir}/${r}"

ln -sf log.html index.html
ln -sf ../style.css style.css
ln -sf ../logo.png logo.png

echo "done"

También debe contar con privilegios de ejecución. Lo que hará que en cada push recibido, el contenido HTML de stagit se actualice.

Para una correcta impresión de los datos, es necesario que cada directorio de repositorio tenga en su raíz los ficheros owner, description y url:

cd /git/code
echo "fjbalon" > owner
echo "Descripción del repositorio" > description
echo "git://templier.es/code.git" > url

Las imágenes por defecto empleadas son favicon.png y logo.png, que irán en la raíz de htmlroot (/srv/git). También style.css.

cp stagit/style.css /srv/git/
cp stagit/favicon.png /srv/git/
cp stagit/logo.png /srv/git/

Autodespliegue con hooks

En este ejemplo damos al hook post-receive del repositorio del sitio web la capacidad de autodesplegarse al recibir push, con el ejemplo de esta propia web estática para que, con mi propio push autenticado por SSH, automáticamente se lance como actualización al servidor Apache.

#!/bin/sh
# /git/arrakis.git/hooks/post-receive 

echo "Ejecutando hook postreicive: desplegando a producción el static-site"
git --work-tree=/srv/http --git-dir=/tex/arrakis.git checkout -f master

Por supuesto, los permisos del directorio htmlroot deben tener los permisos para git.

drwxr-xr-x  3 git  git  4096 Dec 14 15:53 http