DevOps serie CI/CD en SAP BTP (todo en uno)

Esta es la recopilación de todas las entradas de CI/CD para BTP que he ido publicando a finales de 2021.

Pero antes de empezar con esta serie, un poco de contexto para entender lo que vamos a hacer.

Tabla resumen de contenido

Un poco de contexto

El motivo de esta entrada es mostrar como montamos nuestro sistema de despliegues o sistema de continuos integration and delivery de manera fácil utilizando todo lo que tenemos disponible en SAP BTP.

Existen otras maneras de hacer estos despliegues como Bitbucket, AzureOps o Jenkins. Uses la herramienta que uses la idea detrás de este concepto no deja de ser la de poder desplegar aplicaciones o mejoras a nuestro software de una manera rápida y con una frecuencia alta.

Esto se consigue mediante la automatización de tareas, entra las que se encuentran el testing y el transporte del código.

Estos son algunos de los beneficios de de utilizar Integración continua.

6 Beneficios de la Integración Continua “CI” – SmartNodus

Esta es una pata mas del famoso Devops, que mediante algunas practicas, agrupan el modelado, desarrollo, despliegue y control del software de una manera ágil.

Sentando las bases de la metodología DevOps

Y aquí me voy a poner un poco critico, ya que una Devops no es una cultura, pero obliga a un cambio cultural en la parte de IT de la empresa. Si que es cierto que podríamos activar todos los servicios de BTP usados en esta serie y en otros post del blog y decir, hemos desarrollado un marco de Devops y a demás tenemos los mejores sistemas de CI/CD (Continuous integration and delivery), somos un ejemplo a seguir, pero…

  • Como automatizamos pruebas si los tiempos de desarrollo se acortan tanto que casi no se puede ni desarrollar el software con calidad.
  • Como definimos un flujo de trabajo continuo, por ejemplo con Kanban si los distintos departamentos no entienden que las tareas solo puede progresas, nunca ir para atrás para ser redefinidas a media construcción.

Estas son reflexiones que cualquier departamento de IT debería hacerse para moderniza su operativa. El objetivo de esta serie es que veáis los distintos pasos y sus dificultades o facilidades para que en el momento de implementar Devops (y en esta serie concreta CI/CD) podáis valorar la dificultad.

Espero que os guste y que lo disfrutéis igual que lo he disfrutado yo.

Preparativos en nuestras subaccount de desarrollo

Todos estos servicios los activaremos en nuestra cuenta de desarrollo que es donde se cuecen los cambios hacia los siguientes sistemas.

Activaremos estos servicios, “Cloud transport management”, “Continuous Integration & Delivery” y una instancia de
Launchpad Service. Esto lo hacemos ya que por un lado necesitamos la aplicación SaaS para que nos haga cada una de las acciones y por otro lado las instancias que nos permitirán tener APIs para conectar los distintos servicios.

Preparación del servicio Continuous Integration & Delivery

activamos el servicio

Veremos el servicio apunto cuando nos aparezca una instancia activa, con lo que ya podremos ir al servico de CI/CD

Preparación del servicio Transport cloud management

Como en el paso anterior vamos a crear una instancia de transport cloud management

Activaremos el tipo “Subscription” y seleccionaremos el plan “standard”

Este es el resultado:

Adicionalmente necesitaremos una instancia del transport management para poder conectar nuestro servicio de CI /CD con el transport management.

Estos serán los datos a seleccionar:

Una vez creada la instancia generaremos una service key:

En el wizard añadimos el Id de la key y pulsamos crear:

Destination a la subaccount despliegue

Solo nos queda crear una destination para poder conectar el transport management con nuestra subcuenta. Vamos al apartado de destinations, pero antes necesitaremos recopilar estos datos:

Zona y SubOrg:

Space:

Con estos datos tendremos el endpoint de publicación:

https://deploy-service.cfapps.<<ZONA>>.hana.ondemand.com/slprot/<<SUB_ORG>>/<<SPACE>>/slp

Y este es el resultado de la destination, en credenciales añadiremos los datos de nuestra cuenta CF

Toda la infraestructura apunto, vamos a por la parte de seguridad.

Permisos para “Cloud transport management” y “Continuous Integration & Delivery”

Añadimos nuestros usuarios los roles necesarios para acceder a las herramientas de integración continua.

Creando un role collection para Cloud transport management

Primero crearemos un rol para los transportes:

Lo siguiente sera añadir los roles al Role collection:

Aquí añadiremos algunos de los siguientes roles. Para simplificar yo los añadiré todos, pero tenéis todo el detalle de que contiene cada rol

https://help.sap.com/viewer/7f7160ec0d8546c6b3eab72fb5ad6fd8/Cloud/en-US/51939a49db9749578b7e237139bfd08d.html?q=Exportoperator

