Desplegando código con Phing, PHPunit, Coder y Jenkins

22

Transcript of Desplegando código con Phing, PHPunit, Coder y Jenkins

Page 1: Desplegando código con Phing, PHPunit, Coder y Jenkins

Desplegando código con Phing, PHPUnit, Coder y Jenkins

www.ladrupalera.com@ladrupalera

José Antonio Rodríguez Bonilla

Page 2: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Índice de contenidos 

Introducción Consideraciones Configurando Github Realizando nuestra primera tarea Implementando Drupal Developer Plugin Integrando Phing Elaborando nuestro primer Test  

Referencias Web externas 

 

VP1.9  1 / 20  

Page 3: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Manual de uso

Introducción El objetivo de esta guía no es detallar los pasos para la instalación de las herramientas que se comentan a continuación. Más bien nos centraremos en el flujo de despliegue y revisión del código que generamos desde un entorno local hacia otro remoto, tomando como fuente de datos un repositorio de datos (en este caso Github), pasando por la revisión y análisis de dicho código mediante herramientas externas que nos ayudarán a garantizar unos mínimos de calidad antes de realizar un despliegue. Para ello, y antes de entrar en materia, daremos por supuesto que tenemos instalado Jenkins en un servidor con los siguientes Plugins. No obstante, en lo sucesivo iremos comentando en qué momento debemos instalar cada uno de los plugins:

● Drupal developer plugin ● Git client plugin ● Git plugin ● Github plugin ● Phing plugin ● XUnit plugin

Además de esto, deberemos tener instalados los siguientes servicios en nuestra máquina de integración:

● PHPUnit ● Phing ● PHP (5.4) ● Git

Consideraciones Lo que se pretende ofrecer en esta guía es una serie de pasos que garantice, mediante la fusión de ramas a través de Github (Merge), la ejecución de una serie de procesos que garantice que el código mergeado en una rama cumpla con los requisitos funcionales, además de garantizar una sintaxis adecuada, antes de un despliegue, de forma que podamos automatizar una serie de tareas que generalmente realizamos a mano. Para ello, utilizaremos como herramienta motora Jenkins, encargada de centralizar todo el proceso de revisión y garantía del código, asumiendo la responsabilidad de realizar un despliegue en caso de éxito o bien, detener dicho despliegue y avisar a los responsables de los errores cometidos. Jenkins es un software de Integración continua open source escrito en Java. Está basado en el proyecto Hudson y es, dependiendo de la visión, un fork del proyecto o simplemente un cambio de nombre. Jenkins proporciona integración continua para el desarrollo de software. Es un sistema corriendo en un servidor que es un contenedor de servlets, como Apache Tomcat. Soporta herramientas de control de versiones como CVS, Subversion, Git, Mercurial,

 

VP1.9  2 / 20  

Page 4: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Perforce y Clearcase y puede ejecutar proyectos basados en Apache Ant y Apache Maven, así como scripts de shell y programas batch de Windows. El desarrollador principal es Kohsuke Kawaguchi. Y pasamos a la práctica directamente. Para ello, debemos configurar en primer lugar una serie de tareas o jobs en Jenkins de forma lineal. Es decir, si la primera tarea no cumple con los requisitos deseados, no pasaremos a la siguiente. Esto nos permite atomizar los procesos involucrados en la revisión de un despliegue:

1. Análisis de comentarios, seguridad y sintaxis a través de Coder 2. Ejecución de tests unitarios 3. Despliegue en el entorno

Estas tareas se ejecutarán de forma secuencial, de manera que si una de ellas no cumple con los requisitos deseados, el proceso se detendrá automáticamente notificando a las partes implicadas de las incidencias producidas durante el despliegue. Las condiciones previas que deberían darse antes de iniciar este proceso son las siguientes:

● Tener un entorno remoto versionado en Github apuntando a una rama, en este caso ‘Staging’

