Programa pipelines como un Pro

bitbucket-pipelines

Cómo pasar de un pipeline monolítico a uno modular con un ownership escalable.

5 min de lectura

TL;DR

En la introducción y en los pipelines agénticos programamos steps, caches, condiciones de arranque y agentes, todo en un mismo bitbucket-pipelines.yml. Esto funciona para un ejemplo, pero en un proyecto real ese fichero se convierte en un cajón desastre de cientos de líneas donde conviven CI, CD y agentes, nadie es dueño de nada y cada modificación genera fricción. En esta entrada no aprenderemos ninguna figura nueva sino que usaremos lo que ya sabemos. Lo repartiremos por responsabilidad con definitions > imports, reutilizaremos steps y reduciremos el bitbucket-pipelines.yml a un enrutador de todo el CI/CD.

Nota

Todo lo que voy a contar no es más de lo que ya hay escrito en el blog (step, caches, parallel o agents). Lo único que cambia es dónde vive cada entidad. Ten en cuenta que esto es una programación totalmente opinionated y que a mí me ha funcionado.

El monolito no escala

Un bitbucket-pipelines.yml que contenga todo se hace francamente inmantenible cuando el proyecto crece. Cualquier nueva incorporación o evolución de un pipeline requiere estar leyendo un fichero enorme para encontrar un step o luchar por indentar bien el YAML. Además, mezclar responsabilidades hace que no podamos tener una visión general del alcance de nuestras automatizaciones del SDLC.

Un fichero por responsabilidad

La figura que lo resuelve es definitions > imports. Declaramos un alias por cada fichero externo donde vamos a repartir nuestros pipelines:

bitbucket-pipelines.yml
image: node:20-alpine
 
definitions:
  imports:
    ci: .bitbucket/ci-pipelines.yml
    cd: .bitbucket/cd-pipelines.yml
    agentic: .bitbucket/agentic-pipelines.yml

Con esto, ci, cd y agentic pasan a ser referencias a tres ficheros que viven en .bitbucket/ (no es obligatorio usar este directorio), y cada uno agrupa una responsabilidad. Los checks de código van en ci-pipelines.yml, los despliegues en cd-pipelines.yml y los agentes de IA en agentic-pipelines.yml. Dentro de cada fichero declaramos pipelines con su identificador bajo definitions > pipelines:

.bitbucket/ci-pipelines.yml
image: node:20-alpine
 
definitions:
  pipelines:
    pr-checks:
      - step:
          name: Lint
          script:
            - echo "npm run lint"
      - step:
          name: Test
          script:
            - echo "npm run test"

Fíjate en que ci-pipelines.yml no tiene sección pipelines: de primer nivel, o sea, no declara condiciones de arranque. No decide cuándo se ejecuta nada, solo define bloques con nombre (pr-checks) listos para que alguien los invoque. El cuándo se queda en el fichero principal.

El pipeline principal como router

Con las responsabilidades repartidas, el bitbucket-pipelines.yml se reduce hasta quedarse en lo único que de verdad le corresponde, decidir qué pipeline arranca con qué evento. Cada entrada es un import: nombre@alias que trae el pipeline con nombre del fichero correspondiente:

bitbucket-pipelines.yml
image: node:20-alpine
 
definitions:
  imports:
    ci: .bitbucket/ci-pipelines.yml
    cd: .bitbucket/cd-pipelines.yml
    agentic: .bitbucket/agentic-pipelines.yml
 
pipelines:
  pull-requests:
    '**':
      import: pr-checks@ci
 
  custom:
    'Deploy a staging':
      import: deploy-staging@cd
    'Auditoría semanal':
      import: security-audit@agentic

La sintaxis pr-checks@ci se lee como "el pipeline pr-checks del alias ci". El fichero principal se convierte así en un mapa que se lee casi en un lenguaje natural. A la izquierda el disparador (una PR, un custom...) y a la derecha de qué fichero sale la lógica.

Tip

Este fichero se vuelve muy estable. Añadir un step a CI ya no implica su modificación, se edita ci-pipelines.yml. El bitbucket-pipelines.yml solo cambia cuando aparece una condición de arranque nueva.

Reutilizar sin repetir

Dividir por ficheros mejora el ownership, pero dentro de cada fichero seguimos pudiendo repetirnos. El caso más habitual es la instalación de dependencias, con la que arranca casi todo pipeline. Copiar y pegar ese step en cada uno es el mismo monolito a menor escala. Aquí entran los anchors de YAML, que no son ningún término reservado de Bitbucket sino del propio formato. Definimos un valor una vez con &nombre y lo reutilizamos con *nombre.

.bitbucket/ci-pipelines.yml
definitions:
  pipelines:
    _install:
      - step: &install
          name: Instala dependencias
          caches:
            - node
          script:
            - echo "npm ci"
 
    pr-checks:
      - step: *install
      - parallel:
          fail-fast: true
          steps:
            - step:
                name: Lint
                script:
                  - echo "npm run lint"
            - step:
                name: Test
                script:
                  - echo "npm run test"

Definimos el step de instalación una sola vez, lo anclamos con &install y lo inyectamos donde haga falta con *install. Si mañana cambia el comando de instalación, vamos a ir a un solo sitio a modificarlo. Le pongo un guion bajo al bloque (_install) por una convención mía con la que marco los pipelines que solo existen para ejecutarse desde otros y que nunca dependen de una condición de arranque, a diferencia de pr-checks, que sí se dispara con las pull requests.

Nota

El fail-fast: true del parallel termina la ejecución del resto de steps en cuanto uno falla. En una batería de checks (lint, tipos, tests...) evita gastar minutos en algo que ya sabemos que va a echar para atrás la PR.

Ownership

Con todo modularizado, la responsabilidad reside en su sitio correspondiente. La curva de entrada a la programación del pipeline del proyecto se reduce, los conflictos de merge disminuyen y cada equipo razona sobre su fichero sin leerse las mil líneas de los demás.

Si te fijas, ninguna de las entidades descritas en esta entrada es nueva. Son los mismos steps, caches y agentes de las dos entradas anteriores. La diferencia entre un pipeline básico y uno de producción no suele estar en qué figuras usas, sino en cómo las organizas.

© 2026Roberto Pérez Llanos