Como truco, para tenerlos identificados podéis filtrar por “Application Identifier” = “alm”

También añadiremos los roles para la instancia que hemos creado de CD/CI:

Asignación de roles

Ha llegado el momento de añadir todos los role collections a nuestro usuario des de la pestaña Users:

Añadimos los siguientes roles relacionados con el servicio de “Continuous Integration & Delivery” a nuestro usuario.

También añadimos el servicio de Cloud transport management:

Sincronizando la aplicación en BAS con GIT

Este primer punto, si ya dominas Github te lo puedes ahorrar, pero lo considero importante ya que en muchas ocasiones la gente me pregunta sobre este tema y como empezar un proyecto en BAS con un GIT.

Para este ejemplo usaré Github, así que lo primero sera crear un repositorio, os pongo un ejemplo:

Lo siguiente es crear una aplicación con el template. Aquí me permitiréis saltarme todos los pasos porque ya los tendréis muy vistos. Solo os pongo un pantallazo del mas interesante, el último.

Lo siguiente es sincronizar nuestro proyecto con el repositorio git. Para ello, indicaremos que queremos trabajar con git y luego fijaremos la URL.

El primer comando a ejecutar será “git init”

El siguiente paso es fijar la URL:

git remote add origin PATH/TO/REPO

Ya estamos casi conectados, ahora descargaremos el contenido de nuestro repositorio remoto con “git fetch” a diferencia de un pull, el comando fetch actualizará la información de metadatos, sin descargar los ficheros que estén disponibles en nuestro repositorio. Con ello, también tendremos la información de las ramas.

Hacemos reset y conectamos a la rama “main”

Hacemos checkout hacia la rama “main”

Lo siguiente es añadir los ficheros a subir al repositorio con “git add .” y luego “git commit”

Y por ultimo… git push para subir el contenido con “git pull”.

Si tenéis algún problema , volvéis a ejecutar git add, git commit y solucionado 😉

Con estas operaciones ya tenemos nuestro repositorio apunto para los siguientes pasos.

Generando MTAR ( SAP Continuous integration & Delivery ) de manera manual

Lo siguiente sera preparar el servicio para generar el fichero MTAR cuando los cambios lleguen a la rama master/main. Para simplificar, no utilizaremos GIT Flow en esta fase inicial, lo veremos mas adelante, enviaremos de momento los cambios de nuestro código a nuestra rama master… Ya sabes, esto solo es para fines educativos 😉

En entornos de desarrollo podemos habilitar los permisos de desarrollador para nuestra cuenta CF pero nos exponemos a que el desarrollador pueda borrar instancias del space, así que podríamos decir que el rol de desarrollador de una cuenta foundry debería ser el de un responsable de desarrollo.

El MTAR lo podemos generar fácilmente des de nuestra subcuenta cuenta BTP, pero si queremos un proceso automático podremos utilizar el servicio “Continuous integration & Delivery”.

Este es su acceso:

Una vez en el servicio, crearemos un JOB. Este será el responsable de recibir los avisos cuando la rama del GIT se modifique y ejecutará los pasos para construir nuestro MTAR.

Añadiendo las credenciales

Creando las credenciales en GITHUB

Lo primero sera añadir nuestras credenciales en un baúl seguro, lo mínimo es añadir las credenciales de Github. Pero antes, necesitaremos obtener estas credenciales. Actualmente muchos de los repositorios git solicitan credenciales temporales. (Veréis que mas o menos todos los git funcionan igual)

Así que vamos a generar las credenciales git. Accedemos a github y pulsamos sobre nuestro perfil y en la opción “settings”:

En el menu izquierdo de “settings”, pulsamos sobre “Developer settings”, luego “Personal access tokens” y por último en “Generate new token”.

Para generar el token necesitaremos informar alguna configuración, os pongo un ejemplo NADA PRODUCTIVO, ya que no caduca nunca el password y le he dado todos los permisos. Finalmente pulsamos “Generate token”

Una vez generada ya tendremos la “contraseña”, guardarla en un sitio seguro ya que una vez cerrada la ventana no lo podremos volver a recuperar.

Guardando las credenciales de Github

Podemos volver al servicio de CD/CI y crear un nuevo baúl de credenciales:

Añadimos las credenciales GIT, estas serán del tipo “Basic Authentication”

Añadiendo las credenciales de la instancia de transport management

En esta parte, necesitaremos los datos de la key generados en el punto “Transport cloud management“. Estos datos los encontraremos en:

Necesitaremos copiar el json que nos muestra la opción “view”.
Creamos unas nuevas credenciales como en el paso anterior, es decir:
Y seleccionamos el tipo “Service Key”, a parte añadiremos el json copiado en el paso anterior:

Ya lo tenemos todo apunto a nivel de seguridad, vamos a por el repositorio.

Añadiendo el repositorio

