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?