Skip to main content

Proyecto Base

Es hora de pasar a un pipeline completo y para ello necesitaremos un código al que podamos aplicar los diversos pasos de un pipeline. Comenzaremos con el CI inicialmente y el CD podemos implementarlo al final utilizando GitOps.

Haz un fork de este repositorio a tu cuenta y comencemos. Recuerda, este código no es mío, pero podemos aplicar en la práctica los pipelines y usar los recursos de gitlab-ci. Acuérdate de hacer el fork dentro del grupo que tiene el runner que creaste si quieres usarlo, de lo contrario usará los runners compartidos de GitLab.

Al clonar este repositorio podemos observar que es un proyecto hecho en Node.js, es decir, para ejecutarlo vamos a necesitar Node.js.


~/Desktop/gitlab
git clone [email protected]:puziol/learn-gitlab-app.git
cd learn-gitlab-app
# Lo que tenemos en el proyecto
❯ tree -L 1
.
├── e2e
├── eslint.config.js
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── playwright.config.cjs
├── public
├── README.md
├── src
├── tests
└── vite.config.js

Vamos a hacer una modificación para que todo se instale automáticamente y de forma fácil.

Instala el DevBox y entiende cómo funciona, es importante porque creo que cambiará tu vida de aquí en adelante.

Como es un proyecto en nodejs necesitamos instalar Node para ejecutarlo. Esto es lo primero que debemos saber, porque en un pipeline vamos a necesitar en el proceso de build proporcionar el entorno que pueda construir este código.

  1. Instalar las dependencias: Vamos a necesitar npm para la gestión de paquetes y esto viene con la instalación de nodejs.
  2. Construir el proyecto
  3. Probar

En la carpeta del proyecto vamos a inicializar devbox.

# Inicializando el proyecto con devbox
❯ devbox init
# Añadiendo nodejs en la versión que queremos
❯ devbox add [email protected]
# Al iniciar el proyecto dentro de un entorno específico tendremos todo lo que necesitamos sin instalar nada en la máquina. También podemos aprovechar esto para el pipeline en el futuro.
❯ devbox shell
node --version
v23.11.0
npm --version
10.9.2

Observarás que aparecerá una carpeta .devbox así que es bueno ponerla en git-ignore para no subirla al repositorio y también el devbox.lock

echo ".devbox" >> .gitignore
echo "devbox.lock" >> .gitignore

Ahora que ya estamos en un entorno aislado, podemos instalar las dependencias antes de construir el proyecto y para eso podemos hacer.

npm install

added 371 packages, and audited 372 packages in 3s

123 packages are looking for funding
run `npm fund` for details

6 vulnerabilities (4 moderate, 2 critical)

To address all issues, run:
npm audit fix

Run `npm audit` for details.

Aquí ya tenemos un punto importante para el pipeline que vamos a montar, verificar las vulnerabilidades de paquetes.

Vamos a arreglar eso haciendo la actualización de los paquetes.

npm update

added 11 packages, removed 2 packages, changed 85 packages, and audited 380 packages in 17s

130 packages are looking for funding
run `npm fund` for details

6 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
npm audit fix --force

Run `npm audit` for details.

####
npm audit fix --force
npm warn using --force Recommended protections disabled.
npm warn audit Updating vitest to 3.1.2, which is a SemVer major change.
npm warn audit Updating @vitest/ui to 3.1.2, which is a SemVer major change.

added 3 packages, removed 7 packages, changed 11 packages, and audited 376 packages in 2s

129 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities

Listo, ahora no tenemos ninguna vulnerabilidad y tenemos la carpeta node_modules con las dependencias necesarias (paquetes). Ahora podemos construir el proyecto.

npm run build

> [email protected] build
> vite build

vite v6.3.2 building for production...
31 modules transformed.
build/index.html 0.47 kB │ gzip: 0.30 kB
build/assets/react-CHdo91hT.svg 4.13 kB │ gzip: 2.14 kB
build/assets/index-n_ryQ3BS.css 1.39 kB │ gzip: 0.72 kB
build/assets/index-BcKvuBhg.js 147.40 kB │ gzip: 47.58 kB
✓ built in 338ms