Con las credenciales apunto, vamos a registrar el repositorio. Vamos a la opción Repositories y pulsamos el boton “+”.

Lo siguiente es obtener la URL de nuestro repositorio, para ello, vamos a Github, al repositorio y pulsamos sobre “Code”. Allí está la URL de clonado:

Con estos datos ya tenemos todo lo necesario para finalizar el registro del repositorio.

Creando el JOB

Vamos a por el último paso, el job:

Lo primero sera añadir la configuración del repositorio. En el JOB podemos tener varios generadores de MTAR uno por cada rama, por ejemplo uno para la rama de desarrollo y otro para la master.

Los primeros datos que añadiremos son el repositorio que hemos dado de alta antes, y la rama.

En la sección de stages se configura los pasos para generar la aplicación. Esto puede incluir validaciones de código, compresión de ficheros, etc… si somos muy restrictivos podríamos bloquear la generación del código si no cumple alguna de las directivas. pero esto lo veremos mas adelante.

De momento activaremos lo que nos requiere menos esfuerzo “Lint Check” que nos validará los ficheros XML y JS. Así quedara nuestra configuración.

Por último pulsamos en “Create” y probaremos el job de manera manual pulsando al botón play.

Validamos el resultado, si todo es correcto esto es lo que veremos

Siguiente paso, vamos a configurar el servicio de transport management y a conectarlo con este servicio.

Desplegando el MTAR (Transport cloud management)

Lo primero para poder desplegar un MTAR es preparar nuestro entorno. En esta fase solo prepararemos el entorno de desarrollo. Los que leéis el blog con regularidad, esta parte os sera familiar, pero en este caso no tendremos que subir el MTAR de manera manual .

Esto lo podríamos hacer con el servicio de Continuous integration & Delivery pero ese servicio nos obliga a construir el MTAR por cada entorno, aquí buscamos poder distribuir de manera rápida y fácil el código de desarrollo a productivo.

Preparando el entorno de transporte a desarrollo

Vamos a preparar el entorno de desarrollo con la destination que creamos en la fase de preparación. Para ello, vamos al servicio de transport management:

Creamos un nuevo entorno de la siguiente manera

Y estos los datos que añadiremos en configuración.

Ahora volveremos a nuestro servicio de SAP Continuous Integration and Delivery para habilitar el envío del MTAR al transport management.

Seleccionamos nuestro JOB y informamos los datos que hemos creado previamente, es decir, activaremos la release, añadiremos el nombre del Nodo creado y las service key creadas en “Credentials”:

Volvemos a hacer un test con el botón de play y este es el resultado, veréis que este es el cuarto intento… he tenido algún problema de permisos, pero para vosotros sera transparente porque ya esta actualizado ;):

Y aquí vemos como ha llegado el MTAR al Cloud transport management.

Por último para probar si funciona el import, realizaremos el import de manera manual a partir de la cola.

Y este es el resultado, como veis, un aprobador necesita iniciar el transporte. Para poder hacer UTs o UATs en desarrollo no seria necesario este paso, pero como os he comentado vamos a ir añadiendo poco a poco toda la configuración.

Por ultimo validamos si se ha transportado realmente:

Validaciones automáticas de código

Test unitarios automáticos

Preparando QUnit

El siguiente paso es preparar los test unitarios. Estos se deben desarrollar de manera manual, pero nos permiten añadir checks para acelerar y automatizar algunos test. Podemos testear por ejemplo formatters, o funciones para asegurar que los futuros cambios no contienen bugs que puedan afectar al programa.

Serán necesario algunos preparativos previos para nuestra aplicación de test. Para ilustrar este paso solo validaremos que el controlador arranca con el onInit y que los textos están bien traducidos.

Crearemos nuevos ficheros i18n con traducciones en español e inglés. Estos son los añadidos en nuestra aplicación:

En cada archivo añadimos los textos traducidos, para este ejemplo solo utilizaré el texto “text”.

Lo siguiente sera programar los test del controlador de la primera vista, por lo que añadiremos el siguiente código en el js:

Y este es el código que añadiremos, mucha atención a los IDs del controlador y de la aplicación.

/*global QUnit*/