● Tener un entorno local versionado en nuestra máquina, a ser posible a través de un Fork de la rama principal de Staging, de forma que tengamos la posibilidad de solicitar integraciones en la rama principal. No obstante, este flujo es relativo y se basa en el ejemplo real citado a continuación, pero las posibilidades en cuanto a tests basados en haltonfail son prácticamente infinitas.

En el ejemplo que tratamos a continuación, el servidor Jenkins ha sido instalado en la misma máquina donde integraremos el código a través de Github. No obstante, podría estar perfectamente en una máquina remota y realizar un despliegue a través de SSH en un servidor remoto. Si este fuera el caso, un error muy frecuente a tener en cuenta es el acceso mediante el par de claves pública/privada del usuario Jenkins que ejecuta las peticiones en el servidor remoto de despliegue, por lo que sería aconsejable realizar previamente una conexión desde la consola del servidor Jenkins a la máquina remota con el usuario jenkins (que instala el servidor por defecto) para comprobar que el acceso se realiza sin problemas de autenticación. Además de esto, también es importante revisar los accesos mediante SSH al repositorio Github donde tengamos alojado nuestro código de integración para asegurarnos que el usuario jenkins puede acceder al mismo y realizar escrituras.

Configurando Github Sabiendo esto, vamos a establecer el primer paso la llamada automática al trigger o disparador de Jenkins en Github cuando se produce un Merge en una rama determinada. Para ello, en nuestro repositorio principal (o de integración) deberemos acceder a la configuración del repositorio mediante la pestaña ‘Settings’:

 

VP1.9  3 / 20  

Page 5: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Después, debemos acceder a la pestaña ‘Webhooks & Services’:

En esta ventana, debemos acceder el servicio ‘Jenkins (Github Plugin)’:

Para configurar el servicio, nos solicitará un URL de acceso que utilizará para avisar a Jenkins mediante una petición POST de que ha habido un merge en una rama. Para conocer esta URL, debemos acceder a la configuración de Jenkins ‘Administrar Jenkins’, y acceder a la ‘Configuración del sistema’. Si hemos instalado el Github Plugin correctamente, podremos ver la URL que debemos poner en su sección correspondiente:

NOTA: Para ver la ruta habrá que hacer click en el icono de interrogación que aparece a la derecha. Una vez introducida esta URL en Github, éste nos permite realizar un test a través de un botón de acción. No obstante, el ‘status’ de esta petición no se actualiza hasta que se realiza una petición real a través de un Merge (al menos en los ejemplos realizados durante la redacción de este documento), por lo que no debemos preocuparnos demasiado por este asunto de momento.

 

VP1.9  4 / 20  

Page 6: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Realizando nuestra primera tarea Una vez hemos concluido la configuración de nuestro repositorio en Github y hemos finalizado la instalación y configuración de Jenkins, vamos a pasar a configurar nuestra primera tarea. Para ello, hacemos click en el primer item del bloque de la izquierda de nuestro Jenkins ‘Nueva tarea’:

Una vez hacemos click en este item, crearemos un nuevo proyecto de estilo libre, y pondremos un nombre de prueba para la tarea:

Una vez hacemos click en OK, pasamos a la siguiente pantalla, de la cual resaltamos los aspectos más importantes a nivel de configuración:

 

VP1.9  5 / 20  

Page 7: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Hemos destacado 3 opciones, aunque podemos realizar diferentes pruebas con el resto de configuraciones:

● Github project: marcando este item, introduciremos la URL de nuestro repositorio. ● Dentro de ‘Configurar el origen del código fuente’, deberemos marcar la opción Git, y

aquí tendremos que introducir la URL del proyecto. En este caso, no introduciremos la URL del repositorio, sino aquella utilizada para poder hacer un checkout del mismo. Esto se puede hacer de dos maneras:

○ Mediante SSH: si lo hacemos así, tendremos que asegurarnos que el usuario Jenkins de nuestra máquina tiene acceso al repositorio que queremos configurar. Esto lo configuraremos en nuestro repositorio en Github otorgando permisos a través de la clave pública del usuario.

