Visión General de GitLab CI

GitLab CI/CD está integrado directamente en GitLab — sin plugins, sin servicio separado, sin configuración adicional. Cada repositorio de GitLab puede usar CI/CD agregando un archivo .gitlab-ci.yml a la raíz del repositorio. GitLab detecta este archivo automáticamente y ejecuta el pipeline.

Para ingenieros QA, GitLab CI ofrece varias ventajas: reportes de tests nativos en merge requests, registro de contenedores integrado, gestión de entornos y review apps para testing de despliegues.

Estructura de .gitlab-ci.yml

Pipeline Básico

stages:
  - build
  - test
  - deploy

install:
  stage: build
  image: node:20
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

unit-tests:
  stage: test
  image: node:20
  script:
    - npm run test:unit -- --ci --coverage
  artifacts:
    reports:
      junit: junit-results.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
  coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'

e2e-tests:
  stage: test
  image: mcr.microsoft.com/playwright:v1.40.0-focal
  script:
    - npm ci
    - npx playwright test
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    reports:
      junit: test-results/junit.xml
    expire_in: 7 days

Conceptos Clave

ConceptoDescripción
stagesLista ordenada de fases del pipeline; jobs en la misma etapa se ejecutan en paralelo
imageImagen Docker para el entorno del job
scriptComandos shell a ejecutar
artifactsArchivos a preservar entre etapas o después del pipeline
rulesCondiciones que controlan cuándo se ejecuta un job
needsDependencias directas entre jobs (salta el orden de etapas)
servicesContenedores Docker adicionales (bases de datos, APIs) para el job

Services: Dependencias de Test

Los services de GitLab CI levantan contenedores Docker junto a tu job. Esto es perfecto para tests de integración:

integration-tests:
  stage: test
  image: node:20
  services:
    - name: postgres:15
      alias: db
    - name: redis:7
      alias: cache
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: test_user
    POSTGRES_PASSWORD: test_pass
    DATABASE_URL: "postgresql://test_user:test_pass@db:5432/test_db"
    REDIS_URL: "redis://cache:6379"
  script:
    - npm ci
    - npm run test:integration

Los contenedores de servicio son accesibles por sus nombres alias (db, cache) como hostnames dentro del job.

Pipelines de Merge Request

GitLab puede ejecutar pipelines específicamente para merge requests, mostrando resultados directamente en el MR:

e2e-tests:
  stage: test
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
  script:
    - npx playwright test
  artifacts:
    reports:
      junit: test-results/junit.xml

Los resultados de tests de los reportes JUnit aparecen como una pestaña “Tests” en el merge request, mostrando conteos de éxitos/fallos y detalles de tests individuales.

Jobs Paralelos y Matrix

Keyword Parallel

Divide un job entre múltiples runners automáticamente:

e2e-tests:
  stage: test
  parallel: 4
  script:
    - npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL

GitLab establece CI_NODE_INDEX (1-4) y CI_NODE_TOTAL (4) automáticamente, habilitando test sharding sin configuración manual.

Estrategia Matrix

e2e-tests:
  stage: test
  parallel:
    matrix:
      - BROWSER: [chromium, firefox, webkit]
  image: mcr.microsoft.com/playwright:v1.40.0-focal
  script:
    - npx playwright test --project=$BROWSER

Caché

Cachea dependencias entre ejecuciones del pipeline para acelerar builds:

default:
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - node_modules/
    policy: pull-push

Gestión de Entornos

Los entornos de GitLab te permiten rastrear despliegues y conectarlos con testing:

deploy-staging:
  stage: deploy
  script:
    - ./deploy.sh staging
  environment:
    name: staging
    url: https://staging.example.com

smoke-tests:
  stage: test
  needs: [deploy-staging]
  script:
    - npx playwright test --config=smoke.config.ts
  environment:
    name: staging
    action: verify

Ejercicio: Diseña un Pipeline de GitLab CI

Crea un .gitlab-ci.yml para una aplicación web con:

  • Etapa build con instalación de dependencias
  • Etapa test con tests unitarios, integración (necesita PostgreSQL) y E2E en paralelo
  • Deploy a staging en rama main
  • Smoke tests después del despliegue a staging
  • Reportes de tests visibles en merge requests
Solución
stages:
  - build
  - test
  - deploy
  - verify

default:
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - node_modules/

install:
  stage: build
  image: node:20
  script:
    - npm ci
  artifacts:
    paths:
      - node_modules/
    expire_in: 1 hour

unit-tests:
  stage: test
  image: node:20
  needs: [install]
  script:
    - npm run test:unit -- --ci --coverage
  artifacts:
    reports:
      junit: junit-results.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
  coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'

integration-tests:
  stage: test
  image: node:20
  needs: [install]
  services:
    - name: postgres:15
      alias: db
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: test
    POSTGRES_PASSWORD: test
    DATABASE_URL: "postgresql://test:test@db:5432/test_db"
  script:
    - npm run test:integration
  artifacts:
    reports:
      junit: integration-results.xml

e2e-tests:
  stage: test
  image: mcr.microsoft.com/playwright:v1.40.0-focal
  needs: [install]
  parallel:
    matrix:
      - BROWSER: [chromium, firefox, webkit]
  script:
    - npm ci
    - npx playwright test --project=$BROWSER
  artifacts:
    when: always
    paths:
      - playwright-report/
      - test-results/
    reports:
      junit: test-results/junit.xml
    expire_in: 7 days

deploy-staging:
  stage: deploy
  image: alpine:latest
  needs: [unit-tests, integration-tests, e2e-tests]
  script:
    - ./scripts/deploy-staging.sh
  environment:
    name: staging
    url: https://staging.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

smoke-tests:
  stage: verify
  image: mcr.microsoft.com/playwright:v1.40.0-focal
  needs: [deploy-staging]
  script:
    - npm ci
    - npx playwright test --config=smoke.config.ts
  environment:
    name: staging
    action: verify
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

GitLab CI vs GitHub Actions vs Jenkins

FuncionalidadGitLab CIGitHub ActionsJenkins
Archivo config.gitlab-ci.yml.github/workflows/*.ymlJenkinsfile
Reportes de testsNativos en MRVía acciones tercerosVía plugins
Container registryIntegradoGitHub PackagesExterno
ServicesDocker services nativosService containersPlugin Docker
Parallel/Matrixparallel + matrixstrategy.matrixScripted pipeline
EntornosIntegrados con trackingFeature EnvironmentsSetup manual
Review AppsIntegradasVía acciones customSetup manual
Self-hostedGitLab RunnerSelf-hosted runnersFuncionalidad core

Mejores Prácticas para QA

  1. Siempre usa artifacts:reports:junit para obtener resultados de tests en merge requests. Esta es una de las funcionalidades más fuertes de GitLab CI para visibilidad de QA.

  2. Usa needs en lugar de ordenamiento por etapas cuando sea posible. La keyword needs permite que los jobs inicien tan pronto como sus dependencias terminen.

  3. Configura artifacts: when: always en jobs de test. Sin esto, los reportes y capturas de pantalla se pierden cuando los tests fallan.

  4. Usa parallel para suites de tests grandes. La keyword parallel integrada con CI_NODE_INDEX/CI_NODE_TOTAL hace el sharding trivial.

  5. Aprovecha services para tests de integración. Iniciar PostgreSQL, Redis u otras dependencias como services es más simple y rápido que instalarlas en el job.

  6. Usa rules en lugar de only/except. La keyword rules es más poderosa y el enfoque recomendado para controlar cuándo se ejecutan los jobs.