sap.ui.define([
	"sap/ui/base/ManagedObject",
    "sap/ui/core/mvc/Controller",
    "ecastella/cdci_btp/controller/View1.controller",
	"sap/ui/thirdparty/sinon",
	"sap/ui/thirdparty/sinon-qunit",
	"sap/ui/model/resource/ResourceModel"
], function (ManagedObject,Controller,AppController,sinon,sinonqunit,ResourceModel) {
	"use strict";
    
	QUnit.module("Controller View1 check",
	{
			before: function () {
                //Carga de los ficheros de texto
				this.applicationName = "ecastella.cdci_btp";
				sap.ui.getCore().getConfiguration().setLanguage( "es" );
				this._oResourceModel_es = new ResourceModel({
					bundleUrl : jQuery.sap.getModulePath(this.applicationName, "/i18n/i18n.properties")
				});
				sap.ui.getCore().getConfiguration().setLanguage( "en" );
				this._oResourceModel_en = new ResourceModel({
					bundleUrl : jQuery.sap.getModulePath(this.applicationName, "/i18n/i18n.properties")
				});
			},
		
			beforeEach: function() {
			this.oAppController = new AppController();
			this.oViewStub = new ManagedObject({});
			//Obtenemos la vista associada al controlador
			sinon.stub(Controller.prototype, "getView").returns(this.oViewStub);

		},

		afterEach: function() {
            // Eliminamos las vistas una vez finalizada la UT
			Controller.prototype.getView.restore();
            this.oViewStub.destroy();

		},
		
			teardown: function () {
                // Por ultimo eliminamos el controlador
				this._oResourceModel.destroy();
			}
		}
    );

    QUnit.test("Check init controller", function (assert) {
		//Obtenemos el controlador
		//Lanzamos el metodo on init
		this.oAppController.onInit();
		assert.ok(this.oAppController);
	});
    
    QUnit.test("Check text i18n", function (assert) {
		//Obtenemos el controlador
		var texti18nEs = this._oResourceModel_es.getResourceBundle().getText("text");
		var texti18nEn = this._oResourceModel_en.getResourceBundle().getText("text");
		assert.strictEqual(texti18nEs,"Esto es un ejemplo", "Text (ES) correct");
		assert.strictEqual(texti18nEn,"This is an example", "Text (EN) correct");
	});

});

Con todo esto, tenemos dos visiones distintas, la del desarrollador que ejecutará los test a medida que vaya finalizando sus módulos y la del transport management que ejecutará los test y bloqueará la subida en caso de error.

Lo siguiente es generar el marco de pruebas, que como en el caso anterior, aunque ya lo tenemos incluido en la plantilla del proyecto, para CI/CD necesitaremos añadirlo en la raíz de la aplicación (carpeta webapp)

Añadimos al fichero package.json dentro de la carpeta webapp las dependencias de Karma que nos permitirá simular el navegador para ejecutar los test QUnit, que nos permitirá ejecutar los unit test:

        "karma": "^5.0.4",
        "karma-chrome-launcher": "^3.1.0",
        "karma-coverage": "^2.0.2",
        "karma-ui5": "^2.1.0"

Este es el resultado:

Añadimos los scripts de Karma

        "test": "npm run karma-ci",
        "karma-ci": "karma start karma-ci.conf.js

Ahora en la misma carpeta webapp añadiremos el fichero “karma.conf.js”, este fichero tiene la configuración de navegador que se utilizará, este será el contenido:

module.exports = function(config) {
    "use strict";
    config.set({
        frameworks: ["ui5"],
        browsers: ["Chrome"],
        browserConsoleLogOptions: {
            level: "error"
        }
    });
};

Añadimos el fichero “karma-ci.conf.js” con el resto de configuraciones, entre ellas las carpetas donde se alojan los ficheros a simular de la aplicación. El objetivo es ejecutar los test de QUnit, así que estos serán los ficheros incluidos en la configuración.

module.exports = function(config) {
    "use strict";
    require("./karma.conf")(config);
    config.set({
        preprocessors: {
            "{webapp,webapp/!(test)}/!(mock*).js": ["coverage"]
        },
        coverageReporter: {
            includeAllSources: true,
            reporters: [
                {
                    type: "html",
                    dir: "coverage"
                },
                {
                    type: "text"
                }
            ],
            check: {
		statements: 100,
		branches: 100,
		functions: 100,
		lines: 100
                }
            }
        },
        reporters: ["progress", "coverage"],
        browsers: ["ChromeHeadless"],
        singleRun: true
    });
};

Ya esta toda la configuración preparada para poder ejecutar por parte de CD/CI nuestra aplicación demanera automática.

UTs iniciadas por el desarrollador (QUnit)

En tiempo de desarrollo se pueden ir lanzando de manera automática las pruebas unitarias a fin de validar la aplicación de una manera rápida y poder conocer de antemano so podremos hacer el deploy hacia productivo.

Para poder ejecutar los test de manera rápida des de Business application studio nos fijaremos en los comandos que el template de la aplicación nos da, para ello iremos al fichero package.json:

Para ejecutar el test podemos pasar el ratón por sobre del script que queremos ejecutar (esperando un par de segundos) y pulsamos “Run script”.

La otra manera es por consola, que es como lo ejecutará nuestro sistema de CI/CD. Para lanzar los test vamos a la consola y ejecutamos el comando “npm run unit-tests”:

Y este será el resultado, automáticamente se abre una nueva pestaña en el navegador y si todo esta correcto veremos los test en verde, los errores los dejamos para cuando tengamos integrados los test a la generación del MTA.