○ Mediante HTTPS: con esta alternativa, Jenkins nos permitirá introducir las credenciales del usuario con acceso al repositorio. De esta forma, dicho usuario también tendría que tener acceso a este repositorio.

Podemos ver información de estas URL dentro de nuestro propio repositorio en Github tal y como se muestra en la imagen a continuación:

En este aspecto, es importante resaltar un punto. Una vez hemos introducido las credenciales o bien el acceso SSH en nuestro Jenkins, al pulsar el botón tabulador Jenkins internamente comprobará el acceso al repositorio. Si existe algún problema con las credenciales, en este momento dará un aviso notificando del error de acceso. Si este es el caso, sería necesario comprobar que la comunicación entre nuestro usuario Jenkins y el repositorio en Github se está produciendo (en el caso del acceso por SSH), o bien comprobar que las credenciales introducidas (HTTPS) son correctas para el acceso a dicho repositorio.

 

VP1.9  6 / 20  

Page 8: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Una vez hemos asegurado que las credenciales son correctas, debemos especificar la rama sobre la que queremos trabajar; en este caso hemos optado por la rama por defecto (master). El siguiente punto, ‘’Build when a change is pushed to Github” es que el que nos dará la clave para automatizar la tarea que necesitemos. Esta opción indica a Jenkins que debe ejecutar esta tarea cuando alguien realiza un push o un merge en la rama master que hemos configurado, por lo tanto esta opción es vital para poner en marcha nuestro proceso de despliegue automático. Ahora, solo nos quedaría configurar la acción a realizar cuando se detecte un push en nuestra rama master. En nuestro caso, debido a que nuestro servidor Jenkins está instalado en el mismo servidor que nuestro entorno de integración, bastaría con añadir un nuevo paso y ejecutar un comando a través de la shell:

En este caso, el comando básicamente cambia la ubicación del sistema al DOCUMENT ROOT de nuestro servidor apache y realiza un PULL desde la rama master con el usuario developer. Si tuviésemos nuestro entorno de integración en una máquina remota, bastaría con realizar esta misma acción a través de SSH. Con esta tarea ya tenemos nuestro primer despliegue automático a través de Jenkins.

Implementando Drupal Developer Plugin Una vez que hemos visto cómo realizar un despliegue directo a través de Jenkins en un entorno, vamos a añadir una nueva “capa de dificultad”. En este caso vamos a aplicar una validación de código a través del plugin ‘Drupal Developer Plugin’, un módulo de Jenkins que implementa una serie de validaciones de coding estandar y genera las métricas necesarias para evaluar la calidad del código. Este ejemplo sólo sería válido si estamos trabajando sobre un gestor de contenido basado en Drupal y queremos ser respetuosos con los estándares de código. Para ello, antes de crear una nueva tarea, vamos a añadir una nueva configuración a la tarea que hemos creado anteriormente para que ésta solo se lleve a cabo siempre y cuando la validación a través del plugin de Jenkins haya sido satisfactoria. En la configuración de nuestra tarea de despliegue, marcamos la siguiente opción:

 

VP1.9  7 / 20  

Page 9: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Además, vamos a desactivar la opción que activamos anteriormente ‘’Build when a change is pushed to Github” para evitar que esta tarea se ejecute automáticamente, y solo lo haga cuando la tarea que vamos a crear ahora haya cumplido todos los requisitos que necesitamos. En un ejemplo real, realmente esta configuración habría que hacerla después de haber creado la tarea de prueba con el plugin ‘Drupal Developer Plugin’, de lo contrario Jenkins no reconocería la prueba que hemos introducido en este ejemplo, pero la ponemos aquí para darle continuidad a nuestro trabajo. Básicamente estamos especificando que solo se realice un despliegue en nuestro entorno de integración siempre y cuando la tarea ‘Prueba Coder’ se haya ejecutado con éxito. El siguiente paso sería, en primer lugar, instalar los plugins necesarios para Jenkins. Para ello, desde la administración de Jenkins, accedemos a la sección de administración de Plugins:

Una vez aquí, debemos buscar e instalar los siguientes plugins:

● Checkstyle Plug-in: este plugin es necesario para generar las métricas a través de Jenkins y poder evaluar los resultados de los archivos generados.

● Drupal Developer: este plugin realiza una serie de análisis sobre nuestro código fuente para evaluar su calidad, parámetros de seguridad, etc.

No vamos a centrarnos aquí en los pormenores de la instalación, ya que existe documentación en la web oficial de Jenkins sobre estos plugins que describen bastante bien su funcionamiento e instalación. Pasamos pues directamente a crear una nueva con las mismas características que la anterior (Proyecto libre), poniendo el nombre que consideremos oportuno, y pasamos a describir la configuración de la tarea. Para el origen de datos (Github) y la URL del

 

VP1.9  8 / 20  

Page 10: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

repositorio, la configuración sería exactamente la misma, por lo que vamos a obviar de nuevo la explicación de estos parámetros. Como en la anterior tarea desmarcamos finalmente la opción ‘Build when a change is pushed to GitHub’, vamos a marcarla en esta nueva tarea, de forma que sea ésta la que se ejecute en primer lugar, y en caso de éxito pase a la tarea de despliegue como ya configuramos anteriormente. En este caso, tendríamos que añadir un nuevo paso denominado ‘Review code on Drupal’:

En esta prueba, vamos a marcar todos los tests para asegurar la integridad del código en todos sus niveles. Los parámetros a configurar son los siguientes (es necesario pulsar el botón ‘Avanzado’ para ver todas las opciones):

● Drupal root directory: DOCUMENT ROOT de nuestro gestor de contenidos ● Logs directory: directorio en el que el plugin generará los archivos XML con los

resultados de los tests ● Exclude these modules/themes: es importante configurar bien este apartado, ya que

para obtener unos resultados que luego nos sirvan realmente de interés, ignoraremos todos aquellos directorios que no nos vayan a reportar información de interés para nuestro propósito. En nuestro caso, hemos ignorado todas las carpetas de módulos exceptuando la carpeta ‘custom’ o ‘main’ dentro de ‘sites/all/’, ya que es en esta ubicación donde almacenaremos nuestros módulos personalizados, es decir, aquellos que realmente nos interesa evaluar.

Una vez realizado este paso, debemos añadir una acción para poder evaluar los resultados de los tests generados por el plugin. Para ello, hacemos click en ‘Añadir paso’ y agregamos la opción ‘Public Checkstyle analysis results’ con los siguientes parámetros:

 

VP1.9  9 / 20  

Page 11: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Pasamos a describir los parámetros más significativos:

● Checkstyle results: es la carpeta donde el plugin Drupal Developer genera los archivos XML de los resultados de los tests realizados (hemos configurado esta carpeta en el paso anterior). De esta forma, el plugin Checkstyle analizará todos los archivos XML ubicados en este directorio para generar las métricas necesarias.

● Health priorities: desde aquí podemos priorizar las tareas que nos interesa analizar en función de su prioridad

● Status thresholds (Totals): desde aquí podemos configurar el plugin para que su resultado sea exitoso o fallido en función del número de incidencias detectadas y su prioridad. Es aquí donde podemos refinar nuestra herramienta hasta encontrar la flexibilidad/rigidez adecuada para el desarrollo de nuestro proyecto.

Una vez hemos guardado nuestra nueva tarea, es hora de ejecutarla a través de la pantalla principal de Jenkins:

Es importante resaltar que, en el caso de que una tarea haya detectado alguna incidencia, siempre nos resultará muy útil la información que Jenkins almacena para intentar detectar el problema:

 

VP1.9  10 / 20  

Page 12: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Suponiendo que nuestra tarea ha tenido éxito, bien considerando que ha pasado todos los estándares de calidad necesarios, o bien asumiendo que se ha detectado alguna inconsistencia en el código que ha impedido la ejecución de la siguiente tarea, si hacemos click en el desplegable que aparece junto al nombre de nuestra tarea veremos una serie de opciones, entre las que tenemos que elegir ‘Checkstyle Warnings’ (esta opción sólo aparecerá si se ha configurado debidamente el plugin Checkstyle y se han generado los reportes necesarios, en caso contrario sería conveniente revisar los logs para detectar los problemas ocurridos):

 

