Skip to main content

Build

Lo primero que necesitamos es ejecutar el build de nuestro proyecto y para eso vamos a utilizar stages para dividir las etapas. Conviene recordar que el orden de los stages importa.

Para hacer el build vamos a necesitar instalar las dependencias, igual que lo hicimos para ejecutar el proyecto, es decir, todo en la misma secuencia, como si fuésemos a ejecutar el proyecto localmente.

Existen dos métodos para hacer la instalación de las dependencias.

  • npm install: instalará las dependencias de acuerdo con lo que está en el package.json
  • npm ci: instala las dependencias utilizando el archivo package-lock.json sin hacer ninguna alteración respetando exactamente las versiones definidas y garantiza que tengamos una compilación replicable. Además, utilizar npm ci es más rápido que npm install

En nuestro escenario como es un proyecto pequeño cualquier cosa funcionaría, pero es bueno conocer las mejores prácticas. Entonces vamos a utilizar npm ci.

default:
tags:
- general

stages:
- build

build:
image: node:22-slim
script:
- node --version
- npm --version
# - npm install # Instalación de las dependencias
- npm ci # Instalación de las dependencias generará la carpeta node_modules
- npm run build # Generará la carpeta build

Las carpetas que se generen se perderán al final del job, entonces necesitamos guardar lo que nos interesa para uso futuro, por ejemplo crear una imagen docker o cualquier otra cosa.

La única carpeta que utilizaremos es la carpeta build generada en el proyecto. La carpeta node_modules para este escenario no es importante.

Artifacts Advanced

Vamos a profundizar un poco más en artifacts ahora antes de continuar. Si no pasamos el nombre del artefacto generado por este job recibirá el nombre default.

  • Podemos pasar un archivo específico o incluso carpetas enteras utilizando paths y podemos utilizar comodines para filtrar lo que vamos a pasar.

    ...
    artifacts:
    name: "job1-artifacts-file"
    paths:
    - build/ # carpeta completa
    - archivo # un archivo específico
    - teste/*xyz/* # todo dentro de la carpeta teste, pero sólo las carpetas que terminan con xyz
  • Pero no siempre queremos pasar todo lo que está en una carpeta y no necesitamos pasar camino por camino. Si hay algo específico que queremos excluir es posible usando exclude.

...
artifacts:
paths:
- binaries/ # Toda la carpeta binaries
exclude:
- binaries/**/*.o # Pero archivos terminados en .o no, en cualquier nivel, por el **
  • Podemos definir un tiempo para que ese artefacto sea eliminado utilizando expire_in. Si no se define, el tiempo por defecto es de 30 días. A continuación algunos ejemplos con varias opciones de cómo poder utilizar. Podemos usar sólo minutos si queremos y poner 720 minutos en lugar de 12 horas.

    expire_in: 1 week # singular
    expire_in: 2 weeks # plural
    expire_in: 5 days # plural
    expire_in: 1 day # singular
    expire_in: 7 hours # plural
    expire_in: 30 minutes
    expire_in: 1 week 2 hours
    expire_in: 1 day 1 hour 30 minutes # Día y hora en singular para 1.
    expire_in: 1 month # singular
    expire_in: 2 months # plural
  • No es posible limitar acceso a un usuario o grupo de estos artefactos. Esta es una configuración a nivel de repositorio y no de pipeline.

    ...
    artifacts:
    name: "build-artifacts"
    paths:
    ...
    Valor de whenDescripción
    on_successGenera artefactos sólo si el job es exitoso (valor por defecto).
    alwaysGenera artefactos independientemente del éxito o fallo del job.
    on_failureGenera artefactos sólo si el job falla.
    manualGenera artefactos sólo cuando el job se ejecuta manualmente.
    • always: es útil para generar artefactos de diagnóstico (como logs) incluso cuando el job falla.
    • on_failure: Ideal para capturar artefactos que son útiles sólo cuando el job falla, como logs de error o informes de fallo.

Artefacts Paths vs Artefact Reports

El reports en GitLab CI/CD es una funcionalidad especial que permite asociar artefactos a tipos específicos de informes para que GitLab trate estos archivos de una manera especial, ofreciendo funcionalidades adicionales. Esto es particularmente útil cuando quieres que GitLab sepa que determinado artefacto tiene un significado específico, como informes de cobertura de tests, informes de seguridad o variables de entorno, y quieres que estos archivos sean procesados y visualizados de una manera estructurada. Definimos estos tipos de cosas aquí

  artifacts:
when: on_success # Ya es el valor por defecto
expire_in: "1 hour"
paths:
...
reports: # Veremos más adelante.
...

Lo único que creo que podemos inyectar en nuestro pipeline y explorar por ahora son variables de entorno que podemos (no necesitamos), probar en el futuro.

En medio de nuestro pipeline vamos a generar una variable de entorno que después será cargada en otro job y vamos a probar.

Entonces para un punto inicial creo que el pipeline de build podría ser así.

