Automatizar acciones en el Bugzilla al generar versiones con Maven
Índice de contenido
Introducción.
Cómo ya hemos visto varías veces, la creación de plugins de maven es bastante sencilla. Como recordatorio os remito a este tutorial «Desarrollo de Plugins para Maven»
como referencia a la creación de plugins de Maven
Aprovechando la facilidad de crear nuestros propios plugins, en este tutorial
vamos a mostrar como automatizar un conjunto de acciones que hay que hacer siempre
en los sistemas de gestión de incidencias, tales como dar de alta una nueva versión
del producto, cerrar las incidencias que soluciona la nueva versión, etc.
En este caso vamos a ver automatizar estas acciones en Bugzilla.
Entorno
El tutorial está escrito usando el siguiente entorno:
-
Hardware: Portatil Samsung R70 ( Intel(R) Core(TM)2 Duo 2,5Ghz, 2046 MB RAM, 232 Gb HD)
-
Sistema Operativo: Windows Vista Home Premium
-
Máquina Virtual Java: JDK 1.5.0_14 de Sun Microsystems (http://java.sun.com/javase/downloads/index_jdk5.jsp
-
IDE Eclipse 3.3 (Europa) (http://www.eclipse.org/downloads/)
Creación del plugin complementario.
Como hemos explicado en la introducción, la solución que hemos adoptado
es crear un plugin de Maven para que se conecte a nuestro Bugzilla y realice
todas las acciones de forma automática.
En primer lugar identificamos los parámeteros que necesita nuestro plugin
para conectarse al Bugzilla y generar el fichero changes.xml:
- productName: Nombre del producto en el Bugzilla del que obtenemos la
lista de bugs. - bugzillaUser: Usuario para el login en el Bugzilla.
- bugzillaPassword: Contraseña del usuario para el login en el Bugzilla.
- loginPage: Página de login en el Bugzilla.
- loginRequired: Parámetro para indicar si es necesario hacer login en
el Bugzilla para recuperar la lista de bugs. (por defecto true) - parentOnly: Al tener los proyectos de Maven herencia, con este parámetros
le indicamos que sólo genere la información de cambios en el proyecto padre. - versionSuffix: El nombre de la versión es común que tenga un sufijo mientras se está desarrollando, por lo que al consultar en el Bugzilla se debe eliminar. (Por defecto «-SNAPSHOT»).
- bugsToClose: Identifica el «status» de los bugs que deben ser cerrados al generar la versión. (Por defecto «RESOLVED, CLOSED»).
- bugsToMove: Identifica el «status» de los bugs que deben ser movidos al nuevo «milestone». (Por defecto «UNCONFIRMED, NEW, ASSIGNED, REOPENED»).
Además de estos parámetros hay que tener en cuenta al proyecto de Maven que también debe ser accesible desde nuestro plugin, por lo que en
nuestro código debemos añadir:
/** * The Maven Project. * * @parameter expression="${project}" * @required * @readonly */ private MavenProject project; /** * Bugzilla product name. * * @parameter expression="${changesMavenPlugin.productName}" * @required */ private String productName; /** * Bugzilla user. * * @parameter expression="${changesMavenPlugin.bugzillaUser}" * @required */ private String bugzillaUser; /** * Bugzilla password for the user. * * @parameter expression="${changesMavenPlugin.bugzillaPassword}" * @required */ private String bugzillaPassword; /** * Bugzilla login page. * * @parameter expression="${changesMavenPlugin.loginPage}" default-value="index.cgi" */ private String loginPage = "index.cgi"; /** * Bugzilla login required. * * @parameter expression="${changesMavenPlugin.loginRequired}" default-value="true" */ private boolean loginRequired = true; /** * Version name suffix that is removed from the Bugzilla Http request. * * @parameter expression="${changesMavenPlugin.versionSuffix}" default-value="-SNAPSHOT" */ private String versionSuffix = "-SNAPSHOT"; /** * Release in Bugzilla only in parent project. * * @parameter expression="${changesMavenPlugin.parentOnly}" default-value="true" */ private boolean parentOnly = true; /** * Bugzila bug status values that the bug will be closed. * * @parameter expression="${changesMavenPlugin.bugsToClose}" default-value="RESOLVED, CLOSED" */ private String bugsToClose = "RESOLVED, CLOSED"; /** * Bugzila bug status values the the bug will change the target milestone. * * @parameter expression="${changesMavenPlugin.bugsToMove}" default-value="UNCONFIRMED, NEW, ASSIGNED, REOPENED" */ private String bugsToMove = "UNCONFIRMED, NEW, ASSIGNED, REOPENED";
El proceso principal de nuestro plugin se realiza en el método «execute()»
que necesariamente debe implementar al heredar de «org.apache.maven.plugin.AbstractMojo».
Los pasos que sigue son:
- Preprocesamiento de parámetros: Para controlar si seguir con la ejecución
y preparar los datos necesarios para el resto del proceso. - Login en el Bugzilla.
- Crear la nueva versión en el Bugzilla.
- Cerrar los bugs que soluciona la nueva versión.
- Crear un nuevo «milestone» para la próxima versión.
- Cambiar el milestone de los bugs que no están solucionado al nuevo milestone creado.
El código del método «execute()» es:
/* * (non-Javadoc) * @see org.apache.maven.plugin.AbstractMojo#execute() */ public void execute() throws MojoExecutionException { getLog().debug("Entering..."); if (productName == null) { // use project name if is null productName = project.getName(); } // check if the project is a parent project if (parentOnly && (project.getParent() != null)) { return; } // gets version name from project versionName = project.getVersion(); final int index = versionName.indexOf(versionSuffix); if (index != -1) { // removing version suffix versionName = versionName.substring(0, index); } // evaluate next milestone(version) newMilestone = getNextMilestone(); // ask for version names try { versionName = prompter.prompt("What is the product release Bugzilla version name? ", versionName); } catch (final PrompterException e) { throw new MojoExecutionException("Could not get new version name.", e); } try { newMilestone = prompter.prompt("What is the product new development Bugzilla milestone? ", newMilestone); } catch (final PrompterException e) { throw new MojoExecutionException("Could not get milestone name.", e); } // Bugzilla url from issueManagement bugzillaURL = project.getIssueManagement().getUrl(); final WebConversation wc = new WebConversation(); // perform login boolean loginSuccess = true; if (loginRequired) { loginSuccess = login(wc); } if (loginSuccess) { // create the new version in Bugzilla createVersion(wc); // close resolved bugs closeBugs(wc); // create the new milestone createMilestone(wc); // change milestone for unresolved bugs changeMilestone(wc); } else { throw new MojoExecutionException("The username or password you entered is not valid."); } getLog().debug("Exiting..."); }
Como se puede ver en el código, después de un procesamiento previo de los
parámetros se empieza con las peticiones al Bugzilla; hacemos el login y
simulamos la navegación por las páginas del Bugzilla para ir ejecutando las acciones que estamos automatizando.
Esta navegación la realizamos con la librería «httpunit«;
por lo que añadimos su dependencia en el fichero pom.xml:
httpunit httpunit 1.6.2
A modo de ejemplo, ponemos parte del código en el que se muestra como simulamos la navegación utilizando httpunit.
Primero hay que crear una conversación, que viene a ser como una sesión con el servidor:
..... final WebConversation wc = new WebConversation(); .....
y después realizamos la serie de peticiones … (en este caso el login):
..... final WebRequest req = new GetMethodWebRequest(bugzillaURL + loginPage); WebResponse resp; resp = wc.getResponse(req); final WebForm webForm = resp.getFormWithName("login"); ..... webForm.setParameter("Bugzilla_login", bugzillaUser); webForm.setParameter("Bugzilla_password", bugzillaPassword); webForm.submit(); resp = wc.getCurrentPage(); .....
De esta forma, siempre y cuando utilicemos la misma conversación, podemos
seguir haciendo peticiones al servidor bajo la misma sesión. Así pues, el resto
de acciones en el Bugzilla lo realizaremos con la misma conversación (sesión).
Se irán solicitando formularios y enviándose, de forma que se llevarán a cabo todas las acciones previstas.
Ahora sólo queda hacer que nuestro plugin pueda ser utilizado desde otros proyectos instalándolo en nuestro repositorio local ejecutando:
mvn clean install
Utilizando nuestro plugin.
Éste plugin lo deberemos ejecutar cuando generemos una «release» con Maven.
Por lo que el plugin debe estar incluido en los proyectos en su fichero «pom.xml» de la siguiente forma.:
..... ..... Bugzilla https://host/cgi-bin/bugzilla3/ ..... ..... ..... com.autentia.mvn.plugin releaseBugzilla 1.0-SNAPSHOT *** nombre del producto en el bugzilla *** ${bugzillaUser} ${bugzillaPassword} AutentiaBugzillaMaven-release Local Maven repository of releases http://bugzillachanges.sourceforge.net/maven-repository false true
De los parámetros de configuración de nuestro plugin, se pueden considerar
un poco distintos los parámetros «bugzillaUser» y «bugzillaPassword», ya que
es algo particular de cada usuario. Al ser el «pom.xml» un fichero que se suele
compartir, no es aconsejable que aparezcan estos datos; por lo que nos valemos de
las ventajas de Maven para recuperarlos del perfil activo en el fichero «settings.xml»;
de esta forma en nuestro fichero «setting.xml» deberá aparecer:
..... .......... identificador del perfil activo .....user password
Finalmente sólo queda que nuestro plugin se ejecute. Para eso añadimo el «goal» específico a la línea de comandos para que el contexto de Maven llame a la ejecución de nuestro plugin:
mvn com.autentia.mvn.plugin:releaseBugzilla:release
Línea de comandos
Como no todo es Maven en esta vida, ni Java, y podemos tener en Bugzilla la
gestión de otros proyectos, hemos añadido la posibilidad de ejecutar este plugin
desde la línea de comandos pasándole los parámetros necesarios.
java -jar releaseBugzilla-XX.jar -help Nota:El nombre del fichero jar debe ser el correspondiente a la versión del plugin. Uso: java -jar releaseBugzila-XX.jar args args: -productname: Nombre del producto en el bugzilla. Este parámetro es obligatorio. -url: URL del bugzilla, debe terminar con \"/\". (eg. https://host/cgi-bin/bugzilla3/). Este parámetro es obligatorio. -version: Nombre de la versión actual. -suffix: Sufijo del nombre de la versión que será eliminado. Por defecto \"-SNAPSHOT\"". -user: Usuario del Bugzilla. -password: Contraseña del usuario en Bugzilla. -loginpage: Página de login en el Bugzilla. (eg. index.cgi). Por defecto \"index.cgi\". -loginrequired: true o false, indica si es obligatorio el login en el Bugzilla. Por defecto \"true\". -bugs2close: Estados de los bugs que van a ser cerrados. Para más de un estado separarlos por espacios. Por defcto \"RESOLVED VERIFIED\". -bugs2move: Estado de los bugs en los que se va a cambiar el "target milestone"al nuevo "milestone". Para más de un estado separarlos por espacios. Por defecto \"UNCONFIRMED NEW ASSIGNED REOPENED\".
Conclusiones
Como hemos visto varias veces, el desarrollo de plugins de Maven nos sirve
para completar nuestras necesidades. En este caso, al tener la generación de
versiones con Maven, parece lógico que aquellas acciones que podamos ir automatizando
las hagamos en un plugin propio de Maven, que se ejecutará al generar una nueva versión.
Si queréis todo el código fuente de este plugin lo podéis conseguir en
sourceforge.
Documentación extra la podéis encontrar
aquí.
Un saludo.
Borja Lázaro de Rafael.