VP1.9  11 / 20  

Page 13: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Una vez hacemos click, nos apareceŕan por fin las métricas de nuestros resultados:

Podemos resaltar tres secciones interesantes:

● Files: aquí podremos ver un listado general de todos los archivos con problemas detectados, junto al número de incidencias por archivo.

● Warnings: desglose de cada uno de las incidencias detectadas, junto a su prioridad. Además, si hacemos click en alguno de estos errores, el plugin nos presenta el interior del archivo remarcando el error detectado.

● Details: aquí podemos ver una descripción ampliada de los errores detectados

Integrando Phing Para entrar en contexto, Phing es un port de Apache Ant destinado a la ejecución de tareas, como puede ser la creación de carpetas, actualizaciones sobre un repositoiro, elaborar tests de PHP Unit, etc. todo ello configurado en un archivo XML que después será ejecutado por Jenkins. De esta forma, podemos generar un archivo XML con una serie de tests personalizados que luego se integrarán en el flujo de despliegue de Jenkins. En nuestro ejemplo, vamos a elaborar un test personalizado que ejecutaremos con PHP Unit, para luego poder evaluar los resultados obtenidos del test y poder visualizar el resultado de esta información con el ‘xUnit Plugin’ de Jenkins. Bien, de antes ponernos a instalar plugins de Jenkins, es necesario instalar Phing en el servidor de integración continua. La mejor manera de instalar Phing es a través de PEAR y del canal PEAR de Phing, así pues hay que entrar en la terminal e introducir los siguientes comandos:

pear channel-discover pear.phing.info pear install --alldeps phing/phing

pear channel-discover pear.phing.info

 

VP1.9  12 / 20  

Page 14: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Para asegurarnos que la instalación se ha realizado correctamente, podemos ejecutar el siguiente comando en la consola del sistema:

phing -v

Lo siguiente que tendremos que hacer será crear un fichero en la raíz de nuestro proyecto con el nombre build.xml y ahí escribir las tareas o targets. Si ejecutamos ‘phing’ en la consola del sistema, éste intentará localizar el archivo build.xml en el directorio donde hayamos ejecutado el comando. Si no encuentra este archivo, Phing te devuelve un error indicando que no ha encontrado el archivo. Lo bueno de las tareas automatizadas es que no son independientes unas de otras, sino que desde una tarea puedes hacer una llamada a otra o incluso pueden existir tareas que dependan de otras para que puedan ser ejecutadas. No es el objetivo de este manual describir con más detalle la estructura del archivo XML ni su relación de dependencias, aunque existe documentación bastante bien detallada sobre su configuración. El siguiente paso, antes de entrar en el detalle de nuestro archivo XML, será instalar PHPUnit, que es el framework que utilizaremos en este ejemplo para la ejecución de tests unitarios sobre nuestro código. Antes de poder instanciar sus clases y programar la creación de un test, es necesario instalar dicho framework en el sistema. Para ello, podemos descargarlo de su repositorio oficial y ubicarlo dentro de nuestro sistema:

wget https://phar.phpunit.de/phpunit.phar chmod +x phpunit.phar sudo mv phpunit.phar /usr/local/bin/phpunit phpunit --version

Si todo ha ido bien, el sistema nos reportará la versión de PHP Unit instalada. En nuestro ejemplo, usaremos PHPUnit 4.8.24 junto a la versión 5.4.45 de PHP. Damos por hecho que estamos ejecutando estos tests en una máquina con esta versión de PHP o superior instalada.