default:
tags:
- general

stages:
- build

build:
image: node:22-slim
script:
- node --version
- npm --version
- npm ci # Instalación de las dependencias
- npm run build # Generará la carpeta .build
- echo "ACCESS_TOKEN=abc123" > test.env # Una prueba sólo para el reports
artifacts:
when: on_success # Ya es el valor por defecto
expire_in: "1 hour"
paths:
- build/ # La carpeta completa sin exclusiones
reports:
dotenv: test.env # Dentro de este archivo tenemos ACCESS_TOKEN=abc123

Sobre el reports, no estamos cargando una variable de entorno en este job, pero futuros jobs que dependen de estos artefactos deben venir con la variable ACCESS_TOKEN cargada en el terminal. Hablaremos más sobre variables después.

git checkout -b pipe/build
git add .gitlab-ci.yml
git cm "add build"
git push origin pipe/build

alt text

Si tenemos un job y stages, el job necesita tener su stage definido.

default:
tags:
- general

stages:
- build

build:
stage: build #### <<<<<
image: node:22-slim
script:
- node --version
- npm --version
- npm ci # Instalación de las dependencias
- npm run build # Generará la carpeta .build
- echo "ACCESS_TOKEN=abc123" > .env # Una prueba sólo para el reports
artifacts:
when: on_success # Ya es el valor por defecto
expire_in: "1 hour"
paths:
- build/ # La carpeta completa sin exclusiones
reports:
dotenv: .env

Rehaciendo el commit.

git checkout -b pipe/build
git add .gitlab-ci.yml
git cm "add build"
git push origin pipe/build

alt text

alt text

Y aquí todo el proceso del build.

Running with gitlab-runner 17.11.0 (0f67ff19)
on general-debian jyvyfkmfg, system ID: r_szdZCOX2meST
Preparing the "docker" executor
00:09
Using Docker executor with image node:22-slim ...
Using locally found image version due to "if-not-present" pull policy
Using docker image sha256:a7bca975c7f3a862dc60f3d8aaa3862fce3208066dd3567f060381b506f38402 for node:22-slim with digest node@sha256:157c7ea6f8c30b630d6f0d892c4f961eab9f878e88f43dd1c00514f95ceded8a ...
Preparing environment
00:01
Running on runner-jyvyfkmfg-project-69186599-concurrent-0 via 1d8224d47375...
Getting source from Git repository
00:02
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /builds/puziol/learn-gitlab-app/.git/
Created fresh repository.
Checking out 36c04930 as detached HEAD (ref is pipe/build)...
Skipping Git submodules setup
Executing "step_script" stage of the job script
00:14
Using docker image sha256:a7bca975c7f3a862dc60f3d8aaa3862fce3208066dd3567f060381b506f38402 for node:22-slim with digest node@sha256:157c7ea6f8c30b630d6f0d892c4f961eab9f878e88f43dd1c00514f95ceded8a ...
$ node --version # Nuestros primeros comandos
v22.15.0
$ npm --version
10.9.2
$ npm ci # Instalación de los paquetes
added 440 packages, and audited 441 packages in 10s
152 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ npm run build
> [email protected] build
> vite build
vite v6.3.2 building for production...
transforming...
31 modules transformed.
rendering chunks...
computing gzip size... # Véase a continuación las carpetas que fueron generadas.
build/index.html 0.47 kB │ gzip: 0.30 kB
build/assets/react-CHdo91hT.svg 4.13 kB │ gzip: 2.05 kB
build/assets/index-n_ryQ3BS.css 1.39 kB │ gzip: 0.71 kB
build/assets/index-BcKvuBhg.js 147.40 kB │ gzip: 47.66 kB
✓ built in 1.47s
$ echo "ACCESS_TOKEN=abc123" > .env
Uploading artifacts for successful job
00:04
Uploading artifacts... # Carga del build
build/: found 7 matching artifact files and directories
Uploading artifacts as "archive" to coordinator... 201 Created id=9845340606 responseStatus=201 Created token=eyJraWQiO
Uploading artifacts... # Carga del .env
.env: found 1 matching artifact files and directories
Uploading artifacts as "dotenv" to coordinator... 201 Created id=9845340606 responseStatus=201 Created token=eyJraWQiO
Cleaning up project directory and file based variables
00:01
Job succeeded

Cuando hacemos la descarga allá en la página del pipeline siempre recibiremos un archivo artifact.zip. Esto es porque no declaramos el nombre de nuestro artefacto. Lo haremos más tarde, cuando entendamos de variables específicas del gitlab-ci.

  artifacts:
name: artifacts-[job_name]-[commit_sha] # éste sería un buen nombre... pero aún no sabemos cómo hacer esto, así que espera las escenas de los próximos capítulos.

Vale la pena mencionar que varios pipelines pueden estar en ejecución al mismo tiempo en este mismo código y cada uno tiene sus artefactos específicos.