Concepto clave
Una pipeline CI/CD completa es un flujo automatizado que integra desarrollo, pruebas y despliegue en un solo proceso. Imagina una fábrica de coches: cada pieza (código) pasa por una línea de montaje (pipeline) donde se verifica su calidad (tests), se ensambla (build) y finalmente se entrega al cliente (deploy). GitHub Actions actúa como el sistema de control de esa fábrica, orquestando cada etapa automáticamente cuando un desarrollador "empuja" cambios al repositorio.
En el contexto de aplicaciones modernas, esta pipeline no solo compila código, sino que ejecuta pruebas unitarias y de integración, analiza seguridad, genera artefactos y despliega en diferentes entornos (desarrollo, staging, producción). El valor real está en la retroalimentación inmediata: si un test falla, el desarrollador lo sabe en minutos, no días, reduciendo el tiempo de corrección de errores.
Cómo funciona en la práctica
Vamos a construir una pipeline para una aplicación Node.js con React frontend y API backend. El flujo tendrá estas etapas:
- Trigger: Se activa al hacer push a la rama main o abrir un pull request.
- Checkout: GitHub Actions descarga el código del repositorio.
- Setup: Configura Node.js y dependencias.
- Lint y Build: Verifica estilo de código y compila.
- Tests: Ejecuta pruebas unitarias y de integración.
- Security Scan: Analiza vulnerabilidades con CodeQL.
- Deploy: Despliega a un entorno de staging (Vercel para frontend, Heroku para backend).
Cada etapa es un job en GitHub Actions, que puede ejecutarse en paralelo o secuencialmente. Si una etapa falla, la pipeline se detiene, previniendo desplegar código defectuoso.
Código en acción
Aquí está el archivo .github/workflows/ci-cd-pipeline.yml que define nuestra pipeline:
name: CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
lint-and-build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Build application
run: npm run build
test:
runs-on: ubuntu-latest
needs: lint-and-build
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
CI: true
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
deploy:
runs-on: ubuntu-latest
needs: [test, security-scan]
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Deploy to Vercel (Frontend)
run: |
npm install -g vercel
vercel --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Heroku (Backend)
run: |
git push https://heroku:${{ secrets.HEROKU_API_KEY }}@git.heroku.com/${{ secrets.HEROKU_APP_NAME }}.git mainAntes de refactorizar, teníamos jobs separados para frontend y backend. Después, los combinamos en una pipeline unificada con dependencias claras (needs). Esto mejora la eficiencia y visibilidad.
Errores comunes
- No usar secrets correctamente: Exponer tokens en el código. Solución: Usa GitHub Secrets y referéncialos con
${{ secrets.NOMBRE }}. - Jobs sin dependencias: Ejecutar deploy antes de que pasen los tests. Solución: Define
needspara controlar el orden. - Ignorar el cache: Reinstalar dependencias cada vez, ralentizando la pipeline. Solución: Implementa caching con
actions/cache. - No manejar fallos: Si un job falla, la pipeline se detiene sin limpieza. Solución: Usa
continue-on-erroro steps de cleanup. - Desplegar en cada PR: Consumir recursos innecesarios. Solución: Usa condiciones como
if: github.ref == 'refs/heads/main'.
Checklist de dominio
- ¿Puedes crear un workflow que se active en push y pull requests?
- ¿Sabes configurar jobs con dependencias usando
needs? - ¿Implementas caching para acelerar builds?
- ¿Usas GitHub Secrets para manejar credenciales de forma segura?
- ¿Incluyes etapas de lint, test, security y deploy?
- ¿Manejas condiciones para controlar cuándo ejecutar deploy?
- ¿Monitorizas la pipeline con badges en el README?
Implementa una pipeline CI/CD para una app demo de tareas
En este ejercicio, crearás una pipeline completa para una aplicación de lista de tareas (todo app) con frontend en React y backend en Node.js. Sigue estos pasos:
- Prepara el entorno:
- Forkea este repositorio de ejemplo:
https://github.com/example/todo-app-demo - Clona tu fork localmente y navega al directorio.
- Forkea este repositorio de ejemplo:
- Crea el workflow:
- En tu repositorio, crea un archivo en
.github/workflows/ci-cd.yml. - Define el trigger para activarse en push a main y pull requests.
- En tu repositorio, crea un archivo en
- Configura los jobs:
- Job 1:
lint-build- Usa actions/checkout, setup-node, instala dependencias connpm ci, ejecuta ESLint y build. - Job 2:
test- Depende de lint-build, ejecuta tests connpm test. - Job 3:
deploy-staging- Depende de test, despliega a Vercel (frontend) y Heroku (backend) solo en la rama main.
- Job 1:
- Agrega mejoras:
- Implementa caching para node_modules usando actions/cache.
- Añade un step de security scan con CodeQL para JavaScript.
- Prueba la pipeline:
- Haz un push a tu rama main y verifica que todos los jobs pasen en la pestaña Actions de GitHub.
- Abre un pull request y confirma que la pipeline se ejecute.
Entrega: Sube el archivo YAML a tu repositorio y comparte el link en la discusión del curso.
Pistas- Usa el ejemplo de código de la lección como base, adaptando los nombres de los jobs y steps.
- Para caching, investiga la acción actions/cache con la clave 'node-modules-${{ hashFiles('package-lock.json') }}'.
- Configura los secrets VERCEL_TOKEN y HEROKU_API_KEY en Settings > Secrets and variables > Actions de tu repositorio.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.