Acordaros de matar el proceso “control + c” para que no de muchos problemas durante el desarrollo. Esto nos permitirá agilizar durante el desarrollo las pruebas unitarias

Validación automática de código

Preparando ESlint

Una cosa que puede ser interesante, sobre todo en Javascript, donde el código no va compilado, es pasar validaciones de código para poder comprobar de manera automática si tenemos alguna cosa en el código mal.

Un ejemplo seria no cerrar una instrucción de código en Js con “;” . Esto no seria un error ya que nuestro navegador puede interpretarlo, pero no esta de mas que no tengamos estos fallos en el código.

Aunque este paso lo podemos hacer automático con el template, el template lo prepara para tener todo en la raíz por lo que luego SAP Continuous Integration and Delivery no lo reconocería.

Por lo que vamos a hacer las siguientes configuraciones en nuestro proyecto des de BAS:

Creamos un fichero llamado “.eslintrc” un la raíz de la carpeta webapp con el siguiente contenido:

{
  "plugins": ["@sap/ui5-jsdocs","eslint-plugin-fiori-custom"],
  "extends": ["plugin:@sap/ui5-jsdocs/recommended", "eslint:recommended","./node_modules/eslint-plugin-fiori-custom/configure.eslintrc"],
  "ignorePatterns": ["webapp/localservice/**", "webapp/test/**","test/**"]
}

El código anterior nos permite añadir los pluguins de eslint, los extends o normas a ejecutar (yo he puesto las que recomienda SAP) y por último carpetas que no aplican, como por ejemplo la de test o la de servidor local.

Lo siguiente es crear un fichero “package.json” para poder tener librerías node_modules dentro del proyecto html5, es decir en la carpeta webapp igual que en el paso anterior.

Y este sera su contenido, donde tenemos las librerías necesarias y el script para ejecutar la validación:

{
    "name": "cdci_btp",
    "version": "0.0.1",
    "private": true,
    "description": "A Fiori application.",
    "keywords": [
        "ui5",
        "openui5",
        "sapui5"
    ],
    "main": "webapp/index.html",
    "scripts": {
        "lint": "eslint ./ --rulesdir ./node_modules/eslint-plugin-fiori-custom/lib/rules/"
    },
    "devDependencies": {
        "eslint": "7.32.0",
        "@sap/eslint-plugin-ui5-jsdocs": "2.0.5",
        "@sapui5/ts-types": "1.92.2",
        "eslint-plugin-fiori-custom": "2.2.1",
        "@babel/eslint-parser": "7.14.7",
        "@sap/ui5-builder-webide-extension": "1.0.x",
        "ui5-task-zipper": "^0.3.1",
        "mbt": "^1.0.15"
    },
    "ui5": {
        "dependencies": [
            "@sap/ux-ui5-tooling",
            "@sap/ui5-builder-webide-extension",
            "ui5-task-zipper",
            "mbt"
        ]
    }
}

Este es el resultado:

Por último instalaremos las librerias con el comando “npm install” des del terminal del BAS y en la carpeta “webapp”

Validando el código con eslint por parte del desarrollador

Podemos validar el código cuando queramos, solo tendremos que ejecutar el comando “npm run lint” y esperar a los resultados:

  • Encaso de warnings o todo correcto veremos algo así
  • En caso de errores veremos algo así

Como podéis ver, gracias a estos controles, podemos validar pequeños fallos que pueda tener el código y depurarlos antes de cualquier despliegue del código.

UTs iniciadas de manera automática por CI/CD

*En el momento de escribir esta entrada, el servicio de Karma no esta 100% operativo, aunque en la documentación oficial consta que si que se puede usar Karma. Así que os añado los pasos de como quedaría una vez montado

Preparando Karma (lanzamiento de test en fondo)

Lo siguiente sera configurar el sistema de CI/CD para que ejecute los mismos test que ejecuta el desarrollador pero de una manera automática para que no se puedan descartar estos test.

Nuestro objetivo será automatizar el JOB ya que si utilizamos directamente qUnit, CD/CI nos ejecutará el servidor de test pero quedará en una espera eterna (bueno…. nos fallará al los 10 minutos ).

Así que vamos añadir Karma a nuestro proyecto para poder lanzar en background los test. lo primero sera ejecutar los comandos para añadir las librerías de Karma a nuestro proyecto (fichero package.json). Lo siguientes comandos los ejecutaremos en BAS mediante un terminal y situados en la carpeta del proyecto

npm install --save-dev karma
npm install --save-dev karma-ui5
npm install --save-dev karma-chrome-launcher
npm install --save-dev karma-coverage

Tambien añadiremos un navegador que se ejecuta en fondo, en este caso chrome:

npm install chromium

Este sera el resultado que tendremos en nuestro fichero package.json:

Una vez todo instalado, añadiremos un nuevo fichero llamado “karma.conf.js” en la raíz del de nuestro proyecto y añadiremos este código que contiene la configuración mínima para poder arrancar nuestro simulador de navegador.

module.exports = function(config) {
	"use strict";

	var chromeFlags = [
		"--window-size=1280,1024"
	];

	config.set({

		frameworks: ["ui5"],

		browsers: ["ChromeHeadless"],

		browserConsoleLogOptions: {
			level: "error"
		},

		customLaunchers: {
			CustomChrome: {
				base: "Chrome",
				flags: chromeFlags
			},
			CustomChromeHeadless: {
				base: "ChromeHeadless",
				flags: chromeFlags
			}
		},

	});
};

Ahora indicaremos los ficheros que tenemos que ejecutar con el navegador en fondo. Crearemos un fichero llamado “karma-ci.conf.js” donde indicaremos que ejecutar. Como el fichero anterior, lo añadimos en la raíz y este será su contenido:

module.exports = function(config) {
	"use strict";

	require("./karma.conf")(config);
	config.set({

		preprocessors: {
			"{webapp,webapp/!(test)}/*.js": ["coverage"]
		},

		coverageReporter: {
			includeAllSources: true,
			reporters: [
				{
					type: "html",
					dir: "coverage"
				},
				{
					type: "text"
				}
			],
			check: {
				each: {
					statements: 100,
					branches: 100,
					functions: 100,
					lines: 100
				}
			}
		},

		reporters: ["progress", "coverage"],

		browsers: ["CustomChromeHeadless"],

		singleRun: true

	});
};

Así nos quedará la carpeta con los ficheros de configuración.

Nos queda modificar el fichero packaje.json para añadir las instrucciones para ejecutar Karma dentro del TAG “scripts”:

	"karma-ci": "rimraf coverage && karma start karma-ci.conf.js",
	"unittestkarma": "npm run karma-ci",

Este es el resultado:

Añadiendo los test de Karma – QUnit en CI/CD

*En el momento de escribir esta entrada, el servicio de Karma no esta 100% operativo, aunque en la documentación oficial consta que si que se puede usar Karma. Así que os añado los pasos de como quedaría una vez montado.

Vamos a editar nuestro JOB en SAP Continuous Integration and Delivery:

Y añadimos la configuración para lanzar el test:

Ya lo tenemos todo apunto, dispararemos el job para generar la nueva version del MTAR que contiene el testing y que ejecutará de manera automática.

Ahora vemos como se ejecuta un paso adicional

Y aquí es cuando da error, a diferencia del comando ESLint, que si que ha funcionado sin problema.

Añadiendo triggers SAP Continuous Integration and Delivery para construcción automática

Ahora que ya tenemos todos los controles añadidos vamos a automatizar la generación del MTAR para que cuando detecte una modificación en GIT nos lance el proceso.

Este triggers se dispara con un concepto llamado Webhooks. Esto no es mas que un servicio de los repositorios GIT que mandan un mensaje a quien les este escuchando (es decir, cualquier servicio de CI/CD).

Trigger mediante webhook

Esta es la opción recomendada ya que nos permite iniciar la construcción solo en el momento que se envía la señal de cambio des de GitHub.

Creando un webhook en SAP Continuous Integration and Delivery

Vamos a nuestro JOB de SAP Continuous Integration and Delivery para activar el receptor:

Una vez añadido nos queda, añadir el tipo de repositorio y las credenciales

Ya solo nos queda obtener los datos de conexión, para ello, pulsamos en el boton de “…” y el botón “Webhook” data.

Los datos que nos aparecen los necesitaremos en el próximo paso.

Conectando el webhook con GitHub

Ahora activamos en GitHub el servicio webhooks, vamos a nuestro repositorio y activamos el servicio:

Y añadimos en la configuración que nos solicita Github los datos del paso anterior.

Esta es una configuración de ejemplo, esta claro que la url y la clave es la que es, pero el punto donde podéis jugar es el evento que os disparara el webhook. Es este caso cada vez que pase algo en nuestro repositorio. Cuando lo tengamos pulsamos “Add webhook”.

Y este es el resultado:

Ya esta todo listo, ahora cuando hagamos un push (de momento ya que no tenemos mas ramas) SAP Continuous Integration and Delivery construirá el MTAR y lo pondrá en la cola del Transport management.

Vemos que al hacer el push al repositorio de GitHub se inicia la construcción:

Y vemos como del commit que hemos hecho se inicia la construcción:

Trigger mediante JOB (Alternativa)

Esta alternativa es menos recomendable, ya que en verdad un job validará si hay cambios cada X tiempo y en caso que sea así empezará con la construcción. Aun así esta opción tiene mucho sentido en entornos de desarrollo y ramas de desarrollo para que así podamos acumular unos cuantos commits antes de iniciar la construcción.