Elaborando nuestro primer Test Aunque no es objeto de este manual indagar en el uso de PHP Unit para la elaboración de tests unitarios, diremos que PHPUnit se creó con idea de que cuanto antes se detecten los errores en el código antes podrán ser corregidos. Este conocido framework para PHP nos permite crear y ejecutar juegos de tests unitarios de manera sencilla. Como todos los frameworks de pruebas unitarias, PHPUnit utiliza assertions para verificar que el comportamiento de una unidad de código es el esperado. El objetivo de las pruebas unitarias es aislar cada parte del programa y demostrar que las partes de forma individual son correctas. Una prueba unitaria proporciona un contrato escrito que la pieza de código debe satisfacer. Como resultado, las pruebas unitarias encuentran problemas en las fases

 

VP1.9  13 / 20  

Page 15: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

iniciales del desarrollo de software. La idea detras de un assert es crear un objeto, ejecutar algunas funciones y después comprobar su estado interno. Lo mejor es utilizar un ejemplo para ilustrarlo:

class TddTests extends PHPUnit_Framework_TestCase { public function test_tdd_help() { $this->assertEquals(1,1); } }

Como observamos en el código, básicamente lo que hemos hecho es crear una clase TddTests heredada de la clase PHPUnit_Framework_TestCase. Es aquí dentro donde podremos elaborar la programación de los tests. Existen infinidad de asserts proporcionados por PHPUnit para la elaboración y ejecución de diferentes tipos de tests unitarios, aunque en nuestro ejemplo utilizaremos un caso sencillo mediante el assert assertEquals. Este assert compara dos cadenas de texto pasadas por argumento, y nos devolverá un resultado TRUE/FALSE en función de si estas dos cadenas son iguales (TRUE) o diferentes (FALSE). Nuestra función test_tdd_help que invoca al assert devolverá en cualquier caso un resultado positivo, ya que los dos argumentos comparativos que le pasamos a nuestro assert son iguales, no obstante, este ejemplo nos permite hacernos una idea del funcionamiento básico de un assert con PHPUnit y el poder que obtenemos con la ejecución de este tipo de tests. Antes de entrar en la configuración del test unitario a través de Phing, vamos a asegurarnos que nuestro test está bien programado y podemos ejecutarlo sin problemas a través de la consola. De esta forma, si posteriormente nos encontramos con algún problema de configuración, podremos aislar los problemas más fácilmente y detectar con más facilidad el punto de fallo. Para ello, vamos a crear un archivo llamado TddTests.php ubicado, desde el DOCUMENT ROOT de nuestra instalación de Drupal, en sites/all/modules/main/tdd con el siguiente contenido. Aunque la ubicación o los nombres de los archivos pueden cambiar en función de nuestras necesidades, hemos establecido esta ubicación únicamente para ilustrar el ejemplo:

<?php define('DRUPAL_ROOT', '/var/www'); require_once DRUPAL_ROOT . '/includes/bootstrap.inc'; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); class TddTests extends PHPUnit_Framework_TestCase { public function test_tdd_help() { $this->assertEquals(1,1);

 

VP1.9  14 / 20  

Page 16: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

} } ?>

Las tres primeras líneas cargan el bootstrap de Drupal en caso de que tuviéramos que hacer uso de su API. Aunque en este ejemplo no es estrictamente necesario, lo referenciamos por si el lector quiere ampliar el código de este ejemplo apoyándose en la API de nuestro CMS. El resto contiene la clase que hemos comentado anteriormente, integrando el assert assertEquals que, en todo caso, nos devolverá un resultado positivo. Ubicándonos de nuevo en el DOCUMENT ROOT de nuestro portal, ejecutamos en consola el siguiente comando:

phpunit sites/all/modules/main/tdd/TddTests.php

Si todo ha ido bien, el framework nos devolverá la siguiente respuesta por pantalla:

PHPUnit 4.8.24 by Sebastian Bergmann and contributors. . Time: 392 ms, Memory: 42.75Mb OK (1 test, 1 assertion)

En este caso, nos indica que se ha ejecutado un test con un assert, sin ningún error encontrado. Vamos a realizar ahora una modificación en nuestro archivo PHP cambiando el valor de uno de los dos argumentos, de forma que el assert nos devuelva un resultado negativo. Volvemos a ejecutar nuestro comando por consola y ahora el resultado es:

PHPUnit 4.8.24 by Sebastian Bergmann and contributors. Time: 392 ms, Memory: 42.75Mb There was 1 failure: 1) TddTests::test_tdd_help Failed asserting that 0 matches expected 1. /var/www/sites/all/modules/main/tdd/TddTests.php:10 FAILURES! Tests: 1, Assertions: 1, Failures: 1.

 

VP1.9  15 / 20  

Page 17: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

Como vemos en el ejemplo, en esta ocasión, además de informarnos de la ejecución completa del test, nos indica que ha detectado un error, y sabiendo esto, únicamente nos queda recuperar la información resultante del test para poder tratarla con alguna herramienta (¿os imagináis cual?) y poder interactuar con el flujo de despliegue en función de los resultados de los tests. Volvemos pues al punto de partida con Phing. Ahora que ya sabemos para qué sirve PHP Unit, y hemos comprobado su funcionamiento a través de un sencillo ejemplo a través de un comando por consola, estamos preparados para integrar esta funcionalidad a nuestra herramienta de integración continua, estableciendo su configuración con el apoyo de Phing. Vamos pues a crear nuestro primer archivo build.xml en el raíz de nuestro plataforma, o bien ubicarlo en algún directorio que sea accesible con posterioridad con Jenkins. El contenido del archivo es el siguiente:

<?xml version="1.0"?> <project name="MyApplication" default="build"> <property name="package" value="MyApplication" override="true" /> <target name="clean"> <delete dir="../reports"/> </target> <target name="prepare"> <mkdir dir="../reports/logs"/> </target> <target name="phpunit">

<phpunit printsummary="true" haltonfailure="true" pharlocation="/usr/local/bin/phpunit"> <formatter todir="../reports/logs" type="xml"/> <batchtest> <fileset dir="../"> <include name="src/sites/all/modules/main/tdd/TddTests.php"/> </fileset> </batchtest> <formatter type="xml" todir="../reports" outfile="logfile.xml"/> </phpunit> <phpunitreport infile="../reports/logfile.xml" styledir="/usr/share/php/data/phing/etc" format="frames" todir="../reports"/> </target> <target name="build" depends="clean,prepare,phpunit"/> </project>

Como hemos comentado anteriormente, no es objetivo de este manual entrar en profundidad a explicar la creación y configuración de este archivo, no obstante, pasaremos a comentar algunas etiquetas que resultan interesantes para entender su funcionamiento:

● delete dir y mkdir: le indicamos la ubicación de nuestro directorio de reportes para que lo borre antes y lo vuelva a crear de comenzar la ejecución de nuestros tests

● phpunit: le indicamos la ruta de nuestro ejecutable PHP Unit

 

VP1.9  16 / 20  

Page 18: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

● formatter todir: indicamos donde deberán almacenarse nuestros reportes, y en qué formato

Posteriormente indicamos la ruta de nuestro test, además de especificar el nombre de nuestro archivo ‘logfile.xml’ con los resultados de nuestros tests. Como ya hicimos anteriormente con PHPUnit, es hora de probar de forma aislada la composición de nuestro archivo build.xml y comprobar que funciona correctamente antes de integrarlo directamente en Jenkins, de esta forma nos aseguraremos que la estructura de nuestro archivo XML es correcta, y como ya hemos asegurado antes que nuestro test unitario funcionaba correctamente, ahora vamos a subir un nuevo peldaño incluyendo dicha ejecución a través de Phing. Bastaría con ejecutar por consola el siguiente comando en el mismo directorio que hemos creado nuestro archivo build.xml:

phing

Si nuestro archivo build.xml se encuentra en una ubicación diferente, podemos establecer la ruta del archivo con el parámetro -f. Si todo ha ido correctamente, el resultado por consola debería ser similar al siguiente:

Buildfile: /var/www/build.xml MyApplication > clean: [delete] Deleting directory /var/www/reports MyApplication > prepare: [mkdir] Created dir: /var/www/reports/logs MyApplication > phpunit:

[phpunit] Total tests run: 1, Failures: 0, Errors: 0, Incomplete: 0, Skipped: 0, Time elapsed: 0.00471 s MyApplication > build: BUILD FINISHED Total time: 0.1681 seconds

Bien. Llegados a este punto, creo que estamos suficientemente preparados para pasar la ejecución de nuestro test a través de Jenkins, nuestra herramienta de integración continua. Para ello, previamente hay que instalar los módulos ‘Phing Plugin’ para poder ejecutar nuestras tareas a través del archivo build.xml y ‘xUnit Plugin’, que nos permitirá la visualización de las métricas generadas por Phing. No vamos a entrar en más detalles sobre la instalación de Plugins en Jenkins porque ya lo hemos comentado anteriormente. Así que

 

VP1.9  17 / 20  

Page 19: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

pasamos a crear directamente nuestra tarea, siguiendo los pasos anteriormente con el mismo origen de datos, la misma URL de nuestro repositorio, etc. Nos centraremos en la tarea específica que habrá que crear para ejecutar un script de Phing. Para ello, añadiremos un nuevo paso denominado ‘Invoke Phing Targets’. Este paso debería aparecer automáticamente si hemos instalado correctamente nuestros plugins:

El único aspecto aquí a remarcar es el campo ‘Phing Build File’. Simplemente tenemos que indicar la ruta donde hemos creado nuestro archivo build.xml partiendo de nuestro DOCUMENT ROOT. Otro aspecto muy importante a tener en cuenta aquí, y que suele ser la causa de muchos problemas, es el origen de los datos. Esto quiere decir que para que Jenkins pueda leer correctamente nuestro archivo build.xml, éste debe estar versionado en nuestro repositorio, ya que, recordamos, éste es el origen de datos de nuestra tarea en Jenkins, por lo tanto cualquier cambio que hayamos realizado en nuestro archivo build.xml debe estar correctamente actualizado en nuestro repositorio para que Jenkins pueda ejecutarlo. El siguiente paso consiste, dentro de la misma tarea, en añadir una nueva acción ‘Publish xUnit test result report’. Al igual que en el paso anterior, esta acción solo estará presente si hemos instalado correctamente nuestros plugins. Pasamos a describir la configuración de esta acción:

 

VP1.9  18 / 20  

Page 20: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

De esta acción vamos a comentar dos aspectos importantes:

● Ruta de los reportes: es importante recordar que esta ruta debe coincidir con la ruta que hemos configurado en nuestro archivo build.xml de Phing, que es el encargado de generar dichos reportes.

● Failed Tests: aunque es bastante obvio, me limitaré a comentar que aquí podemos configurar la flexibilidad de nuestros avisos, de forma que podamos configurarlo de tal modo que la tarea pueda resultar exitosa o fallida en función del número de tests que se hayan ejecutado con éxito, etc.

Como comentamos en puntos anteriores, esta tarea puede ser configurada para que sea ejecutada antes o después de otras tareas en nuestro proceso de despliegue, aunque una vez conocida la práctica, creo que en este punto tenemos el conocimiento suficiente como para decidir en qué momento necesitamos ejecutar este test.

Web externas ● Jenkins:https://jenkins.io/ ● Phing: https://www.phing.info/ ● PHP Unit: https://phpunit.de/ ● Github: https://github.com/ ● xUnit Plugin: https://wiki.jenkins-ci.org/display/JENKINS/xUnit+Plugin ● Phing Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Phing+Plugin ● Git Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin ● Drupal Developer Plugin:

 

VP1.9  19 / 20  

Page 21: Desplegando código con Phing, PHPunit, Coder y Jenkins

 

 

https://wiki.jenkins-ci.org/display/JENKINS/Drupal+Developer+Plugin ● Checkstyle Plugin: https://wiki.jenkins-ci.org/display/JENKINS/Checkstyle+Plugin

 

VP1.9  20 / 20  

Page 22: Desplegando código con Phing, PHPunit, Coder y Jenkins

www.ladrupalera.com@ladrupalera