Y tenemos la carpeta build que también será ignorada por el .gitignore al subir el código. Eso es lo que necesitamos tener en el proceso de build, nuestra carpeta build.

Vamos a añadir el paquete serve para ejecutar el proyecto y verificar.

npm install serve
❯ npx serve ./build

┌────────────────────────────────────────┐
│ │
│ Serving!
│ │
│ - Local: http://localhost:3000 │
│ - Network: http://10.0.0.26:3000 │
│ │
│ Copied local address to clipboard!
│ │

Y tenemos el proyecto ejecutándose en el navegador.

alt text

Dos puntos importantes al aprovechar devbox. ¿El npm install podría formar parte de la inicialización cuando devbox suba, qué opinas?

Vamos a editar el archivo de devbox para que cuando se inicialice ya haga npm install si existe el archivo package.json. Podemos eliminar el test, pues no lo usaremos ahora.

{
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.2/.schema/devbox.schema.json",
"packages": ["[email protected]"],
"shell": {
"init_hook": [
"if [ -f package.json ]; then npm install; fi"
]
}
}

El código listo está en la rama devbox.

Quiero dejar claro que podríamos instalar node en la máquina y no necesitaríamos devbox, pero la limpieza y la facilidad que podemos tener en el futuro con los pipelines usando devbox es de otro mundo, lo veremos más adelante.

No para este estudio, pero ¡el pipeline podría comenzar localmente! En realidad muchos errores que tendremos con el pipeline en el futuro podrían resolverse localmente antes de subir el código. Echa un vistazo a pre-commit pero no lo implementes para este estudio.

Ahora hablando un poco del pipeline, el runner tiene que estar listo para ejecutar este proyecto y tenemos 3 opciones.

1 - Instalar node tan pronto como el runner comience. Si vamos a comenzar desde la imagen "debian:bullseye-slim", ten en cuenta que no tiene nodejs así que sería necesario instalarlo a través del gestor de paquetes apt de esta imagen. 2 - Utilizar el mismo proceso que hicimos localmente para ejecutar, es decir, instalar devbox y dejar que prepare el entorno completo. Sería lo mismo que el ítem 1, pero utilizaríamos menos comandos. 3 - Utilizar una imagen docker que ya viene con node instalado en lugar de "debian:bullseye-slim".

Todo el proceso de instalación requiere tiempo hasta que el runner esté listo para hacer lo que necesita. Cada job ejecutará todo ese proceso, de preparar el runner para que tenga capacidad de hacer lo que necesita.

La mejor forma de hacer esto es utilizar el ítem 3, ejecutando una imagen que ya tenemos lo que necesitamos, pero no siempre tenemos todo lo que necesitamos en una imagen y a veces una imagen es tan específica y para mantenerla pequeña todo se elimina. Por ejemplo una imagen node puede no tener el gestor de paquetes instalado para que instalemos un Curl si lo necesitamos.

La mejor forma es crear una imagen con todo lo que necesitamos, pero para eso es necesario conocimiento en Docker. Si no tienes esta experiencia deberías tenerla, porque hoy es base para DevOps y desarrollo.

Consejos

Al crear un proyecto podemos definir algunas cosas en Settings. Podemos hacer esto a nivel de grupo también para toda la organización. ¿Qué es bueno hacer?

En Settings > Merge request tenemos algunas opciones.

¿Cuál es el tipo de método de merge?

alt text

La opción de arriba no crea un commit para el merge request manteniendo el historial más limpio.

alt text

Squashing commits es útil al hacer push. Si hiciste varios cambios en la rama, en lugar de fusionar todos los cambios individualmente hechos en tu rama, creará un único commit en la rama de destino. Es mucho mejor para leer el historial.

Es interesante siempre que el pipeline tenga éxito y todas las marcas de revisión hayan sido corregidas.

alt text

Otra cosa que podemos hacer es crear ramas protegidas, para que nadie pueda hacer un push directo a una rama como main, siendo necesario un merge request y forzando la ejecución del pipeline. La rama main ya está protegida, pero las personas pueden hacer push directo a ella. Podemos eliminar eso.

alt text