Un dato importante es que estos Jobs son compatibles también con la opción anterior.

Para activar estos JOBS y estando sin editar el job (esto es muy importante) nos aparece la opción de añadir un nuevo job:

Al pulsar add, tenemos que informar dos opciones, una es el nombre de la rama a “controlar” y el patron del cronometro:

Un desplegable nos ayudara con el cronometro pero resumiendo utiliza 5 caracteres, cada uno es una unidad temporal que va de mas corta a mas larga. Esto significa que el primer carácter de la izquierda son los minutos, el siguiente las horas, luego días, messes y el último es el día de la semana concreto.

Con el carácter “*” indicamos algo parecido a “en cualquier momento”, luego cada posición podemos añadir números. Incluso podemos hacer divisiones. Así por ejemplo. si queremos que se lance un job los viernes cada 15 minutos usaríamos este patron: “*/15 * * * 6”.

Trasportando el contenido a otras accounts/subaccounts

Para este paso transportáremos a otras subaccount. En este ejemplo, transportare a mi account secundaria. Lo que haremos es crear un space secundario con el botón “space”.

Añadimos el nombre que queramos, por ejemplo, test y le damos todos los permisos a nuestro usuario.

Una vez tenemos el nuevo entorno podemos empezar con la configuración:

Creando una destination a nuestra cuenta Test

Para acelerar un poco el proceso, copiaremos la destination que creamos al inicio, pero en este caso le pondremos el entorno de test:

Este es el resultado:

Configurando el transport management

Ahora que ya tenemos las dos subaccounts conectadas, es momento de crear la ruta de transportes y transportar.

Creando un nodo nuevo

Lo primero sera crear el nuevo nodo hacia test. Vamos a Landscape visualization y pulsamos el botón “+”:

Este paso no lo detallo mucho porque es lo mismo que hemos hecho antes, pero esta vez con el nodo “test”:

El único punto importante es que no marcaremos el flag “Allow Upload to Node” que si que teníamos activado para desarrollo, esto lo hacemos para blindar el nodo y no permitir subidas de código que no estén definidas en el transport path.

Configurando el path de transporte

Ahora definiremos los path de transporte mediante la creación de una ruta.

Vamos a la opción “Transport” y pulsamos en el botón “+” donde aparecerá una pantalla donde indicaremos el nombre, la descripción y los nodos de inicio y fin:

Ya está todo apunto, si volvemos a la opción “Landscape Visualization” veremos los dos nodos conectados.

Transportando

Ya podemos realizar los transportes. Esto se realiza de manera manual mediante las colas de transporte. Si has llegado hasta aquí siguiendo las instrucciones, ahora tendrás pendiente en desarrollo un transporte. Sino, puedes ir a SAP Continuous Integration and Delivery e iniciar un Job para que te llegue a la cola de Dev un nuevo MTAR.

Para transporta, nos vamos al “Landscape Visualization” y seleccionamos el entorno de desarrollo “Dev” (donde veremos un transporte pendiente en Initial/repeatable) y pulsamos “Go to this node’s import queue”:

Nos aparecerán los transportes pendientes en el nodo de desarrollo, seleccionamos el artefacto a transportar y pulsamos el botón “Import Selected” para empezar el despliegue.

Aceptamos el aviso y empezará el transporte

Y veremos como el transporte se inicia tanto en el detalle del nodo como en la página del Landscape:

Una vez transportado, repetiremos esta acción para el entorno de test pulsando “Test” y pulsamos otra vez “Go to this node’s import queue”.

Seleccionamos el artefacto a transportar, que como vemos, nos avisa que su origen era el nodo DEV, y pulsamos en “Import Selected.

En caso de error, como me ha pasado a mi veremos que el nodo queda en rojo:

Podremos ver el problema si vamos a la sección: “Transport action Log”

Y accedemos al log para ver el problema:

En mi caso el servicio ya existía, esto es debido a que existen dos space en la misma subaccount y elservicio XSUAA queintento desplegar utiliza el managed appRouter lo que provoca un ID de aplicación duplicado pero me servía para ilustrar los errores.

Y ahora… ¿como lo organizamos bien?

Pues llegamos al final de esta serie, ya hemos aprendido a crear y sincronizar nuestro Git, añadir testing a nuestras aplicaciones, crear los MTAR de una manera rápida, ágil y con un versionado y mover el software a los distintos entornos.

Para los que tengáis mas años, llega el momento de hacer nuestro símil entre la SE01 y la STMS y nuestro sistema de despliegue e integración de código.

Git flow

Empezamos en como tenemos que organizar nuestro repositorio. Aquí la respuesta es Git Flow, una propuesta de organización de Git que pertenece inalterable des de hace mas de 10 años.

Antes de seguir, hay que avisar que cada proyecto Git debe ser una sola aplicación y que no es nada recomendable utilizar carpetas para poner distintos proyectos en el mismo repositorio.

