Desplegando código con Jenkins, Phing, Coder y PHPUnit (Parte I)

20/04/2016
Desplegando código con Jenkins, Phing, Coder y PHPUnit (Parte I)

El objetivo de esta guía es conseguir configurar Jenkins para realizar una serie de tests antes de desplegar un desarrollo en un entorno concreto. Para ello, se utilizarán las siguientes herramientas:

  • Jenkins: herramienta para poner en práctica la integración continua
  • Phing: vamos a tratar esta herramienta como un automatizador de tareas de PHP. Para aquellos que conozcan Apache Ant, podemos tratarla como un equilvaente, pero especialmente orientado a PHP
  • PHPUnit: framework de PHP que sirve para realizar pruebas unitarias de código. Ilustraremos una prueba sencilla y su uso práctico en un entorno real
  • Coder: herramienta que evalúa el código que generamos para alertarnos cuando nos escapamos del coding estándar que marca la comunidad de Drupal

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, 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’:

1.png

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

2.png

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

3.png

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:

4.png

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.

Implementando 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’:

Panel de control  Jenkins.png

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

Nuevo Tarea  Jenkins .png

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:

Proyecto de prueba Config  Jenkins .png

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:

Emergya thinkbig UK.png

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.

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:

Staging deployment Config  Jenkins .png

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.

En las dos próximas entregas profundizaremos en el uso de Jenkins con la integración de Drupal Developer Plugin para la validación de nuestro coding estandar, Phing para la programación de tareas y PHP Unit para la elaboración de tests unitarios.