Wiki source code of Libertya CI/CD
Last modified by admin on 2026/07/18 17:44
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | = Pestaña 1 {{id name="pestaña-1" /}}= | ||
| 2 | |||
| 3 | **Libertya CI/CD** | ||
| 4 | |||
| 5 | Análisis e implementación de mejoras en la metodología de desarrollo Libertya mediante CI/CD y testing automation. | ||
| 6 | |||
| 7 | [[image:image1.png]]\\[[image:image2.png]] | ||
| 8 | |||
| 9 | = **Índice** {{id name="índice" /}}= | ||
| 10 | |||
| 11 | {{toc/}} | ||
| 12 | |||
| 13 | = **Objetivo** {{id name="objetivo" /}}= | ||
| 14 | |||
| 15 | El objetivo de este documento es detallar el análisis, tareas realizadas y proporcionar información útil acerca de la implementación de automatización en la metodología de desarrollo de Libertya. La idea es apuntar a un pipeline CI/CD que ayude a automatizar diferentes etapas del proceso, así como también incorporar el uso de tests. Para lograr llevar adelante estas mejoras, se propone la utilización de Jenkins https://www.jenkins.io/ | ||
| 16 | |||
| 17 | = **Acceso a Jenkins** {{id name="acceso-a-jenkins" /}}= | ||
| 18 | |||
| 19 | Se configuró Jenkins para acceder por medio de tunel ssh en el puerto 9090. | ||
| 20 | |||
| 21 | Conectarse de esta forma: | ||
| 22 | |||
| 23 | |=ssh -p 4565 usuario@138.219.43.229 -L 9090:localhost:9090 | ||
| 24 | |||
| 25 | Luego acceder desde el navegador con **localhost:9090** | ||
| 26 | |||
| 27 | *. **Username:** jenkins\\ | ||
| 28 | *. **Password:** Bangla… | ||
| 29 | |||
| 30 | **[[image:image3.png]]** | ||
| 31 | |||
| 32 | = **Acceso a SonarQube (deshabilitado)** {{id name="acceso-a-sonarqube-deshabilitado" /}}= | ||
| 33 | |||
| 34 | Se configuró SonarQube para acceder por medio de tunel ssh en el puerto 9000. | ||
| 35 | |||
| 36 | Acceder desde el navegador con **localhost:9000** | ||
| 37 | |||
| 38 | *. **Username:** admin\\ | ||
| 39 | *. **Password:** Putra… 424 (con espacio) | ||
| 40 | |||
| 41 | **token (utilizado por jenkins):** squ_6999e9c29d865ed3233d47cb2ec31fb9904f06f2 | ||
| 42 | |||
| 43 | [[image:image4.png]] | ||
| 44 | |||
| 45 | = **Información de la instancia** {{id name="información-de-la-instancia" /}}= | ||
| 46 | |||
| 47 | == Nociones generales {{id name="nociones-generales" /}}== | ||
| 48 | |||
| 49 | Todo lo relacionado a Jenkins se encuentra ubicado en el servidor de desarrollo en el directorio /home/jenkins. | ||
| 50 | |||
| 51 | Se encuentra archivo el **docker-compose.yml** | ||
| 52 | |||
| 53 | |||
| 54 | {{code language="bash"}} | ||
| 55 | version: '3.8' services: jenkins: image~: jenkins/jenkins-custom:latest container_name: jenkins restart: unless-stopped user: root privileged: true network_mode: host volumes: - jenkins_home:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock - /home/jenkins/reportes:/var/reportes environment: - JAVA_OPTS=-Djenkins.install.runSetupWizard=true - JENKINS_OPTS=--httpPort=9090 postgres: image~: postgres:10.10 container_name: libertya-postgres restart: unless-stopped network_mode: host environment: POSTGRES_DB: libertya_test POSTGRES_USER: libertya POSTGRES_PASSWORD: libertya PGPORT: 5434 volumes: - | ||
| 56 | ./init-db:/docker-entrypoint-initdb.d - | ||
| 57 | ./pgdata:/var/lib/postgresql/data | ||
| 58 | # sonarqube: | ||
| 59 | # image~: sonarqube:latest | ||
| 60 | # container_name: sonarqube | ||
| 61 | # restart: unless-stopped | ||
| 62 | # network_mode: host | ||
| 63 | # ports: | ||
| 64 | # - "9000:9000" | ||
| 65 | # volumes: | ||
| 66 | # - sonarqube_data:/opt/sonarqube/data | ||
| 67 | # - sonarqube_extensions:/opt/sonarqube/extensions | ||
| 68 | # - sonarqube_logs:/opt/sonarqube/logs volumes: jenkins_home: | ||
| 69 | # sonarqube_data: | ||
| 70 | # sonarqube_extensions: | ||
| 71 | # sonarqube_logs: | ||
| 72 | {{/code}} | ||
| 73 | |||
| 74 | Existen 2 contenedores principales, el de jenkins y el de postgres utilizado para almacenar las bases de test de los pipelines. | ||
| 75 | |||
| 76 | Notar que se creó una **imagen custom de jenkins** como solución, ya que fue necesario instalar ciertas herramientas y al reiniciar el contenedor esos cambios se perderían. Actualmente esas herramientas son las siguientes: | ||
| 77 | |||
| 78 | **Instalar jdk11 y zip** | ||
| 79 | |||
| 80 | |=echo “deb http:~/~/deb.debian.org/debian bullseye main” >> /etc/apt/sources.list apt update apt install -y openjdk-11-jdk apt install -y zip | ||
| 81 | |||
| 82 | **Instalar jdk8 (desde servidor)** | ||
| 83 | |||
| 84 | |||
| 85 | {{code language="bash"}} | ||
| 86 | cd /home/jenkins docker | ||
| 87 | cp jdk1.8.0_121.zip jenkins:/opt docker exec -it jenkins bash | ||
| 88 | cd /opt | ||
| 89 | unzip jdk1.8.0_121.zip | ||
| 90 | {{/code}} | ||
| 91 | |||
| 92 | == Cómo reiniciar el servicio? {{id name="cómo-reiniciar-el-servicio" /}}== | ||
| 93 | |||
| 94 | Para reiniciar tanto Jenkins como el Postgres asociado, acceder como root y luego ejecutar lo siguiente: | ||
| 95 | |||
| 96 | |||
| 97 | {{code language="bash"}} | ||
| 98 | #Acceder a la ubicación | ||
| 99 | cd /home/jenkins #Detener los contenedores docker compose down #Levantar los contenedores en modo detach docker compose up -d | ||
| 100 | {{/code}} | ||
| 101 | |||
| 102 | = **Pipelines** {{id name="pipelines" /}}= | ||
| 103 | |||
| 104 | Actualmente existen 2 pipelines principales. | ||
| 105 | |||
| 106 | **Libertya-Core** es el pipeline productivo para Libertya Core. Clona los repositorios de Libertya y lyrestapi, compila, configura y ejecuta el test-set. Finalmente envía un mail con los reportes generados con los tests automáticos. | ||
| 107 | |||
| 108 | **Libertya-Core-Sandbox** es un pipeline copia de Libertya-Core pensado para implementar nuevas funcionalidades y hacer pruebas en el pipeline antes de pisar el pipeline productivo. Es un pipeline de “juguete” que en principio se comporta igual que el productivo pero no envía mails, no pisa los reportes ni ninguna otra acción que pueda repercutir. | ||
| 109 | |||
| 110 | [[image:image5.png]] | ||
| 111 | |||
| 112 | = **Diseño de pipelines** {{id name="diseño-de-pipelines" /}}= | ||
| 113 | |||
| 114 | == Pipeline exploratorio para Libertya-Core {{id name="pipeline-exploratorio-para-libertya-core" /}}== | ||
| 115 | |||
| 116 | 🚀 **Desencadenante** | ||
| 117 | |||
| 118 | *. Se realiza un **push a {{code}}master{{/code}}** del repo de **Libertya Core** en GitHub.\\ | ||
| 119 | *. Jenkins detecta el cambio y **dispara el pipeline automáticamente**. | ||
| 120 | |||
| 121 | 🏗️ **Flujo completo** | ||
| 122 | |||
| 123 | **1. Preparación del entorno** | ||
| 124 | |||
| 125 | *. Se configura el entorno con {{code}}JAVA 11{{/code}}, paths internos ({{code}}OXP_HOME{{/code}}, {{code}}WORKDIR{{/code}}, {{code}}REPORTS_DIR{{/code}}, etc.), y credenciales de DB.\\ | ||
| 126 | *. Se definen variables de entorno necesarias para compilar Libertya y ejecutar los tests. | ||
| 127 | |||
| 128 | **2. Clonar y compilar Libertya Core** | ||
| 129 | |||
| 130 | *. Se clona el repo de **Libertya** desde GitHub ({{code}}branch: master{{/code}}).\\ | ||
| 131 | *. Se obtiene el **commit hash** actual ({{code}}LIBERTYA_COMMIT{{/code}}).\\ | ||
| 132 | *. Se le dan permisos de ejecución a los scripts {{code}}.sh{{/code}}.\\ | ||
| 133 | *. Se ejecuta el script {{code}}utils_dev/Compilar.sh{{/code}} para compilar el sistema. | ||
| 134 | |||
| 135 | **3. Generación de Keystore** | ||
| 136 | |||
| 137 | *. Se genera un **keystore Java ({{code}}myKeystore{{/code}})** si no existe, necesario para la ejecución de ConfigurarAuto.sh | ||
| 138 | |||
| 139 | **4. Configuración de Libertya** | ||
| 140 | |||
| 141 | *. Se copia el archivo {{code}}LibertyaEnv.properties{{/code}} desde el **Config File Provider** de Jenkins.\\ | ||
| 142 | *. Se le da permiso de ejecución a todos los scripts.\\ | ||
| 143 | *. Se ejecuta {{code}}ConfigurarAuto.sh{{/code}} para inicializar la instalación. | ||
| 144 | |||
| 145 | **5. Limpieza del jar OXPXLib** | ||
| 146 | |||
| 147 | *. Se eliminan clases conflictivas ({{code}}org.slf4j.impl.*{{/code}}) y metainformación innecesaria del {{code}}.jar{{/code}} ({{code}}META-INF/INDEX.LIST{{/code}}). | ||
| 148 | |||
| 149 | **6. Clonar LYRestAPI** | ||
| 150 | |||
| 151 | *. Se clona el repo de **lyrestapi** desde GitHub ({{code}}branch: main{{/code}}).\\ | ||
| 152 | *. Se guarda el **commit hash** ({{code}}LYRESTAPI_COMMIT{{/code}}). | ||
| 153 | |||
| 154 | **7. Ejecución de Tests** | ||
| 155 | |||
| 156 | *. Se usa **Java 8** (temporal downgrade) para ejecutar los tests.\\ | ||
| 157 | *. Se corre {{code}}./gradlew clean test --info{{/code}} desde el directorio {{code}}lyrestapi{{/code}}. | ||
| 158 | |||
| 159 | 🧾 **Post build (siempre se ejecuta)** | ||
| 160 | |||
| 161 | ✅ **Si los tests pasan o fallan:** | ||
| 162 | |||
| 163 | *. Se copian los reportes HTML de los tests al directorio {{code}}/var/reportes{{/code}}.\\ | ||
| 164 | *. Se ajustan permisos para que estén disponibles públicamente en http://lycore-tests.libertya.office-on-the.net/ | ||
| 165 | |||
| 166 | 📧 **Se envía un email HTML con:** | ||
| 167 | |||
| 168 | *. Estado del build ({{code}}SUCCESS{{/code}} o {{code}}FAILURE{{/code}})\\ | ||
| 169 | *. Fecha y hora\\ | ||
| 170 | *. Commit de Libertya\\ | ||
| 171 | *. Commit de LYRestAPI\\ | ||
| 172 | *. Link al reporte de tests | ||
| 173 | |||
| 174 | == Pipelines para ramas dev y master {{id name="pipelines-para-ramas-dev-y-master" /}}== | ||
| 175 | |||
| 176 | ✅ 2 Pipelines separados en Jenkins: uno para {{code}}dev{{/code}} y otro para {{code}}master{{/code}} | ||
| 177 | |||
| 178 | 1. 🛠️ Pipeline {{code}}dev{{/code}} (Integración continua) | ||
| 179 | |||
| 180 | *. **Trigger**: push en {{code}}dev{{/code}}\\ | ||
| 181 | *. **Qué hace**: | ||
| 182 | **. Compila\\ | ||
| 183 | **. Ejecuta tests automáticos\\ | ||
| 184 | **. despliega en entorno //de testing manual//\\ | ||
| 185 | *. **Resultado esperado**: Confirmar que lo nuevo no rompe nada. Si falla, no se hace el PR a {{code}}master{{/code}}. | ||
| 186 | |||
| 187 | 🎯 Este es el filtro de calidad previo. | ||
| 188 | |||
| 189 | |||
| 190 | ---- | ||
| 191 | |||
| 192 | 1. 🚀 Pipeline {{code}}master{{/code}} (Despliegue continuo) | ||
| 193 | |||
| 194 | *. **Trigger**: merge a {{code}}master{{/code}} (después del PR aprobado desde {{code}}dev{{/code}})\\ | ||
| 195 | *. **Qué hace**: | ||
| 196 | **. Repite la build\\ | ||
| 197 | **. Corre los tests automáticos nuevamente\\ | ||
| 198 | **. Hace deploy del release (//release server//, //prod//, etc.)\\ | ||
| 199 | **. (Opcional) versiona, taguea, sube binarios, etc. | ||
| 200 | |||
| 201 | 🎯 Este pipeline representa la versión oficial y estable. | ||
| 202 | |||
| 203 | |||
| 204 | ---- | ||
| 205 | |||
| 206 | 🧠 ¿Por qué dos pipelines? | ||
| 207 | |||
| 208 | Porque **la intención y los riesgos de cada rama son distintos**: | ||
| 209 | |||
| 210 | |=Rama |=Pipeline |=Objetivo |=Despliegue | ||
| 211 | |{{code}}dev{{/code}} |CI |Validar cambios antes del merge |Staging (opcional) | ||
| 212 | |{{code}}master{{/code}} |CD |Versión estable para producción |Producción | ||
| 213 | |||
| 214 | == Automatización de otros proyectos y consideración de metadata {{id name="automatización-de-otros-proyectos-y-consideración-de-metadata" /}}== | ||
| 215 | |||
| 216 | Otros proyectos van a requerir sus propios pipelines, como LYEI o LocaleAR. Estos a su vez deberían ser tenidos en cuenta para integrarse en el deploy automático a la instancia de testing manual. En caso de exportar un release de estos proyectos, se incluiría tanto binarios como metadata completa, pero para exportar a la instancia de testing manual, se tienen que ajustar algunos parámetros ya que la metadata se instala de forma incremental. Esto impacta directamente en los ID de changelogs a considerar en cada incremento. | ||
| 217 | |||
| 218 | **Opcion 1:** parametrizar el archivo devinfo.properties dentro del pipeline. | ||
| 219 | |||
| 220 | Se podría utilizar sed, awk, envsubst o alguna herramienta similar que pise valores específicos, por ejemplo, el {{code}}ExportChangelogFromID{{/code}} Para ajustar la versión a instalar en el entorno de pruebas. Al ser incremental, la base de datos de test ya tendría la metadata previa, entonces habría que parametrizar los changelogs a incluir. | ||
| 221 | |||
| 222 | **IMPORTANTE:** Para realizar esto, es necesario sanitizar el preinstall de LYEI. Actualmente tiene instrucciones del tipo “CREATE TABLE” que dan error en la instalación si esas tablas ya fueron creadas. | ||
| 223 | |||
| 224 | **Opcion 2:** Modificar clases de Libertya para lograr cierta flexibilidad a la hora de realizar un export o install. Por ejemplo, modificar la clase ExportPlugin para que permita tomar variables de entorno con prioridad en lugar de tomar únicamente los valores por defecto de devinfo.properties. También se podría investigar si es posible modificar el [[PluginInstaller.sh>>http://PluginInstaller.sh]] (y clases java asociadas) para instalar un componente de forma más flexible. Por ejemplo instalar los changelogs faltantes de la versión actual e ignorar los que ya fueron instalados, en lugar de tener que exportar el rango exacto a instalar. | ||
| 225 | |||
| 226 | = **Cambios en metodología de Desarrollo – Flujo de ramas y automatización** {{id name="cambios-en-metodología-de-desarrollo-flujo-de-ramas-y-automatización" /}}= | ||
| 227 | |||
| 228 | == Ramas {{id name="ramas" /}}== | ||
| 229 | |||
| 230 | **dev** | ||
| 231 | |||
| 232 | *. **Rama libre** de trabajo diario | ||
| 233 | *. Todos los desarrolladores pueden hacer **push directo** a esta rama | ||
| 234 | *. Cada push dispara el pipeline CI/CD (build + tests automáticos). | ||
| 235 | |||
| 236 | **master** | ||
| 237 | |||
| 238 | *. Rama estable y protegida. | ||
| 239 | *. **No se puede pushear directamente**. | ||
| 240 | *. Solo se actualiza vía Pull Request (PR) desde {{code}}dev{{/code}}. | ||
| 241 | *. Representa siempre el estado listo para producción/release. | ||
| 242 | |||
| 243 | == Flujo de trabajo {{id name="flujo-de-trabajo" /}}== | ||
| 244 | |||
| 245 | **1. Trabajo diario** | ||
| 246 | |||
| 247 | *. Cada dev hace sus cambios y pushea a la rama dev (directamente o mediante branches personales, si lo prefiere). | ||
| 248 | *. El pipeline de Jenkins corre automáticamente con cada cambio en {{code}}dev{{/code}}: | ||
| 249 | |||
| 250 | **. Compila el proyecto. | ||
| 251 | **. Ejecuta todos los tests automáticos. | ||
| 252 | **. Al finalizar, **envía un email** a todos los desarrolladores con los resultados (éxito o errores de los tests). | ||
| 253 | |||
| 254 | Ejemplo de notificación implementada: | ||
| 255 | |||
| 256 | [[image:image6.png]] | ||
| 257 | |||
| 258 | **2. Preparación para nuevo release** | ||
| 259 | |||
| 260 | Cuando {{code}}dev{{/code}} está estable y **todos los tests pasan**, cualquier integrante puede proponer un **Pull Request (PR)** de {{code}}dev{{/code}} hacia {{code}}master{{/code}} desde la web de GitHub. | ||
| 261 | |||
| 262 | El pipeline podría volverse a ejecutar sobre {{code}}master{{/code}} después del merge para asegurar estabilidad final. | ||
| 263 | |||
| 264 | **3. Generación y distribución del release** | ||
| 265 | |||
| 266 | *. Una vez que el PR se aprueba y mergea en {{code}}master{{/code}}, Jenkins dispara automáticamente el pipeline de release: | ||
| 267 | |||
| 268 | **. Se asigna un nuevo **número de versión** (versionado automático). | ||
| 269 | **. Se genera el ejecutable/distribuible. | ||
| 270 | **. Se publica o distribuye en el servidor de releases. | ||
| 271 | |||
| 272 | = **Bitácora de implementación** {{id name="bitácora-de-implementación" /}}= | ||
| 273 | |||
| 274 | Se detallan a continuación las tareas realizadas en función de avanzar con la implementación del entorno y pipelines. | ||
| 275 | |||
| 276 | Se instaló Jenkins mediante docker en el servidor de desarrollo. Se creó el directorio /home/jenkins para centralizar todo lo relacionado a la herramienta. | ||
| 277 | |||
| 278 | Se configuró la red en modo host y el puerto de Jenkins 9090. | ||
| 279 | |||
| 280 | El archivo docker-compose.yml utilizado al momento de redactar este documento es el siguiente: | ||
| 281 | |||
| 282 | |||
| 283 | {{code language="bash"}} | ||
| 284 | version: '3.8' services: jenkins: image~: jenkins/jenkins:lts container_name: jenkins restart: unless-stopped user: root privileged: true network_mode: host volumes: - jenkins_home:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock environment: - JAVA_OPTS=-Djenkins.install.runSetupWizard=true - JENKINS_OPTS=--httpPort=9090 postgres: image~: postgres:10.10 container_name: libertya-postgres restart: unless-stopped network_mode: host environment: POSTGRES_DB: libertya_test POSTGRES_USER: libertya POSTGRES_PASSWORD: libertya PGPORT: 5434 volumes: - | ||
| 285 | ./init-db:/docker-entrypoint-initdb.d volumes: jenkins_home: | ||
| 286 | {{/code}} | ||
| 287 | |||
| 288 | Se configuraron las credenciales para Github y SVN. Estas son necesarias para interactuar con los repositorios y poder clonar los proyectos. | ||
| 289 | |||
| 290 | Se creó un pipeline inicial para probar las funcionalidades básicas como clonación de repositorios, ejecución de scripts, etc… Se probaron también diferentes formas de ejecutar el pipeline, mediante el uso de Jenkinsfile en el repositorio y mediante un script dentro del propio Jenkins. | ||
| 291 | |||
| 292 | Se configuró un contenedor para postgres (ya especificado en el docker-compose.yml) que se levanta junto a Jenkins para instanciar la base de datos de test. Al crear el contenedor se toma el dump ubicado en el directorio init-db que es una base de datos preparada para testing actualmente basada en Libertya 22. | ||
| 293 | |||
| 294 | Se mejoró iterativamente el pipeline, probando diferentes ejecuciones y actualmente se pueden clonar los repositorios de Libertya y lyrestapi, disparar la compilación de Libertya, etc… | ||
| 295 | |||
| 296 | La compilación de Libertya falla con el script ./[[Compilar.sh>>http://Compilar.sh]] debido a que intenta utilizar el jdk17 que está por defecto en la instancia. Se configuró el openjdk-11 desde el contenedor para utilizar en el pipeline. | ||
| 297 | |||
| 298 | == Configuración de JDK para pipeline {{id name="configuración-de-jdk-para-pipeline" /}}== | ||
| 299 | |||
| 300 | Por defecto, el contenedor de Jenkins tenía configurado Java 17. Para instalar Java 11, se siguieron los siguientes pasos: | ||
| 301 | |||
| 302 | **1. Actualizar las fuentes del sistema operativo (Debian):**\\El paquete {{code}}openjdk-11-jdk{{/code}} no estaba disponible inicialmente. Para solucionarlo se agregó el repositorio adecuado: | ||
| 303 | |||
| 304 | |=echo “deb http:~/~/deb.debian.org/debian bullseye main” >> /etc/apt/sources.list apt update apt install -y openjdk-11-jdk | ||
| 305 | |||
| 306 | **2. Configuración de la instalación del JDK en Jenkins** | ||
| 307 | |||
| 308 | Una vez instalado el JDK, se registró manualmente en Jenkins: | ||
| 309 | |||
| 310 | 1. Ir a: **Jenkins > Administrar Jenkins > Global Tool Configuration** | ||
| 311 | 1. Buscar la sección **JDK** | ||
| 312 | 1. Añadir una nueva entrada con los siguientes valores: | ||
| 313 | |||
| 314 | 1*. **Nombre**: {{code}}java-11-openjdk-amd64{{/code}} | ||
| 315 | 1*. **JAVA_HOME**: {{code}}/usr/lib/jvm/java-11-openjdk-amd64{{/code}} | ||
| 316 | 1*. Desmarcar la opción **“Instalar automáticamente”** (ya que ya está instalado en el sistema). | ||
| 317 | |||
| 318 | **3. Uso del JDK desde un Jenkinsfile** | ||
| 319 | |||
| 320 | Para utilizar este JDK en un pipeline declarativo, se incluyó la configuración del JDK en la sección {{code}}tools{{/code}}, y luego se actualizó el {{code}}PATH{{/code}}: | ||
| 321 | |||
| 322 | |||
| 323 | {{code language="bash"}} | ||
| 324 | tools { jdk 'java-11-openjdk-amd64' } environment { JAVA_HOME = "${tool 'java-11-openjdk-amd64'}" PATH = "${env.JAVA_HOME}/bin:${env.PATH}" } | ||
| 325 | {{/code}} | ||
| 326 | |||
| 327 | **Nota**: Para la ejecución de lyrestapi se configuró java-8-temurin de manera similar en /opt/jdk8u452-b09 | ||
| 328 | |||
| 329 | [[image:image7.png]] | ||
| 330 | |||
| 331 | El error persiste: | ||
| 332 | |||
| 333 | [mkdir] Created dir: /var/jenkins_home/workspace/Libertya-Core/libertya/install/compilacion/ServidorOXP/jboss/server\\[copy] Copying 284 files to /var/jenkins_home/workspace/Libertya-Core/libertya/install/compilacion/ServidorOXP/jboss/server\\[zip] Building zip: /var/jenkins_home/workspace/Libertya-Core/install/ServidorOXP_V22.0.zip | ||
| 334 | |||
| 335 | **BUILD FAILED**\\/var/jenkins_home/workspace/Libertya-Core/libertya/utils_dev/build.xml:32: The following error occurred while executing this line:\\/var/jenkins_home/workspace/Libertya-Core/libertya/install/build.xml:218: Problem creating zip: /var/jenkins_home/workspace/Libertya-Core/install/ServidorOXP_V22.0.zip (No such file or directory) (and the archive is probably corrupt but I could not delete it)Total time: 1 minute 31 seconds\\Se intentó modificar los scripts y/o pipeline para poder alterar los directorios donde se exporta Libertya ([[Compilar.sh>>http://Compilar.sh]], build.xml, [[VariablesCompilacion.sh>>http://VariablesCompilacion.sh]], etc..) | ||
| 336 | |||
| 337 | Se logró realizar la compilación. Da errores al descomprimir el zip pero se probó realizar la descompresión manualmente dentro del pipeline: | ||
| 338 | |||
| 339 | Env. | ||
| 340 | |||
| 341 | |||
| 342 | {{code language="bash"}} | ||
| 343 | environment { WORKDIR = '/var/jenkins_home/workspace/Libertya-Core' JAVA_HOME = "${tool 'java-11-openjdk-amd64'}" PATH = "${env.JAVA_HOME}/bin:${env.PATH}" OXP_ROOT = '$(pwd)' DB_NAME = 'libertya_test' DB_USER = 'libertya' DB_PASS = 'libertya' DB_PORT = '5434' } | ||
| 344 | {{/code}} | ||
| 345 | |||
| 346 | Stage “Clonar y Compilar Libertya” | ||
| 347 | |||
| 348 | |||
| 349 | {{code language="bash"}} | ||
| 350 | stage('Clonar y Compilar Libertya') { steps { dir('libertya'){ git branch: 'master', url: 'https://github.com/Disytel-Consulting-SA/libertya.git' sh ''' echo "==> Listando directorios y archivos" ls -lhst INSTALL_DIR="${WORKDIR}/install" | ||
| 351 | mkdir -p ${INSTALL_DIR} | ||
| 352 | chmod -R u+w ${INSTALL_DIR} echo "==> Habilitando permisos de ejecución..." find . -type f -name "*.sh" -exec | ||
| 353 | chmod \+x {} \\; echo "==> Ejecutando script de compilación..." | ||
| 354 | cd utils_dev && | ||
| 355 | ./Compilar.sh #echo "==> Descomprimiendo..." OXP_HOME="${WORKDIR}/ServidorOXP" | ||
| 356 | unzip ${INSTALL_DIR}/ServidorOXP_V22.0.zip -d ${WORKDIR} ''' } } } | ||
| 357 | {{/code}} | ||
| 358 | |||
| 359 | Consiguiendo que Libertya quede en el workspace dentro de ServidorOXP.\\[[image:image8.png]]\\Lógicamente esto se buscó para no utilizar las rutas por defecto como /ServidorOXP o /install ya que se escapan del contexto del pipeline (workdir). La idea es que todo quede contenido en el propio workdir del pipeline para no correr el riesgo de mezclar datos con otros pipelines. | ||
| 360 | |||
| 361 | Para tener una versión preparada de LibertyaEnv.properties se configuró el plugin Config File Provider que permite administrar archivos de configuración (como {{code}}.properties{{/code}}, {{code}}.xml{{/code}}, etc.) directamente desde Jenkins y usarlos en los pipelines o jobs. | ||
| 362 | |||
| 363 | Se puede acceder desde **Administrar Jenkins > Managed files** | ||
| 364 | |||
| 365 | [[image:image9.png]] | ||
| 366 | |||
| 367 | Ejecución de [[ConfigurarAuto.sh>>http://ConfigurarAuto.sh]] | ||
| 368 | |||
| 369 | + ./ConfigurarAuto.sh\\=======================================\\Comenzando Configuraci�n …\\=======================================\\Validando existencia de clases duplicadas en ./lib/plugins\\Sin archivos para procesar. | ||
| 370 | |||
| 371 | …\\…\\… | ||
| 372 | |||
| 373 | [delete] Deleting directory /var/jenkins_home/workspace/Libertya-Core/ServidorOXP/nuevosComponents\\[delete] Deleting directory /var/jenkins_home/workspace/Libertya-Core/ServidorOXP/backupOXP\\[echo] KeyStore=/var/jenkins_home/workspace/Libertya-Core/ServidorOXP/keystore/myKeystore - Alias=libertya\\[signjar] Signing JAR: /var/jenkins_home/workspace/Libertya-Core/ServidorOXP/lib/OXPXLib.jar\\**[signjar] jarsigner error: java.lang.RuntimeException: keystore load: /var/jenkins_home/workspace/Libertya-Core/ServidorOXP/keystore/myKeystore (No such file or directory)** | ||
| 374 | |||
| 375 | **BUILD FAILED**\\**/var/jenkins_home/workspace/Libertya-Core/ServidorOXP/build.xml:414: exec returned: 1** | ||
| 376 | |||
| 377 | Total time: 26 seconds | ||
| 378 | |||
| 379 | Luego de revisar la ejecución y hacer pruebas locales, se observó que no fue creado **ServidorOXP/keystore/myKeystore** en jenkins. Probablemente por algo ocurrido en el proceso de compilación. | ||
| 380 | |||
| 381 | Se modificó [[**VariablesCompilacion.sh**>>http://VariablesCompilacion.sh]] desde Github para hacer mas flexible la toma de variables para compilacion, ahora seteando un OXP_HOME adaptado a jenkins se debería poder compilar correctamente. | ||
| 382 | |||
| 383 | Se realizaron modificaciones en Libertya CORE pero aun así se tiene el problema de la keystore. Se va a configurar manualmente para que permita firmar los Jars a la hora de ejecutar el [[ConfigurarAuto.sh>>http://ConfigurarAuto.sh]] | ||
| 384 | |||
| 385 | Se optó por incluir la configuración de keystore desde el propio pipeline: | ||
| 386 | |||
| 387 | |||
| 388 | {{code language="bash"}} | ||
| 389 | stage('Preparar keystore') { steps { sh ''' | ||
| 390 | mkdir -p ${OXP_HOME}/keystore if [ ! -f ${OXP_HOME}/keystore/myKeystore ]; then keytool -genkey -keyalg RSA \ -alias libertya \ -dname "CN=Jenkins, OU=CI, O=TuEmpresa, L=Ciudad, ST=Provincia, C=AR" \ -keypass libertya \ -storepass libertya \ -validity 365 \ -keystore ${OXP_HOME}/keystore/myKeystore fi ''' } } | ||
| 391 | {{/code}} | ||
| 392 | |||
| 393 | La ejecución final funcionó correctamente. | ||
| 394 | |||
| 395 | BUILD SUCCESSFUL\\Total time: 1 minute 8 seconds | ||
| 396 | |||
| 397 | ~*~** 2025-06-12 02:01:46.38 OpenXpertya Log (CLogConsole) ~*~** | ||
| 398 | |||
| 399 | Si se examina el workspace se puede observar como quedó compilado Libertya:\\[[image:image10.png]] | ||
| 400 | |||
| 401 | Se configuró el pipeline para tomar lyrestapi y ejecutar los tests. Actualmente falla porque lyrestapi aun no es compatible con jdk11. Se va a configurar un jdk8 para poder hacer esta ejecución. | ||
| 402 | |||
| 403 | > Task :compileJava FAILED\\/var/jenkins_home/workspace/Libertya-Core/lyrestapi/src/main/java/org/libertya/api/controller/AbstractController.java:16: error: package javax.rmi.CORBA does not exist\\import javax.rmi.CORBA.Util;\\^\\Note: /var/jenkins_home/workspace/Libertya-Core/lyrestapi/src/main/java/org/libertya/api/security/WebSecurityConfig.java uses or overrides a deprecated API.\\Note: Recompile with -Xlint:deprecation for details.\\1 error | ||
| 404 | |||
| 405 | FAILURE: Build failed with an exception. | ||
| 406 | |||
| 407 | Se configuró jdk-8-temurin y se volvió a ejecutar: | ||
| 408 | |||
| 409 | java -version\\openjdk version “1.8.0_452”\\OpenJDK Runtime Environment (Temurin)(build 1.8.0_452-b09)\\OpenJDK 64-Bit Server VM (Temurin)(build 25.452-b09, mixed mode)\\[Pipeline] sh\\+ chmod +x ./gradlew\\[Pipeline] sh | ||
| 410 | |||
| 411 | + ./gradlew clean test\\Starting a Gradle Daemon (subsequent builds will be faster) | ||
| 412 | |||
| 413 | > Task :clean UP-TO-DATE | ||
| 414 | |||
| 415 | > Task :compileJava\\Note: /var/jenkins_home/workspace/Libertya-Core/lyrestapi/src/main/java/org/libertya/api/security/WebSecurityConfig.java uses or overrides a deprecated API.\\Note: Recompile with -Xlint:deprecation for details.\\Note: Some input files use unchecked or unsafe operations.\\Note: Recompile with -Xlint:unchecked for details. | ||
| 416 | |||
| 417 | > Task :processResources\\> Task :classes | ||
| 418 | |||
| 419 | > Task :compileTestJava\\> Task :processTestResources NO-SOURCE\\> Task :testClasses | ||
| 420 | |||
| 421 | > Task :test | ||
| 422 | |||
| 423 | AllocationIntegrationTests > initializationError FAILED\\java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98\\Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 424 | |||
| 425 | BPartnerIntegrationTests > initializationError FAILED\\java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98\\Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 426 | |||
| 427 | BPartnerLocationIntegrationTests > initializationError FAILED\\java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98\\Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 428 | |||
| 429 | BanksAccountsIntegrationTests > initializationError FAILED\\java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98\\Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 430 | |||
| 431 | BanksIntegrationTests > initializationError FAILED\\java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98\\Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 432 | |||
| 433 | CashBooksIntegrationTests > initializationError FAILED\\java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98\\Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 434 | |||
| 435 | Se obtuvieron varios errores que en local no ocurren. Se procede a cambiar el jdk por una version de oracle. | ||
| 436 | |||
| 437 | AllocationIntegrationTests > initializationError FAILED java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:98 Caused by: java.lang.IllegalArgumentException at Assert.java:702 | ||
| 438 | |||
| 439 | Se sigue obteniendo el mismo error. Se ejecutó gradlew clean test –info | ||
| 440 | |||
| 441 | Successfully started process ‘Gradle Test Executor 1’ | ||
| 442 | |||
| 443 | Gradle Test Executor 1 started executing tests. | ||
| 444 | |||
| 445 | > Task :test | ||
| 446 | |||
| 447 | AllocationIntegrationTests STANDARD_OUT\\- Neither @ContextConfiguration nor @ContextHierarchy found for test class [org.libertya.api.AllocationIntegrationTests], using SpringBootContextLoader\\- Could not detect default resource locations for test class [org.libertya.api.AllocationIntegrationTests]: no resource found for suffixes {-context.xml, Context.groovy}.\\- Could not detect default configuration classes for test class [org.libertya.api.AllocationIntegrationTests]: AllocationIntegrationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration.\\- Found @SpringBootConfiguration org.libertya.api.LYRestAPI for test class org.libertya.api.AllocationIntegrationTests\\- Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.event.ApplicationEventsTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]\\- Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@75390459, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@7756c3cd, org.springframework.test.context.event.ApplicationEventsTestExecutionListener@2313052e, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@2bd2b28e, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@16746061, org.springframework.test.context.support.DirtiesContextTestExecutionListener@57fd91c9, org.springframework.test.context.event.EventPublishingTestExecutionListener@6cfcd46d, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@52045dbe, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@674658f7, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@5c8eee0f, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@565b064f, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener@26425897, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@73163d48] | ||
| 448 | |||
| 449 | *. Caught exception while allowing TestExecutionListener [org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@16746061] to prepare test instance [org.libertya.api.AllocationIntegrationTests@419a20a6]\\java.lang.IllegalStateException: Failed to load ApplicationContext\\at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98)\\at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)\\at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)\\at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)\\at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43)\\at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)\\at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda~$invokeTestInstancePostProcessors~$8(ClassBasedTestDescriptor.java:363)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:368)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda~$invokeTestInstancePostProcessors~$9(ClassBasedTestDescriptor.java:363)\\at java.util.stream.ReferencePipeline~$3~$1.accept(ReferencePipeline.java:193)\\at java.util.stream.ReferencePipeline~$2~$1.accept(ReferencePipeline.java:175)\\at java.util.ArrayList~$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)\\at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)\\at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)\\at java.util.stream.StreamSpliterators~$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)\\at java.util.stream.Streams~$ConcatSpliterator.forEachRemaining(Streams.java:743)\\at java.util.stream.ReferencePipeline~$Head.forEach(ReferencePipeline.java:580)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:362)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda~$instantiateAndPostProcessTestInstance~$6(ClassBasedTestDescriptor.java:283)\\at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:282)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda~$testInstancesProvider~$4(ClassBasedTestDescriptor.java:272)\\at java.util.Optional.orElseGet(Optional.java:267)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda~$testInstancesProvider~$5(ClassBasedTestDescriptor.java:271)\\at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda~$before~$2(ClassBasedTestDescriptor.java:197)\\at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:196)\\at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:80)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda~$executeRecursively~$6(NodeTestTask.java:148)\\at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda~$executeRecursively~$8(NodeTestTask.java:141)\\at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda~$executeRecursively~$9(NodeTestTask.java:139)\\at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)\\at java.util.ArrayList.forEach(ArrayList.java:1249)\\at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda~$executeRecursively~$6(NodeTestTask.java:155)\\at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda~$executeRecursively~$8(NodeTestTask.java:141)\\at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda~$executeRecursively~$9(NodeTestTask.java:139)\\at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)\\at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)\\at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)\\at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)\\at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)\\at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)\\at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)\\at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda~$execute~$0(EngineExecutionOrchestrator.java:54)\\at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)\\at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)\\at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)\\at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)\\at org.junit.platform.launcher.core.DefaultLauncherSession~$DelegatingLauncher.execute(DefaultLauncherSession.java:86)\\at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)\\at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor~$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)\\at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor~$CollectAllTestClassesExecutor.access~$000(JUnitPlatformTestClassProcessor.java:79)\\at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)\\at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)\\at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\\at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\\at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\\at java.lang.reflect.Method.invoke(Method.java:498)\\at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)\\at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)\\at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)\\at org.gradle.internal.dispatch.ProxyDispatchAdapter~$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)\\at com.sun.proxy.~$Proxy2.stop(Unknown Source)\\at org.gradle.api.internal.tasks.testing.worker.TestWorker~$3.run(TestWorker.java:193)\\at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)\\at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)\\at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)\\at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)\\at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)\\at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)\\at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)\\at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)\\Caused by: java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.JDK14LoggerFactory loaded from file:/var/jenkins_home/workspace/Libertya-Core/ServidorOXP/lib/OXPXLib.jar). If you are using WebLogic you will need to add ‘org.slf4j’ to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.JDK14LoggerFactory\\at org.springframework.util.Assert.instanceCheckFailed(Assert.java:702)\\at org.springframework.util.Assert.isInstanceOf(Assert.java:621)\\at org.springframework.boot.logging.logback.LogbackLoggingSystem.getLoggerContext(LogbackLoggingSystem.java:294)\\at org.springframework.boot.logging.logback.LogbackLoggingSystem.beforeInitialize(LogbackLoggingSystem.java:118)\\at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationStartingEvent(LoggingApplicationListener.java:238)\\at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:220)\\at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)\\at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)\\at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)\\at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)\\at org.springframework.boot.context.event.EventPublishingRunListener.starting(EventPublishingRunListener.java:79)\\at org.springframework.boot.SpringApplicationRunListeners.lambda~$starting~$0(SpringApplicationRunListeners.java:56)\\at java.util.ArrayList.forEach(ArrayList.java:1249)\\at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)\\at org.springframework.boot.SpringApplicationRunListeners.starting(SpringApplicationRunListeners.java:56)\\at org.springframework.boot.SpringApplication.run(SpringApplication.java:298)\\at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:136)\\at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:141)\\at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:90)\\… 81 more | ||
| 450 | |||
| 451 | Luego de análisis y consultas, se modificó el pipeline para eliminar org/slf4j/impl y el index | ||
| 452 | |||
| 453 | zip -d OXPXLib.jar “org/slf4j/impl/*”\\zip -d OXPXLib.jar “META-INF/INDEX.LIST” | ||
| 454 | |||
| 455 | Para esto fue necesario instalar ZIP en el contenedor de jenkins. | ||
| 456 | |||
| 457 | Se configuraron las notificaciones por email mediante Extended email plugin. | ||
| 458 | |||
| 459 | [[image:image11.png]] | ||
| 460 | |||
| 461 | Node 22 y pnpm | ||
| 462 | |||
| 463 | Se instaló Node 22 y pnpm 9.6.0 para el deploy del pos-web y productos afines | ||
| 464 | |||
| 465 | curl -fsSL https:~/~/deb.nodesource.com/setup_22.x | bash -\\apt-get install -y nodejs\\npm install -g pnpm@9.6.0 | ||
| 466 | |||
| 467 | == SonarQube {{id name="sonarqube" /}}== | ||
| 468 | |||
| 469 | Se realizaron pruebas a nivel local con SonarQube para el análisis de código, con la posibilidad de integrarlo en el pipeline junto con los tests automáticos. | ||
| 470 | |||
| 471 | |=services: sonarqube: image~: sonarqube:latest ports: - “9000:9000” volumes: - sonarqube_data:/opt/sonarqube/data - sonarqube_extensions:/opt/sonarqube/extensions - sonarqube_logs:/opt/sonarqube/logs volumes: sonarqube_data: sonarqube_extensions: sonarqube_logs: | ||
| 472 | |||
| 473 | [[image:image12.png]][[image:image13.png]] | ||
| 474 | |||
| 475 | Se ejecutó sonar-scanner desde CLI (docker). Para eso fue necesario generar un token desde el servidor de SonarQube para el usuario admin. Después es necesario especificar el directorio donde se encuentra Libertya **compilado**. En este caso se configuró /libertya_export | ||
| 476 | |||
| 477 | |=docker run \ –rm \ -e SONAR_HOST_URL=“http:~/~/172.17.0.1:9000” \ -e SONAR_TOKEN=“squ_69d3653bc7494955e0187e4dee003fef14231bd0” \ -v “/libertya_export:/usr/src” \ sonarsource/sonar-scanner-cli | ||
| 478 | |||
| 479 | Para ejecutar el CLI se tiene que configurar un archivo **sonar-project.properties** en el directorio raiz del proyecto, en este caso directamente en /libertya_export | ||
| 480 | |||
| 481 | |=sonar.projectKey=libertya sonar.projectName=Libertya ERP sonar.projectVersion=1.0 sonar.sources=base/src,client/Src sonar.java.binaries=base/compilacion,client/compilacion sonar.sourceEncoding=UTF-8 | ||
| 482 | |||
| 483 | Uno de los errores que surgieron en la ejecución fue:\\22:39:23.573 INFO Sensor JavaSensor [java]\\22:39:23.593 ERROR Error during SonarScanner Engine execution\\org.sonar.java.AnalysisException: Your project contains .java files, please provide compiled classes with sonar.java.binaries property, or exclude them from the analysis with sonar.exclusions property.\\at org.sonar.java.classpath.ClasspathForMain.init(ClasspathForMain.java:70)\\at org.sonar.java.classpath.AbstractClasspath.getElements(AbstractClasspath.java:316)\\at org.sonar.java.SonarComponents.getJavaClasspath(SonarComponents.java:250)\\at org.sonar.java.JavaFrontend.<init>(JavaFrontend.java:92) | ||
| 484 | |||
| 485 | Esto se debe a que la CLI no encuentra los .class del proyecto. Se debe configurar explicitamente donde encontrarlos en el archivo **sonar-project.properties.** Para eso se utiliza la línea **sonar.java.binaries=base/compilacion,client/compilacion.** En este caso se incluyeron solamente los .class de esos directorios. Lógicamente no hay que tener en cuenta directorios relacionados a librerías como tools/ etc.. | ||
| 486 | |||
| 487 | Una vez ejecutado, va a aparecer el reporte en el servidor de sonarqube:\\[[image:image14.png]] | ||
| 488 | |||
| 489 | [[image:image15.png]] | ||
| 490 | |||
| 491 | Dentro de Jenkins se instaló el plugin SonarQube Scanner, luego en Tools se configuró:\\[[image:image16.png]] | ||
| 492 | |||
| 493 | y luego en administrar jenkins -> system se agrega el server | ||
| 494 | |||
| 495 | [[image:image17.png]] | ||
| 496 | |||
| 497 | Se configuró un pipeline de pruebas para la ejecución de SonarQube, los stages relevantes son los siguientes: | ||
| 498 | |||
| 499 | |||
| 500 | {{code language="bash"}} | ||
| 501 | stage('Analizar con SonarQube') { tools { jdk 'jdk-17' } steps { dir('libertya') { script { def scannerHome = tool 'SonarQube-Scanner' withSonarQubeEnv("${SONARQUBE_SERVER}") { sh """ ${scannerHome}/bin/sonar-scanner \ -Dsonar.projectKey=libertya \ -Dsonar.projectName="Libertya ERP" \ -Dsonar.projectVersion=1.0 \ -Dsonar.sources=base/src,client/Src \ -Dsonar.java.binaries=base/compilacion,client/compilacion \ -Dsonar.sourceEncoding=UTF-8 \ -Dsonar.token=${SONARQUBE_TOKEN} """ } } } } } stage('Esperar Quality Gate') { steps { timeout(time: 10, unit: 'MINUTES') { waitForQualityGate abortPipeline: true } } } | ||
| 502 | {{/code}} | ||
| 503 | |||
| 504 | Aún así, se presentaron errores en la ejecución: | ||
| 505 | |||
| 506 | 02:29:41.092 **WARN Invalid character encountered in file /var/jenkins_home/workspace/test/libertya/base/src/org/openXpertya/model/MRole.java at line 2 for encoding UTF-8. Please fix file content or configure the encoding to be used using property ‘sonar.sourceEncoding’.**\\02:29:46.206 **WARN** Invalid character encountered in file /var/jenkins_home/workspace/test/libertya/base/src/org/openXpertya/model/MAttributeSet.java at line 173 for encoding UTF-8. Please fix file content or configure the encoding to be used using property ‘sonar.sourceEncoding’.\\02:29:49.441 **WARN** Invalid character encountered in file /var/jenkins_home/workspace/test/libertya/base/src/org/openXpertya/model/MOrder.java at line 3550 for encoding UTF-8. Please fix file content or configure the encoding to be used using property ‘sonar.sourceEncoding’.\\02:30:10.808 **WARN** Invalid character encountered in file /var/jenkins_home/workspace/test/libertya/base/src/org/openXpertya/print/ArchiveEngine.java at line 125 for encoding UTF-8. Please fix file content or configure the encoding to be used using property ‘sonar.sourceEncoding’.\\02:30:21.575 INFO 42% analyzed\\02:30:37.897 INFO 43% analyzed\\02:30:42.794 **WARN** Invalid character encountered in file /var/jenkins_home/workspace/test/libertya/client/Src/org/openXpertya/grid/ed/VPAttributeDialog.java at line 1134 for encoding UTF-8. Please fix file content or configure the encoding to be used using property ‘sonar.sourceEncoding’.\\02:30:42.847 **WARN** Invalid character encountered in file /var/jenkins_home/workspace/test/libertya/base/src/org/openXpertya/model/MQuarter.java at line 251 for encoding UTF-8. Please fix file content or configure the encoding to be used using property ‘sonar.sourceEncoding’.\\**02:30:56.626 ERROR [stderr] OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c5200000, 378535936, 0) failed; error=‘Not enough space’ (errno=12)**\\**02:30:56.681 INFO [stdout] #**\\**02:30:56.681 INFO [stdout] # There is insufficient memory for the Java Runtime Environment to continue.**\\**02:30:56.681 INFO [stdout] # Native memory allocation (mmap) failed to map 378535936 bytes. Error detail: committing reserved memory.**\\**02:30:56.682 INFO [stdout] # An error report file with more information is saved as:**\\**02:30:56.682 INFO [stdout] # /var/jenkins_home/workspace/test/libertya/hs_err_pid10107.log**\\**02:30:57.682 INFO EXECUTION FAILURE**\\**02:30:58.539 INFO Total time: 5:32.863s** | ||
| 507 | |||
| 508 | El servidor llegó al límite de memoria, usar Jenkins, SonarQube, Postgres, etc.. es demasiada carga para la memoria actual. | ||
| 509 | |||
| 510 | Se deshabilitó temporalmente la utilización de SonarQUbe por sobrecarga en el servidor. | ||
| 511 | |||
| 512 | Se creó el pipeline Libertya-Core-Sandbox para pruebas que no afecten el pipeline “productivo”. | ||
| 513 | |||
| 514 | Se configuraron credenciales y secrets para transferir builds al server de desarrollo | ||
| 515 | |||
| 516 | = **Referencias** {{id name="referencias" /}}= | ||
| 517 | |||
| 518 | https://www.jenkins.io/doc/book/installing/ |