Construir una pipeline para Azure Functions con Node

INTRODUCCIÓN

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.

CREACIÓN DE LA BUILD PIPELINE

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:

Construir una pipeline para Azure Functions con Node

A continuación seleccionamos el repositorio:

pipeline para Azure Functions con Node

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:

Pipeline Azure Functions

El siguiente paso es enlazar la pipeline con el recurso en Azure, tendremos que seleccionar la suscripción diponible para continuar:

Azure Functions

Y la Function App que solo aparecerá en el listado si es de tipo Linux:

Function App

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:

pipeline azure

Podemos entrar en la ejecución:

pipeline con azure functions

Y en Stages y ver el detalle de los pasos:

stages azure pipeline

Ahora ya tenemos la pipeline base creada y nuestras AF desplegadas en Azure:

sandbox azure functions

CONFIGURAR EL PROYECTO EN VSCODE Y EDITAR LA BUILD PIPELINE

Vamos a tener que añadir ciertas configuraciones en nuestro package.json para adecuar los resultados que muestra Jest.

Instalar y configurar jest-unit

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:

scripts azure

Analizamos los flags que hemos añadido y que podemos revisar en la documentación de Jest para más detalle:

  • --ci: Cuando se activa esta opcion Jest asume que se esta corriendo en un entorno de Integración Continua CI.
  • --coverage: Indica que la información de cobertura de prueba debería ser recolectada.
  • --colors: Resultados forzados de pruebas se muestran resaltados incluso si stdout no es un TTY.
  • --maxWorkers: Especifica el número máximo de trabajadores que el pool de trabajadores creará para correr las pruebas. Para asegurarnos que Jest no afecta en el rendimiento de la pipeline.
  • --testResultsProcessor: este flag está documentado aquí. Es para señalar que processor queremos usar por defecto.

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:

jest unit azure

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:

jest azure

Aquí es importante mencionar para los coverageReporters la siguiente funcionalidad:

  • Lcov: será necesario para mostrar la cobertura en SonarCloud y generará el fichero lcov.info
  • Text: nos permitirá ver por consola los resultados de los tests al ejecutar un npm test.
  • Cobertura: genera el fichero cobertura-coverage.xml.

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:

resumen scripts azure

Si testeamos el flag --testResultsProcessor='jest-junit' en test:

test azure

Generaría un fichero junit.xml, necesario para mostrar el resumen de los reports en la build pipeline:

junit azure

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.

MODIFICAR LA BUILD PIPELINE PARA MOSTRAR EL RESULTADO DE LOS TEST Y LA COBERTURA

Qué vamos a añadir en la build 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:

esquema pipeline azure

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:

esquema tareas pipeline azure

Como se ve, hemos añadido 3 pasos:

  • Ejecución de los test:ci que configuramos en el apartado anterior.
  • Publicar los resultados de los tests para que estén disponibles en la pipeline.
  • Publicar la cobertura de los tests para que estén disponibles en la pipeline.

Vamos a ver como implementar estas tres tareas ahora que sabemos su lugar en la pipeline.

Añadir la ejecución de los test:ci

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.

azure function node

La tarea debemos añadirla justo debajo de este apartado:

azure script prepare binaries

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:

anadir tarea azure functions

Deberíamos rellenar lo siguiente:

npm azure

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:

raiz build azure functions

Aquí podemos añadir el displayName para que se muestre como nombre de la tarea en la ejecución de la pipeline.

Publicar los resultados de los tests en 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:

tests results azure

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:

tabla test results azure

Dejaremos esta task así:

task azure

El siguiente paso es configurar la cobertura de los tests para que aparezcan en el resumen de la ejecución de la Pipeline.

Publicar la cobertura de los tests en 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:

busqueda task

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

tabla code coverage results azure

La task debería de quedar así:

tyask code coverage azure

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:

resultados test sonar azure

Y su cobertura:

resultados test cobertura azure

AÑADIR SONAR CLOUD A LA BUILD PIPELINE

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:

  1. Entrar en sonarcloud.io con nuestra cuenta de AzureDevOps > Crear una organización y enlazarla a nuestra organización de DevOps mediante la url
  2. Desde Azure DevOps instalaremos la extensión de Sonar Cloud
  3. Desde Azure DevOps creraremos una Service Connection con nuestra organización de SonarCloud mediante un Personal Access Token que obtendremos en Sonarcloud y añadiremos a nuestra service connection
  4. Añadiremos las 3 tasks necesarias de SonarCloud en nuestra build pipeline.

Crear una organización en SonarCloud

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:

portal sonar cloud azure

Necesitaremos el nombre de la organización y un token que obtendremos desde Azure DevOps:

crear organizacion azure

Cuando creemos el Token, debemos darle permisos de Full Access:

permiso tokens azure

Después se conectará y elegimos el plan free. Vamos a proceder a instalar la extensión de SonarCloud en Azure DevOps.

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:

azure devops

Y una vez instalada nos aparecerá como extensión:

extension azure instalada

Ahora ya dispondremos de las tasks de SonarCloud en el listado de la Build Pipeline.

Crear una Service Connection de SonarCloud en Azure DevOps

En el portal de Azure DevOps entramos en nuestro proyecto y elegimos en la esquina inferior Project settings > Service Connections > New Service Connection:

crear 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:

token sonar connection

Ahora ya podemos configurar nuestra build pipeline con las nuevas tasks para Sonar Cloud.

Configurar el fichero properties de SonarCloud en nuestro proyecto

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):

propiedades sonar connection azure

Añadir las tasks de Sonar Cloud a la build pipeline

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í:

tasks de sonar cloud azure

Y con las nuevas tareas pasará a estar así:

new tasks de sonar cloud

Añadimos la primera tarea llamada Prepare Analysis Configuration (SonarCloudPrepare@1):

añadir primera tarea azure

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).

seleccionar valores azure

Debemos situar esta tarea entre la de PublishCodeCoverageResults@1 y ArchiveFiles@2, quedaría:

situar tarea

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:

  1. Run Code Analysis - SonarCloudAnalyze@1
  2. Publish Quality Gate Result (dejaremos el timeout a 300 por defecto) - SonarCloudPublish@1

2 nuevas tasks

Y esta parte de la pipeline quedaría así:

pipeline tareas final

Ahora ya estaríamos listos para ejecutar de nuevo la pipeline y ver los resultados en el resumen de la pipeline.

RESULTADOS DE LA BUILD 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:

resultado quality gate de sonar

Desde el enlace podemos dirigirnos al resumen del análisis de Sonar:

resumen del analisis del 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):

azure function node test

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:

latest activity azure

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:

main branch status

En este caso el proyecto analizado no ha llegado al 80% de cobertura con los tests y podemos verlo aquí.

 

 

 

 

 

 

Tags

He leído y acepto la política de privacidad
Acepto recibir emails sobre actividades de recruiting NTT DATA