¿Cuántas veces has olvidado ejecutar los tests antes de hacer push? ¿Te has encontrado desplegando manualmente a producción a horas que no imaginabas? ¿Has tenido que volver atrás porque alguien del equipo rompió algo en main? Si has respondido sí a alguna de estas preguntas, GitHub Actions es la solución que necesitas.
GitHub Actions es el sistema de CI/CD (Continuous Integration/Continuous Deployment) integrado directamente en GitHub. Lo que hace especial a GitHub Actions no es solo que está perfectamente integrado con tu repositorio, sino que te permite automatizar prácticamente cualquier aspecto de tu workflow de desarrollo: desde ejecutar tests y validar code quality, hasta desplegar aplicaciones y publicar paquetes.
En este artículo vamos a ir desde cero hasta tener workflows completamente funcionales. Te mostraré cómo crear tu primer workflow, entenderás los conceptos fundamentales, verás ejemplos reales con Python, y al final tendrás las herramientas para automatizar tu propio proyecto. No necesitas experiencia previa con CI/CD, solo ganas de mejorar tu forma de trabajar.
Conceptos fundamentales
Antes de escribir código, necesitas entender cómo funciona GitHub Actions. La buena noticia es que todo gira alrededor de conceptos bastante intuitivos.
Workflows
Un workflow es básicamente un proceso automatizado que defines en un archivo YAML. Este archivo vive en .github/workflows/ en tu repositorio y contiene todas las instrucciones sobre qué hacer, cuándo hacerlo y cómo hacerlo. Puedes tener múltiples workflows en un mismo repositorio, cada uno con su propósito específico.
Events
Los events son los disparadores que inician tus workflows. Cuando ocurre un evento específico en tu repositorio, GitHub Actions puede ejecutar automáticamente uno o más workflows. Los eventos más comunes son:
push: Cuando alguien hace push de commits a una ramapull_request: Cuando se abre, actualiza o cierra un pull requestschedule: Para ejecutar workflows en horarios específicos (como un cron)workflow_dispatch: Para ejecutar workflows manualmente desde la UI de GitHubrelease: Cuando publicas una nueva release
Pero hay muchísimos más: issues, comentarios, stars, forks... prácticamente cualquier acción en GitHub puede ser un evento.
Jobs
Un workflow está compuesto por uno o más jobs. Los jobs son unidades de trabajo que se ejecutan en paralelo por defecto, aunque puedes configurar dependencias entre ellos. Cada job se ejecuta en un runner fresco, lo que significa que tiene su propio entorno aislado.
Steps
Dentro de cada job tienes steps, que son los comandos o acciones individuales que se ejecutan secuencialmente. Un step puede ser tan simple como ejecutar un comando de bash, o puede usar una action predefinida del marketplace.
Actions
Las actions son bloques reutilizables de código que realizan tareas específicas. GitHub tiene un marketplace enorme de actions creadas por la comunidad. Por ejemplo, hay actions para hacer checkout de tu código, configurar Python en distintas versiones, cachear dependencias, desplegar a diferentes plataformas, etc. También puedes crear tus propias actions.
Runners
Los runners son las máquinas donde se ejecutan tus jobs. GitHub proporciona runners hosteados con Ubuntu, Windows y macOS, completamente gratis para repositorios públicos (con límites para privados). También puedes usar self-hosted runners si necesitas un entorno específico o más control.
¿Cómo se conecta todo?
Piénsalo así: cuando ocurre un event (como un push), GitHub ejecuta tu workflow. Ese workflow tiene uno o más jobs que corren en runners. Cada job tiene varios steps que pueden ejecutar comandos o usar actions. Simple, ¿verdad?
Tu primer Workflow
Vamos a crear nuestro primer workflow de Continuous Integration para un proyecto Python. Este workflow ejecutará tests automáticamente cada vez que hagas push o abras un pull request.
Imagina que tienes un proyecto Python con esta estructura:
mi-proyecto/
├── src/
│ └── calculator.py
├── tests/
│ └── test_calculator.py
├── requirements.txt
└── .github/
└── workflows/
└── ci.ymlAquí está el contenido del workflow .github/workflows/ci.yml:
name: CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pytest pytest-cov
- name: Run tests
run: |
pytest tests/ -v --cov=src --cov-report=term-missing
- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: pytest-results
path: test-results/
retention-days: 30Desglosamos
Vamos a analizar cada sección:
name: CI Pipeline - Es el nombre que aparecerá en la UI de GitHub. Hazlo descriptivo.
on: - Define cuándo se ejecuta el workflow. En este caso:
pusha las ramasmainydevelopCualquier
pull_requestcontramain
jobs: - Aquí definimos los trabajos. Tenemos uno llamado test.
runs-on: ubuntu-latest - Le dice a GitHub que use un runner con Ubuntu. Otras opciones son windows-latest y macos-latest.
steps: - Los pasos que se ejecutan en orden:
Checkout code: Usa la action
actions/checkout@v4para descargar tu código al runner. Sin esto, el runner estaría vacío.Set up Python: Usa
actions/setup-python@v5para instalar Python 3.11. Puedes especificar la versión que necesites.Install dependencies: Ejecuta comandos de bash para instalar dependencias. Actualiza pip y luego instala tus requirements más pytest.
Run tests: Ejecuta pytest con coverage. El flag
-vda output verbose,--cov=srcmide coverage del directorio src, y--cov-report=term-missingmuestra las líneas sin cubrir.Upload test results: Sube los resultados de tests como artifacts. El
if: always()garantiza que se ejecute incluso si los tests fallan, permitiéndote descargar los resultados para análisis. Los artifacts se retienen 30 días.
Cómo ver los resultados
Una vez que hagas commit de este archivo y lo pushees a GitHub, ve a la pestaña "Actions" de tu repositorio. Ahí verás tu workflow ejecutándose. Puedes hacer click para ver los logs de cada step en tiempo real.
Si algún test falla, el workflow marcará el commit con una X roja. Si todo pasa, verás un check verde. En pull requests, esto es especialmente útil porque puedes configurar que no se permita mergear si los checks no pasan.
Los artifacts subidos (como los resultados de tests) estarán disponibles para descargar desde la página del workflow, lo cual es útil para analizar fallos o generar reportes.
Casos de uso intermedios
Ahora que entiendes lo básico, vamos a ver casos de uso más potentes.
Ejemplo 1: Deployment Automático
Este workflow despliega automáticamente tu aplicación cuando creas un tag de versión:
name: Deploy to Production
on:
push:
tags:
- 'v*' # Ejecuta cuando pusheas tags como v1.0.0
workflow_dispatch: # Permite ejecución manual
inputs:
environment:
description: 'Environment to deploy'
required: true
type: choice
options:
- staging
- production
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install build twine
- name: Build package
run: python -m build
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: twine upload dist/*
- name: Deploy to server
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
SSH_USER: ${{ secrets.SSH_USER }}
SERVER_HOST: ${{ secrets.SERVER_HOST }}
run: |
echo "$SSH_KEY" > key.pem
chmod 600 key.pem
ssh -i key.pem -o StrictHostKeyChecking=no $SSH_USER@$SERVER_HOST << 'ENDSSH'
cd /var/www/myapp
git pull origin main
source venv/bin/activate
pip install -r requirements.txt
sudo systemctl restart myapp
ENDSSH
rm -f key.pemPuntos clave:
Se ejecuta cuando pusheas tags que empiezan con 'v' o manualmente con
workflow_dispatchEl
workflow_dispatchpermite ejecutar el workflow desde la UI de GitHub seleccionando el ambienteConstruye el paquete con
python -m buildPublica a PyPI usando secrets para las credenciales
Se conecta por SSH al servidor usando heredoc (
<< 'ENDSSH') para mayor robustez en comandos multilineaLimpia el archivo
key.pemdespués de usarlo por seguridadUsa
$SSH_USERcomo secret en lugar de hardcodear el usuario
Ejemplo 2: Code Quality Checks
Un workflow completo que valida calidad de código usando múltiples herramientas:
name: Code Quality
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install tools
run: |
pip install black isort flake8 mypy pylint bandit
pip install -r requirements.txt
- name: Check code formatting with Black
run: black --check src/
- name: Check import sorting with isort
run: isort --check-only src/
- name: Lint with flake8
run: flake8 src/ --max-line-length=100
- name: Type check with mypy
run: mypy src/ --ignore-missing-imports
- name: Security check with Bandit
run: bandit -r src/ -ll -f json -o bandit-report.json
# -ll = solo reporta issues de severidad medium/high
# Nota: No usamos continue-on-error porque queremos que
# el workflow falle si hay vulnerabilidades serias
- name: Upload Bandit results
if: always()
uses: actions/upload-artifact@v4
with:
name: bandit-report
path: bandit-report.json
retention-days: 30Este workflow ejecuta:
Black: Formatter de código
isort: Ordenador de imports
flake8: Linter de estilo
mypy: Type checker estático
Bandit: Scanner de seguridad con
-llpara reportar solo severidades medium/high
Si alguna herramienta encuentra problemas, el workflow falla, obligándote a arreglar el código antes de mergear. No usamos continue-on-error: true en el security check porque queremos que las vulnerabilidades serias bloqueen el merge.
Trabajando con secrets y variables de entorno
Para manejar información sensible como API keys, tokens, o passwords, GitHub Actions tiene un sistema de secrets:
Ve a Settings → Secrets and variables → Actions en tu repositorio
Crea un nuevo secret (por ejemplo,
PYPI_TOKEN)Úsalo en tu workflow con
${{ secrets.PYPI_TOKEN }}
Importante: Los secrets nunca se muestran en los logs. Si intentas hacer echo ${{ secrets.MI_SECRET }}, GitHub automáticamente lo censurará mostrando ***.
Para variables de entorno que no son sensibles, puedes usar el bloque env::
jobs:
build:
runs-on: ubuntu-latest
env:
DATABASE_URL: postgresql://localhost/mydb
DEBUG: false
steps:
- name: Print environment
run: |
echo "Database: $DATABASE_URL"
echo "Debug mode: $DEBUG"Tips y mejores prácticas
Cachear dependencias para acelerar builds
Instalar dependencias en cada ejecución es lento. Puedes cachear los paquetes de pip:
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txtEsto puede reducir el tiempo de instalación de 2-3 minutos a apenas segundos en ejecuciones subsecuentes. El cache se invalida automáticamente cuando cambias requirements.txt gracias al uso de hashFiles().
Usar Actions del Marketplace vs Scripts Custom
El GitHub Actions Marketplace tiene miles de actions listas para usar. Antes de escribir un script custom, busca si ya existe una action:
actions/setup-python@v5: Configura Pythoncodecov/codecov-action@v4: Sube coverage a Codecovpypa/gh-action-pypi-publish@release/v1: Publica a PyPIdocker/build-push-action@v5: Construye y pushea imágenes Docker
Usar actions del marketplace:
Ahorra tiempo de desarrollo
Está probado por la comunidad
Recibe actualizaciones de seguridad
Tiene mejor manejo de errores
Pero si necesitas algo muy específico, no dudes en escribir tu propio script.
Costes y límites de uso
Para repositorios públicos, GitHub Actions es completamente gratis con minutos ilimitados.
Para repositorios privados, tienes minutos gratis dependiendo de tu plan:
Free: 2,000 minutos/mes
Pro: 3,000 minutos/mes
Team: 3,000 minutos/mes
Enterprise: 50,000 minutos/mes
Los multiplicadores por runner son:
Ubuntu: 1x
Windows: 2x
macOS: 10x
Así que 10 minutos en macOS = 100 minutos de tu cuota.
Límites importantes a tener en cuenta:
Timeout máximo de job: 6 horas
Timeout máximo de workflow: 72 horas (35 días para self-hosted runners)
Tamaño máximo de logs: 64 KB por step de output
Artifacts: 500 MB por artifact individual, 10 GB total por workflow
Cache: 10 GB total por repositorio
Puedes revisar tu uso en Settings → Billing → Plans and usage.
Recursos de interés
Documentación oficial
La documentación de GitHub Actions es excelente y siempre actualizada. Aquí están los recursos esenciales:
Guía de inicio (https://docs.github.com/en/actions/quickstart): Tutorial interactivo perfecto para comenzar, con ejemplos paso a paso
Referencia de sintaxis de workflows (https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions): La referencia completa de todas las opciones disponibles en YAML
Contextos y expresiones (https://docs.github.com/en/actions/learn-github-actions/contexts): Explica cómo usar
${{ }}y qué información tienes disponibleVariables de entorno predefinidas (https://docs.github.com/en/actions/learn-github-actions/environment-variables): Lista completa de variables que GitHub proporciona automáticamente
Marketplace
Algunas actions imprescindibles para proyectos Python:
actions/checkout@v4: Checkout de código (casi siempre la necesitas como primer step)
actions/setup-python@v5: Configura Python en cualquier versión, con soporte para Poetry y pipenv
actions/cache@v4: Cachea dependencias para acelerar builds dramáticamente
actions/upload-artifact@v4: Sube archivos generados (reports, builds) para descargar después
actions/download-artifact@v4: Descarga artifacts de jobs anteriores
codecov/codecov-action@v4: Reporta coverage a Codecov con gráficas bonitas
github/codeql-action: Análisis automático de seguridad y vulnerabilidades
snok/install-poetry@v1: Instala y configura Poetry con caching inteligente
pre-commit/[email protected]: Ejecuta pre-commit hooks en CI
Explora más en el marketplace: https://github.com/marketplace?type=actions
Ejemplos de repos con workflows interesantes
Estudiar workflows de proyectos reales es la mejor forma de aprender patrones avanzados:
FastAPI (https://github.com/tiangolo/fastapi): Testing multi-plataforma, releases automatizadas, y deployment a PyPI
Django (https://github.com/django/django): Testing exhaustivo en múltiples versiones de Python y bases de datos
Requests (https://github.com/psf/requests): Ejemplo clásico de CI bien hecho con matrices simples pero efectivas
Flask (https://github.com/pallets/flask): Workflows simples pero muy efectivos para proyectos medianos
Black (https://github.com/psf/black): Auto-formatting, auto-releases, y self-testing de herramientas de quality
Conclusión
GitHub Actions transforma completamente cómo trabajamos. Lo que antes requería configurar Jenkins, mantener servidores CI, o ejecutar comandos manualmente, ahora es un archivo YAML en tu repo que funciona automáticamente.
La automatización no es solo sobre ahorrar tiempo, aunque ganarás horas cada semana. Es sobre algo mucho más valioso: paz mental.
Aquí va mi consejo, de desarrollador a desarrollador: no intentes implementar todo de golpe. Empieza con un workflow básico que ejecute tus tests. Solo eso. Úsalo una semana y verás cómo cambia tu forma de trabajar. Después, cuando ya sea parte de tu rutina, añade code quality checks. Y cuando eso se sienta natural, automatiza tus deployments. La mejor forma de adoptar GitHub Actions es paso a paso, dejando que cada mejora se asiente antes de añadir la siguiente.
El mejor momento para empezar es justamente ahora. Abre tu proyecto, crea .github/workflows/ci.yml, copia el ejemplo básico de este artículo, ajusta un par de líneas, y haz commit. En 10 minutos estarás viendo tu primer workflow ejecutándose. En una semana no querrás volver a trabajar sin él.
¿Vas a encontrarte con errores? Seguro. ¿Vas a tener que consultar la documentación? Sin duda. ¿Vas a aprender en el camino? Absolutamente. GitHub Actions no es algo que aprendes de memoria, es algo que vas dominando con la práctica.
Empieza pequeño. Tu primer workflow no tiene que ser perfecto, solo tiene que existir. Y cuando veas ese primer check verde, cuando sientas esa primera victoria de haber automatizado algo que antes hacías manualmente, vas a entender por qué GitHub Actions cambió la forma en que millones de desarrolladores trabajamos.
Tu yo del futuro, te lo agradecerá.
Nos vemos en la pestaña Actions.
