Inicio > CI, Delphi, Jenkins, TDD > 4- Integración continua con Delphi (Jenkins) – Pipelines

4- Integración continua con Delphi (Jenkins) – Pipelines

Imagen relacionadaHasta ahora ya hemos visto cómo crear Jobs en Jenkins. Partiendo del que hicimos en la última entrada ya podemos extenderlo (ya sea en un único job o en varios) para conseguir el proceso completo de compilar nuestro proyecto, incluyendo obtener el código GIT, compilar el proyecto y el correspondiente de test unitarios, ejecutar las pruebas y enviar resultados vía email.

Esto sería el “pack” básico, pero a partir de ahí podemos extenderlo según las necesidades. Podríamos desplegar versiones, compilar diferentes ramas desde nuestro repositorio, subir los proyectos a un servidor de preproducción, a un FTP, enviar resultados y comunicados, estadísticas,… y un sinfín de opciones.

Antes de continuar, os adjunto los links de las entradas anteriores:

1- Integración continua con Delphi (GIT)
2- Integración continua con Delphi (Jenkins) – Instalación
3- Integración continua con Delphi (Jenkins) – Primer proyecto
4- Integración continua con Delphi (Jenkins) – Pipelines

INTRODUCCIÓN A LAS PIPELINES

Las pipelines de Jenkins vienen a ser una evolución de los jobs. En una pipeline se definen los diferentes pasos/operaciones del trabajo que vamos a realizar. Algo similar a como hemos hecho anteriormente en un Job, sólo que aquí tenemos mucha más libertad para definirlos.

Las pipelines al final no son más que un programa (escrito en Groovy) que puedes guardar en un fichero (o en un repositorio de código), por lo tanto podemos tener “versionado” de nuestros trabajos, al igual que hacemos con nuestro código. Esta es sólo una de las ventajas de las pipelines, algunas más las iré comentando a lo largo de esta entrada.

Integración continua con jenkins

VENTAJAS DE LAS PIPELINES

Como ya hemos dicho las pipelines son más complejas, pero a la vez mucho más potentes que los Jobs. ¿Qué ventajas nos ofrecen frente a estos?

Flexibilidad

Mayor potencia y flexibilidad a la hora de definir operaciones. Tenemos total libertad (ya que nosotros escribimos el código del programa) de cuando y dónde se realizan las diferentes acciones y el orden en el que las queremos ejecutar. Además disponemos de más opciones para poder pausarlas y esperar a entrada “manuales” antes de poder continuar.

Versionado

Como hemos comentado, las pipelines al final son programas de código interpretados, por lo tanto podemos agregarlos a un repositorio, y tenerlos dentro de un control de versiones. A estas alturas ya no voy a comentar todas las ventajas que esto nos aporta. Jenkins nospermite definir la ubicación del repositorio para el código de la pipeline.

Versatilidad

Las pipelines se adaptan mejor a los requisitos de la Integración continua y del mundo real. Permiten realizar un Fork/Join (bifurcación/unión), permiten generar Loops, y mejoran la ejecución en paralelo frente a los Jobs.

ESTRUCTURA DE UNA PIPELINE

Resultado de imagen de pipeline programmingUna pipeline se escribe como un programa o script que luego es interpretado por la maquinaria de Jenkins. Cuenta con diferentes secciones que vemos a continuación.

Pipeline

Define el proceso competo que representa nuestro trabajo a realizar. es el nodo principal de nuestro programa.

Node

Es un contenedor o máquina que nos permite ejecutar una pipeline en Jenkins.

Stage

Es una agrupación lógica de Steps (o pasos a realizar). Es una forma de organizar nuestras acciones dentro da la pipeline, aunque funcionalmente no tienen contenido.

Step

Es el elemento básico de una pipeline que representa una operación/acción a realizar. Podría ser descargar código del repositorio, compilar, enviar un mail,…

De todos los elementos comentados, hay 2 principales dentro de una pipeline; Los Stages y los Steps.

Resultado de imagen de pipelines en jenkins

TIPOS DE PIPELINES

Sólo como comentario, decir que hay 2 tipos de pipelines.

DECLARATIVE

Tienen un modelo de programación declarativo. Su sintaxis es más simple, y limitado a lo que puede hacer el usuario. Y se declara y ejecuta mediante el comando pipeline y los diferentes Stages, Stage, Steps y Step.

SCRIPTED

Tienen un modelo de programación imperativo. Permite todas las funcionalidades. Y se declara y se ejecuta mediante nodos.

CONSTRUYENDO UNA PIPELINE

