Vamos a construir una pipeline para desplegar un proyecto de Azure Functions (AF) programadas con JavaScript en un recurso de Function App Linux en Azure. En el proyecto de estas functions habremos añadido tests unitarios con Jest, que es el framework que Microsoft recomienda para testear AF. Es necesario añadir antes en nuestro proyecto la configuración mostrada en el artículo del enlace anterior.
En el artículo no se explicarán los test unitarios con Jest, sólo como configurar Jest en el proyecto para poder mostrar los test y la cobertura de los test en la build pipeline, así como pasar la cobertura a SonarCloud.
El primer paso para crear la pipeline es tener el código subido en un repositorio GitHub, en nuestro caso está ya DevOps. Previamente tenemos que tener creado un recurso en Azure de una Function App que corra en Linux. En el portal de DevOps nos dirigimos a Pipelines > New Pipeline:
A continuación seleccionamos el repositorio:
Una vez seleccionado el repositorio podremos seleccionar el tipo de pipeline que queremos configurar, aquí es muy importante haber elegido una Function App que corra bajo Linux para poder seleccionar la configuración que queremos:
El siguiente paso es enlazar la pipeline con el recurso en Azure, tendremos que seleccionar la suscripción diponible para continuar:
Y la Function App que solo aparecerá en el listado si es de tipo Linux:
Una vez hecho esto le damos al botón Validate and configure. Y ya tendremos la pipeline configurada para hacer el despliegue en Azure. Podemos seleccionar el botón Save and run par comprobar que la pipeline funciona. Para ver las ejecuciones clicamos en el icono de Pipelines y veremos nuestras pipelines:
Podemos entrar en la ejecución:
Y en Stages y ver el detalle de los pasos:
Ahora ya tenemos la pipeline base creada y nuestras AF desplegadas en Azure:
Vamos a tener que añadir ciertas configuraciones en nuestro package.json para adecuar los resultados que muestra Jest.
Para poder mostrar los resultados de tests en la pipeline, necesitamos instalar en el proyecto jest-unit, que nos generará ficheros junit compatilbes para mostrar los resultados en la pipeline. Actualmente este tipo de ficheros son generados por JaCoCo o Cobertura en proyectos de Java o C#. Simplemente, desde consola en la ruta del proyecto, con npm i --save-dev jest-junit lo tendríamos instalado. El siguiente paso es añadir jest-unit como test results processor por defecto y añadir su configuración en el package.json. En paralelo y necesario para lo anterior, añadiremos la configuración para ejecución de tests en la integración continua en scripts > test:ci. Configuración del proyecto para la ejecución de los tests en la pipeline:
Analizamos los flags que hemos añadido y que podemos revisar en la documentación de Jest para más detalle:
Ahora debemos añadir al proyecto la configuración para los ficheros de jest-unit. Podemos definirlo de la siguiente forma (este ejemplo se encuentra en la documentación de npmjs.org que hemos adjuntado más arriba) en el package.json:
Aprovechamos para repasar la configuración de Jest que ya debería estar en el proyecto a partir de la configuración de la documentación de Microsoft:
Aquí es importante mencionar para los coverageReporters la siguiente funcionalidad:
IMPORTANTE: necesitamos añadir “collectCoverage”: true a jest para que la cobertura aparezca en Sonar cuando la configuremos. Sin esta configuración no aparecerá la cobertura en el portal de Sonarcloud.io aunque tengamos toda la configuración de sonar como aparece en la documentación oficial. Se encontró la solución en este artículo: https://community.sonarsource.com/t/test-coverage-using-jest-sonar-reporter-not-shown-in-ui/29231. Aunque no es necesario usar jest-sonar como se ve en la configuración del artículo. Es un paquete que no está mantenido y desde Sonar se desaconseja su uso. Aquí podemos ver en conjunto todo lo que acabamos de comentar en la configuración de scripts>test y scripts>test:ci:
Si testeamos el flag --testResultsProcessor='jest-junit' en test:
Generaría un fichero junit.xml, necesario para mostrar el resumen de los reports en la build pipeline:
Ahora los siguientes pasos son en la pipeline, para recuperar los ficheros que se están generando en local y mostrarlos en el resumen de la ejecución de dicha pipeline.
Aquí tenemos que tener en cuenta que para conseguir mostrar la cobertura y el resultado de los tests tenemos que añadir nuevas tareas en la pipeline en un orden concreto. Estas serían a groso modo las tareas en la pipeline original:
Y así es como quedaría la pipeline después de añadirle las task necesarias para mostrar el resultado de los tests y la cobertura:
Como se ve, hemos añadido 3 pasos:
Vamos a ver como implementar estas tres tareas ahora que sabemos su lugar en la pipeline.
La primera tarea que vamos a añadir es la ejecución de los tests y lo vamos a hacer mediante la task Npm@1 (docu de la task). Esta tarea nos permitirá ejecutar comandos npm. En concreto queremos ejecutar: npm test:ci, que es el comando que definimos en los scripts del package.json.
Necesitamos ir a pipelines y editar la pipeline que hemos creado.
La tarea debemos añadirla justo debajo de este apartado:
Para añadir una task, el paso 1 es añadir el cursor justo donde vamos a insertar esa task en el fichero, y a continuación, seleccionar la task en el asistente lateral que aparece:
Deberíamos rellenar lo siguiente:
En nuestro caso es un comando custom, queremos que ejecute el test:ci creado y DefaultWorkingDirectory es una variable de DevOps que nos sirve para ubicar nuestro package.json que está en la raíz del Build que hemos hecho.
Deberíamos obtener algo como esto:
Aquí podemos añadir el displayName para que se muestre como nombre de la tarea en la ejecución de la pipeline.
Para publicar los resultados de los test vamos añadir la task PublishTestResults@2 (docu de la task) que seleccionará el fichero junit.xml que hemos visto que aparecerá en el DefaultWorkingDirectory al ejecutarse el comando npm test:ci.
Ahora nos situamos justo debajo de la tarea que acabamos de crear y repetimos el mismo proceso en el buscador lateral:
En esta tarea en concreto vamos a rellenar solamente el campo Test result files con $(System.DefaultWorkingDirectory)/junit.xml pero vamos a necesitar modificar esta tarea para añadir el campo condition, que no aparece en el formulario pero podemos encontrarlo en la documentación y nos permitirá publicar los resultados, quede como quede el test:
Dejaremos esta task así:
El siguiente paso es configurar la cobertura de los tests para que aparezcan en el resumen de la ejecución de la Pipeline.
Para publicar los resultados de los test vamos añadir la task PublishCodeCoverageResults@2 (docu de la task) que seleccionará el fichero cobertura-coverage.xml que hemos visto que aparecerá en el DefaultWorkingDirectory/coverage al ejecutarse el comando npm test:ci. Ahora nos situamos justo debajo de la tarea que acabamos de crear y repetimos el mismo proceso en el buscador lateral:
Seleccionamos Cobertura para el Code coverage tool y en el Summary file añadimos la ubicación del fichero cobertura-coverage.xml que será $(System.DefaultWorkingDirectory)/coverage/cobertura-coverage.xml
La task debería de quedar así:
Ahora ya tenemos preparada la pipeline para que al ejecutarla podamos obtener los resultados de los tests y de cobertura en el resumen de la pipeline.
Al ejecutar las pipeline podremos ver los resultados de los tests:
Y su cobertura:
Ahora como paso opcional podríamos configurar SonarCloud para escaneara nuestor código en tiempo de ejecución. Para esto necesitamos completar los siguientes pasos:
Lo primero es dirigirnos a https://sonarcloud.io/ e iniciar sesión con nuestra cuenta de Azure DevOps. Una vez dentro del portal creamos una nueva organización:
Necesitaremos el nombre de la organización y un token que obtendremos desde Azure DevOps:
Cuando creemos el Token, debemos darle permisos de Full Access:
Después se conectará y elegimos el plan free. Vamos a proceder a instalar la extensión de SonarCloud en Azure DevOps.
En la parte inferior del portal de Azure DevOps seleccionamos Organization Settings > Extensions > Browse marketplace y buscamos sonarcloud:
Y una vez instalada nos aparecerá como extensión:
Ahora ya dispondremos de las tasks de SonarCloud en el listado de la Build Pipeline.
En el portal de Azure DevOps entramos en nuestro proyecto y elegimos en la esquina inferior Project settings > Service Connections > New Service Connection:
Y la rellenamos. Solo necesitamos obtener el token desde el portal de SonarCloud como se indica en el propio formulario Account > Security > Generate Tokens:
Ahora ya podemos configurar nuestra build pipeline con las nuevas tasks para Sonar Cloud.
Necesitamos añadir un fichero sonar-project.properties en la raíz de nuestro proyecto para la configuración de sonar. Los parámetros más importantes serían los de sonar.sources para los directorios a escanear, sonar.tests y sonar.exclusions para el directorio de test.
Es importante para la cobertura en sonar el parámetro sonar.javascript.lcov.reportPaths para el fichero que lleva los datos de la cobertura (docu para configuración de cobertura):
Las tasks de SonarCloud deben ejecutarse justo antes y después de la creación de los artifacts que se usarán para el Stage de Deploy. Actualmente la pipeline estaría así:
Y con las nuevas tareas pasará a estar así:
Añadimos la primera tarea llamada Prepare Analysis Configuration (SonarCloudPrepare@1):
Y seleccionamos los valores. En nuestro caso debemos usar el Standalone Scanner al no ser Java o C# nuestro código y seleccionamos nuestro .properties que tenemos en nuestro proyecto (aunque este campo no es necesario si el fichero se llama como en la imagen).
Debemos situar esta tarea entre la de PublishCodeCoverageResults@1 y ArchiveFiles@2, quedaría:
Nos situamos debajo de la tarea ArchiveFiles@2 y a continuación añadiremos las dos siguientes tasks de Sonar. En estos dos casos, las tasks no requieren de añadir configuración, solo es seleccionarlas y confirmar para añadirlas:
Y esta parte de la pipeline quedaría así:
Ahora ya estaríamos listos para ejecutar de nuevo la pipeline y ver los resultados en el resumen de la pipeline.
Además de los resultados de tests y cobertura en la pipeline ahora en la pestaña Extensions tenemos el resultado del Quality Gate de Sonar:
Desde el enlace podemos dirigirnos al resumen del análisis de Sonar:
Hay 3 apartados importantes aquí: Main Branch Evolution, Main Branch Status y Latest Activity.
En el apartado Main Branch Evolution podemos ver el estado global del proyecto y su evolución a lo largo del tiempo. En este caso, un ejemplo de si empeora nuestro análisis (se ha añadido una function nueva pero no se han añadido los correspondientes tests):
En Latest Activity podemos ver como incrementa o decrementa cada parámetro por análisis respecto al análisis anterior, por ejemplo en el caso de % Coverage o líneas de código. En un análisis en el que no se añadan más líneas de código o haya la misma cobertura tendrémos un 0% y 0 líneas nuevas:
Podemos revisar en Main Branch Status los parámetros configurados para el Quality Gate. Si por ejemplo no pasamos el quality gate en DevOps podemos revisar clicando en “1 failed condition” como desde Main Branch Status:
En este caso el proyecto analizado no ha llegado al 80% de cobertura con los tests y podemos verlo aquí.