Os presento un dibujo de como tiene que ser la organización de las ramas:

Una Taza de Java: [GIT] Git Flow - GitHub Flow

Podríamos definirlo por niveles, de menos alterable a mas:

  • La rama master, que ahora en GitHub pasa a llamarse rama main, es la mas parecida al código de productivo ya que no es modificable directamente y solo recibe actualizaciones de errores (bugs) y releases (conjunto de desarrollos probados y que están pendientes de subir a productivo)
  • En el siguiente nivel tenemos las ramas de hotfixes y release.
    • La primera, hotfixes se crea y se destruye en cada error, es una rama que creamos de la rama master y una vez solucionados los errores la sincronizamos con las ramas de desarrollo y master y la destruimos.
    • La rama de release agrupa todas esas mejoras de que se pactan para antes de la subida a desarrollo. Sobre esta branca podríamos discutir si tiene sentido en un marco de gitops (Si otro nombre para acelerar mas lo que ya hemos acelerado 🙂 ) pero esta rama puede recibir releases cada día si hace falta. En este punto se realizarían las pruebas integradas.
  • Seguimos con la rama develop, aquí es donde se van consolidando los distintos códigos del desarrollo y donde se integran para poder realizar las primeras pruebas unitarias.
  • Las últimas ramas son las de cada cambio concreto que se defina, las feature branches. Estas ramas se pueden partir a la vez en una rama para cada desarrollador y luego consolidar los distintos cambios en de esa feature concreta.

Y ¿Como vamos de una rama a otra? Pues la respuesta es utilizar pull request en todas las ramas a excepción de desarrollo y features. Esto nos permite tener cierto control para que un revisor sea el encargado de aceptar os cambios de código.

Espero que os haya quedado un poco mas claro, pero ¿por qué se hace todo esto? pues la razón es que necesitamos controlar como y quien va moviendo el software. Así pues, un pull request de la rama release a main solo se podrá aceptar con unas UAT pasadas, mientras que una feature finalizada se podrá pasar a develop por el desarrollador una vez las UT estén finalizadas.

Y ¿Qué hago con SAP Continuous Integration and Delivery y SAP Transport management?

Hemos visto que el servicio de SAP Continuous Integration and Delivery nos permite hacer deploy directamente contra la subcuenta o mandarlo a SAP transport manager.

Aunque podemos jugar como queramos, ya que cada organización es un mundo, mi consejo es utilizar un job para hacer deploy des de la rama develop hacia la subcuenta de desarrollo. Esto evitara tener que dar permisos para desplegar a muchos usuarios, que a la vez implica tener que habilitar los permisos de desarrollo del space, por lo que podemos tener problemas de borrado de instancias por error o despliegue de “porqueria” para pocs.

Una vez tenemos este Job a punto, el siguiente job sera el de transporte a integración. Este lo conectaría a la rama release y su deploy se enviaría al nodo de UAT de nuestro servicio de SAP Tranport management. Ya que así requiere del despliegue mediante aprobación de cola.

Para productivo jugaríamos con dos escenarios:

  • El transporte de las releases, que como hemos visto, definiríamos un path de transporte de UAT a Productivo. Una vez pasadas las ultimas pruebas se podría mover todo el software a producción mediante cola.
  • El segundo escenario es el de error, este es delicado, porque si se activa es que algo esta mal en productivo. Para este, tendríamos un job dedicado a la rama hotfixes y conectado para hacer el deploy des de SAP Continuous Integration and Delivery hacia nuestra cuenta de desarrollo. Luego para UAT como en el caso anterior pero con paso extra un path dev a uat y de uat a productivo.

Este seria el esquema aplicando GitHub y los dos servicios SAP Continuous Integration and Delivery y SAP Transport management:

Transporte / EntornoDevUatProd
Ramadevelophotfixes / release N/A
TransporteCI/CD deploy directo CI/CD deploy directo – cierre de release al Nodo UATTransporte del Nodo UAT a Prod mediante transport path

Y hasta aquí la serie de Devops centrada en CI/CD, si os ha gustado preparé una nueva serie de la parte de monitoring una vez nuestras aplicaciones ya están deployadas.

Como veis, la configuración es relativamente sencilla de montar, y aunque requiere de una pensada inicial y algo de mantenimiento, nos permite controlar accesos, realizar pruebas rápidas y realizar los transportes de una manera controlada.

Tambien he dejado algunos cabos sueltos al mas puro estilo Netflix… como por ejemplo, como transportamos el launchpad en bloque, pero en el momento de escribir esta entrada, el transporte del launchpad en la cuenta trial no esta activo.

Como siempre suscribete, dale a la campanita de notificaciones y comparte en redes para estar a la última. Vota Like / Dislike para aportar feedback.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.