Para construir nuestra primera pipeline, debemos crear un nuevo trabajo/job en Jenkins.

Una vez en el editor, veremos que tras las opciones iniciales (generales y de ejecución) nos encontramos con un editor para introducir el código de nuestra pipeline.

Vamos a ver las diferentes secciones de código que podemos utilizar para los elementos más habituales que podemos utilizar en un pipeline. Además intentaremos recrear el JOB que vimos en las primeras entradas, pero en este caso usando pipelines.

Los diferentes elementos los vamos a ver dentro de un Step.

La estructura básica será la siguiente y a partir de ahí iremos añadiendo nuevos Steps.

pipeline {
  agent any
    stages {
      stage('Stage: Hola Mundo') {
        steps {
          echo 'Paso 1. Hola Mundo'
        }
      }
    }
  }

Esto sería el esqueleto más básico. Ya podemos ver un Stage con un Step, que en este caso permitirá visualizar un texto en pantalla.

Si ejecutamos nuestra tarea recién creada veremos que Jenkins nos muestra el resultado de la siguiente forma:

DESCARGA DE FUENTES

Otro de los pasos necesarios que ya hemos visto anteriormente es la descarga del código fuente un repositorio. En el caso de las pipes podemos hacerlo utilizando el siguiente step:

stage('Descargar source de GIT') {
            steps {
                echo 'Descargando...'
                git([url: 'https://github.com/NeftaliBlog/Ejemplos'])
            }
        }

Para ello podemos utilizar el comando git. Hay variantes a este comando. En este caso nuestro repositorio es público. Si fuera privado, deberíamos añadir credenciales o un token de acceso al comando. El token lo podemos obtener desde el propio repositorio. En ese caso el formato sería similar a este:

stage('Descargar código Tests') {
      steps {
            echo 'GIT Pull...'
            git([url: 'https'https://github.com/NeftaliBlog/Ejemplos', 
          branch: 'master', credentialsId: 'a12284da-9dzx-4388-9d6034-472cdrt5633fa4'])
            }
       }

Como podemos ver, además del repositorio, podemos especificar las credenciales utilizando el token credentialsId, y la rama que queremos descargar utilizando el token branch.

COMPILAR UN PROYECTO

Al igual que hicimos cuando explicamos los JOBS de Jenkins, en las pipelines vamos a ver cómo ejecutar un fichero de procesamiento por lotes para compilar nuestro proyecto. El mismo que ya teníamos creado y que utilizamos en el JOB. Para ejecutar un fichero BAT podemos utilizar el comando bat, de la siguiente forma:

stage('Compilando Tests Unitarios') {
            steps {
                //-- Ejecutando fichero BAT de compilacion
                echo 'Ejecutando fichero BAT de compilacion'
                bat '"c:\\Proyectos\\Proyecto Pruebas CI\\tests\\compilar.bat"'
            }
        }

Hay que tener en cuenta que los path deben escribirse con dobles barras invertidas (\\) y que podemos utilizar variables de entorno.

A medida que vamos añadiendo pasos, la salida de la compilación nos va mostrando datos sobre el resultado de cada uno de ellos.

VARIABLES DE ENTORNO

Ya que hemos hablado de ellas, dentro de una pipeline podemos utilizar variables de entorno (y definir nuevas). Para definirlas podemos hacerlo en la zona de environment de la siguiente forma:

pipeline {
agent any
environment {
color = 'blue'
BASE_DIR='f:\\Proyectos\\Proyecto Pruebas CI'
}
stages  {
…

Y para referirnos a ellas utilizaremos el nombre entre %%. Como ejemplo, dentro de nuestra pipeline podemos utilizar un código como este.

 

stage ('Variables de entorno...') {
steps {
echo '----------------------------------------------------------'
bat '@echo Jenkins path: %JENKINS_HOME%'
bat '@echo Workspace: %WORKSPACE%'
bat '@echo Build number: %BUILD_NUMBER%'
bat '@echo Base dir: %BASE_DIR%'
echo '----------------------------------------------------------'
echo env.BUILD_NUMBER
echo env.BASE_DIR
echo '----------------------------------------------------------'
}
}

Arriba hemos definido la variable de entorno BASE_DIR y además podemos visualizar otras de las que tenemos disponibles. El resultado de la consola para esta ejecución será similar a este:

Una cosa muy útil es saber todas las variables de entorno que tenemos disponibles para utilizar en nuestra pipeline. Lo podemos hacer con un step utilizando el comando bat(‘set’), de la siguiente forma (utilizamos un step):

stage ('Lista de variables de entorno disponibles'){
steps{
//-- Todas las variables de entorno
echo '=========================================='
echo '           VARIABLES DE ENTORNO DISPONIBLES '
echo '=========================================='
bat('set')
echo '=========================================='
}
}

Y la salida que obtendremos será similar a esta; Os adjunto este link para abrirlo en una nueva ventana con la imagen completa para verlo mejor –es una imagen, se puede utilizar zoom-.

EJECUTAR UN PROYECTO

Seguimos avanzando. Una vez compilado nuestro proyecto de test unitarios, lo siguiente que queremos es ejecutarlo para detectar que nuestros tests siguen siendo correctos. Este es un paso previo necesario y obligatorio antes de continuar con la compilación del proyecto.

Para ello, tal como hicimos en la compilación, podemos utilizar un fichero por lotes (yo lo prefiero porque me permite hacer variaciones sin tener que modificar el código de la pipeline) o directamente llamar al ejecutable. Ambos mediante el comando bat.

El código a utilizar es el siguiente (para ambos casos):

stage('Ejecutar test unitarios BAT/CMD') {
  steps {
        //-- Ejecutar test unitarios BAT/CMD
       echo 'Ejecutar test unitarios BAT/CMD'
       bat '"c:\\Proyectos\\Proyecto Pruebas CI\\tests\\ejecutar.bat" RELEASE'
       }
  }
stage('Ejecutar test unitarios EXE') {
   steps {
      //-- Ejecutar test unitarios EXE
      echo 'Ejecutar test unitarios EXE'
      bat '"%BASE_DIR%tests\\PTestFunciones.exe"'
       }
   }

Si ejecutamos nuestra pipeline, con todos los pasos vistos hasta ahora, el resultado obtenido será el siguiente:

Nuestro último paso ha sido el de ejeciutar los test unitarios. Si vemos la salida de consola de la aplicación podemos ver los resultados de los test. Jenkins reconoce de forma automática la salida de los test unitarios generados con DUnitX (paquete recomendado para las ultimas versiones de delphi). De esta forma si los test fallaran, la pipeline nos daría un resultado erróneo.

A continuación vemos el trozo final de la salida de consola de esta ejecución donde bvemos el resultado de los tests.

Llegados a este punto si los test se han ejecutado sin problemas (Jenkins reconoce los resultados) podemos continuar adelante. Los siguientes pasos son compilar y ejecutar el proyecto que realmente nos interesa. No me voy a extender en esto, porque el sistema es el mismo que hemos utilizado para el proyecto de tests automáticos que acabamos de ver.

Añadiríamos el código siguiente que compila nuestro proyecto, similar a la que hemos usado para el proyecto de pruebas.

        stage('Compilando proyecto') {
            steps {
                //-- compilar proyecto
                echo 'compilar proyecto'
                bat '"%BASE_DIR%compilar.bat"'
            }
        } 

Con esto ya tenemos nuestra pipeline completa. Si la ejecutamos podemos ver el resultado:

Y a continuación os pongo lo que sería la salida de consola de la ejecución completa, donde se pueden ver todos los pasos que se van ejecutando.

Con esto completo esta entrada y la serie sobre Jenkins y automatización. Al final se ha alargado un poco, pero no quería dejarla a medias.
El tema es mucho más extenso, pero creo que hasta aquí ya he tratado lo suficiente para iniciar y probar si es necesario.

Como siempre comentarios, sugerencias y críticas (constructuivas) son bienvenidas.

Hasta la próxima.

BIOBLIOGRAFÍA ÚTIL SOBRE EL TEMA

https://code-maven.com/jenkins-pipeline-short-text
https://code-maven.com/jenkins-pipeline-environment-variables
https://sdos.es/blog/la-integracion-continua-actual-pasa-por-pipelines
https://www.edureka.co/blog/jenkins-pipeline-tutorial-continuous-delivery
https://opensource.com/article/19/9/intro-building-cicd-pipelines-jenkins
https://pipelinedriven.org/article/pipeline-driven-vs-we-have-jenkins-jobs
https://devops.stackexchange.com/questions/4611/jenkins-job-vs-jenkins-pipeline
https://jenkins.io/doc/book/pipeline/
https://www.paradigmadigital.com/dev/pipelines-de-jenkins-evolucion-continuous-delivery/
https://sdos.es/blog/la-integracion-continua-actual-pasa-por-pipelines
https://codingpotions.com/jenkins-integracion-continua

5/5 - (2 votos)
Categories: CI, Delphi, Jenkins, TDD Tags: , , , ,
  1. Sin comentarios aún.
  1. Sin trackbacks aún.