Versionado automático con Maven

Tiempo aproximado: 4 min.
Este fin de semana he estado jugando con maven-release-plugin con el objetivo de automatizar el versionado de mi código y, bueno, el resultado ha sido un tanto agridulce porque por un lado ha sido muy sencillo pero por otro me he encontrado con un defecto de esos que cuesta encontrar, sobre todo cuando no estás seguro de lo que tienes entre manos porque ni lo has hecho tú ni está suficientemente documentado.

La parte fácil

Antes que nada, os cuento lo que yo suelo hacer con el código cada vez que termino una iteración.

Supongamos que la versión actual es la 0.0.1-SNAPSHOT.

1) Me recorro todos los pom.xml donde he puesto 0.0.1-SNAPSHOT y le quito el -SNAPSHOT.
2) Hago commit de los pom.xml que he cambiado.
3) Etiqueto esta versión del código en el repositorio (en mi caso Subversion).
4) Vuelvo a recorrer todos los pom.xml para dejar la siguiente versión: 0.0.2-SNAPSHOT.
5) Hago commit de los pom.xml.

Y eso todas las veces…

Pues bien, resulta que hay un plugin de Maven que hace todo eso por mi: maven-release-plugin.

Antes de empezar yo aconsejo también hacer mvn clean install, pero no es obligatorio. Yo es que soy un poco obsesivo con estas cosas.

Para usarlo no puedo tener ningún “commit” pendiente, de lo contrario, el plugin se quejará. Es obligatorio también proporcionar la información de dónde está nuestro repositorio, para ello debemos incluir el apartado “scm” en los pom.xml que lo requieran (según los tengamos organizados):



https://shopaas.googlecode.com/svn/trunk/shopaas
scm:svn:http://shopaas.googlecode.com/svn/trunk/shopaas
scm:svn:https://shopaas.googlecode.com/svn/trunk/shopaas

El plugin sustituirá en estas cadenas los valores adecuados, por eso es aconsejable revisar cómo quedan estas secciones de los pom.xml las primeras veces.

Lo primero que hay que hacer es:

mvn release:prepare -DdryRun=true

Esta instrucción cubre los pasos 1, 2 y 3. La propiedad “dryRun” nos sirve para decirle al plugin si queremos o no hacer efectivos los cambios, si le damos el valor “true”, el plugin NO hará commit ni tag. También comprueba si hay dependencias con artefactos cuya versión aún es SNAPSHOT, pero esto no lo he probado, la verdad. Además, “release:prepare” ejecuta por defecto los siguientes “goals” sobre el proyecto: “clean verify”. Esto hace que se ejecuten las pruebas.

Cuando lo ejecutemos, por la consola Maven nos preguntará la versión de cada pom.xml (él no quita el “-SNAPSHOT” sino que pone la versión que nosotros le digamos). También nos pregunta cuál es el nombre con el que va a etiquetar esta versión en el repositorio de control de versiones. Y por último nos pregunta cuál es la versión que vamos a tener para trabajar después de este versionado (que suele ser la siguiente con el “-SNAPSHOT”). El plugin nos propone valores por defecto que podemos aceptar pulsando “intro”. Para cada pom.xml, la ejecución con “dryRun=true” nos dejará 3 ficheros: pom.xml.releaseBackup, pom.xml.tag y pom.xml.next, que se corresponden con el que tenemos antes de ejecutar (0.0.1-SNAPSHOT), el que se etiquetará como versión estable (0.0.1) y el que quedará en el “trunk” con la nueva versión de trabajo (0.0.2-SNAPSHOT). Pero el plugin no hará efectivos estos cambios porque le hemos dicho “dryRun=true”.

La parte difícil

Hasta aquí todo iba bien, pero el siguiente paso me dio problemas. Pero primero hay que ejecutar sin “dryRun” para que se hagan efectivos los cambios en SVN.


mvn release:clean release:prepare

release:clean sirve para limpiar los ficheros que haya podido dejar una ejecución anterior. También podemos usar releas:rollback para deshacer los cambios efectuados en SVN.

El primer obstáculo fue al usar el Maven embebido que viene con m2eclipse. Así que tuve que pasar a usar una instalación externa (concretamente la 2.0.9).

El segundo obstáculo fue al ejecutar el comando y encontrarme con el siguiente mensaje de error:


[INFO] Executing: cmd.exe /X /C "svn --non-interactive commit --file C:\Temp\maven-scm-2032301768.commit --targets C:\Temp\maven-scm-5209016095571570993-targets"
[INFO] Working directory: C:\eclipseWorkspaces\MiTienda\shopaas
[INFO] Tagging release with the label shopaas-0.0.1...
[INFO] Executing: cmd.exe /X /C "svn --non-interactive copy --file C:\Temp\maven-scm-328141097.commit . https://shopaas.googlecode.com/svn/tags/shopaas-0.0.1"
[INFO] Working directory: C:\eclipseWorkspaces\MiTienda\shopaas
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Unable to tag SCM
Provider message:
The svn tag command failed.
Command output:
svn: Commit failed (details follow):
svn: File '/svn/tags/shopaas-0.0.1/domain/pom.xml' already exists

El caso es que hay un bug (¡cómo no!) que, para colmo, no parece estar claro si está del lado de Maven o de SVN. Parece que maven-release-plugin hace “svn copy” para crear el tag y que, a partir de la versión 1.5.1 de Subversion esto mismo ha comenzado a fallar. Así que hay que hacer manualmente la siguiente chapu:


# mvn release:prepare
=> fails
# svn up -r head
# mvn release:prepare -Dresume

De esta manera, los ficheros en .svn que han quedado chungos se arreglan con “svn up” y luego se continúa por donde se había quedado (con -Dresume). Con Eclipse consiste en primero hacer “Team / Update” y a continuación ejecutar Maven con el goal “release:prepare” y el Parameter “resume” (al que tenemos que ponerle el valor “true” porque la configuración del launcher que propone m2eclipse no permite añadir un parámetro con nombre pero sin valor).

Llegados a este punto podemos revisar que en nuestro servidor de SVN se han creado tres nuevas revisiones con el siguiente comentario:
* [maven-release-plugin] prepare release shopaas-0.0.1
* [maven-release-plugin] copy for tag shopaas-0.0.1
* [maven-release-plugin] prepare for next development iteration

Los ficheros que son cambiados tras la ejecución (los pom.xml) podemos compararlos con las correspondientes versiones anteriores. En mi ejemplo, el mismo trozo del pom.xml que muestro más arriba queda como:



https://shopaas.googlecode.com/svn/tags/shopaas-0.0.1
scm:svn:http://shopaas.googlecode.com/svn/tags/shopaas-0.0.1
scm:svn:https://shopaas.googlecode.com/svn/tags/shopaas-0.0.1

Y en nuestro espacio de trabajo tenemos que la versión de los diferentes pom.xml ha quedado ahora como 0.0.2-SNAPSHOT, tal y como respondimos en su momento. También nos ha quedado un fichero release.properties con todas las versiones y trayectorias en SVN de los componentes versionados por este plugin.

Queda pendiente

Me queda aún por probar a realizar el despliegue de la nueva versión de manera automatizada. Para ello hay que usar el goal “release:perform”, que según parece ejecuta por defecto los goals “deploy site-deploy” después de obtener dicha versión desde el servidor de control de versiones.