Hace poco tuvimos una agradable visita aquí en Frogtek. Una de las muchas aportaciones de Emma fue hacernos replantear nuestro sistema de lanzamiento de builds en Jenkins, pasando de uno más pesado en recursos a otro más eficiente. A raíz de dicho cambio hemos aprovechado y mejorado el procedimiento de bloqueo que tenemos configurado en Jenkins y la forma en la que lo realizamos. Vamos a explicarlo para que nos ayudéis a mejorarlo todavía mas.
En sí, el procedimiento consiste en no permitir commits al servidor SVN si hay una build rota. Excepto al usuario que haya provocado dicha rotura. De esta forma nos aseguramos de varias cosas:
- No se avanza en el desarrollo si el código subido no es de una calidad mínima, pasa los test y se construye correctamente.
- Los desarrolladores se hacen responsables de los problemas que ellos han generado y los arreglan.
- Cuando existe un problema en una parte del proyecto, y dicho problema tarda en resolverse, todo el equipo se preocupa por saber qué pasa y ayudar a resolverlo para poder seguir avanzando.
Para conseguir este funcionamiento usamos dos scripts. Uno, invocado al comienzo y finalización de cada proyecto en Jenkins, encargado de realizar el bloqueo en sí. Y otro, invocado desde el hook de SVN de pre-commit, que comprueba que no haya nadie bloqueando el servidor en el momento del commit.
El primero de ellos:
#!/bin/bash
#
# Script that creates and fill the data for the lock or empty the files
# in order to unblock jenkins
#
case $# in
3)
LOCK=$1
AUTHOR=$2
PROJECT=$3
;;
*) # Error
echo "Usage: $0 [lock|unlock] AUTHOR PROJECT_NAME" >&2
exit 1
;;
esac
AUTHORFILE=/frogtek/locks/$PROJECT
if [ "unlock" = "$LOCK" ]; then
cat /dev/null > $AUTHORFILE
exit 0;
else
echo $AUTHOR > $AUTHORFILE
exit 0;
fi
Simplemente escribe el autor del bloqueo en un archivo por proyecto, un especie de lock. Al inicio de cualquier trabajo de Jenkins invocamos al script con el párametro lock el nombre del proyecto y el autor. Así :
lockOrUnlockJenkins.sh lock `svnlook author REPOS_PATH` ${JOB_NAME}
Y como último paso del mismo trabajo, hacemos un unlock:
lockOrUnlockJenkins.sh unlock jenkins ${JOB_NAME}
El segundo script cumple tres funciones:
- Comprobar que el mensaje que se envía con el commit no está vacío.
- Comprobar que tiene una longitud de entre 10 y 3000 caracteres.
- Asegurarse de que no se permiten commits si hay builds rotas en Jenkins, excepto aquellas del causante de la rotura.
A continuación podemos ver el script que nos permite esto:
#!/bin/bash
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/local/bin/svnlook
PROJECTS=( PROJECT1 PROJECT2 PROJECT3 PROJECT4 )
AUTHOR=`$SVNLOOK author -t $TXN $REPOS`
HUDSONUSER="hudson"
NUM_CHARS=`$SVNLOOK log -t $TXN $REPOS | wc -c`
COMMENT=`$SVNLOOK log -t $TXN $REPOS`
if [ "$COMMENT" = "" ]; then
echo "" 1>&2
echo "*** Your commit has been blocked because you did not give any log message or your log message was too short." 1>&2
echo "Please write a log message describing the purpose of your changes and then try committing again." 1>&2
exit 1
else
if [ "$NUM_CHARS" -lt 10 -o "$NUM_CHARS" -gt 300 ]; then
echo "" 1>&2
echo "*** Your commit has been blocked because you give a log message very short or very large.(10-300 characters)" 1>&2
echo "Please write a log message describing the purpose of your changes and then try committing again." 1>&2
exit 1
fi
for i in 0 1 2 3
do
lock=`cat /frogtek/locks/${PROJECTS[i]}`
if [ "$lock" != "" -a "$lock" != $AUTHOR ]; then
echo "SVN LOCKED BY COMPILATION FAILED IN " ${PROJECTS[i]} " COMMITED BY "$lock 1>&2
exit 1
fi
done
exit 0
fi
Como veis nada muy complicado de configurar. ¿Qué os parece? ¿Cómo lo mejoraríais? ¿Utilizáis algo parecido?