checkout, por eso
needs ordena pero no comparte ficheros, y por eso existen los artifacts. Si entiendes
dónde está la frontera del sistema de archivos, el YAML deja de ser algo que se copia y pasa a ser
algo que se deduce.
| Palabra | Qué es | Dónde aparece |
|---|---|---|
| Workflow | Un fichero YAML con una automatización completa | .github/workflows/*.yml |
| Event | Lo que dispara el workflow | La clave on: |
| Job | Un conjunto de steps que corren en una máquina | Bajo jobs: |
| Step | Una tarea individual, secuencial dentro del job | Bajo steps: |
| Action | Un paquete reutilizable de terceros o propio | uses: |
| Runner | La máquina virtual donde corre el job | runs-on: |
La frontera que importa no está entre workflow y job: está entre job y job. Los steps de un mismo job comparten disco, variables exportadas y directorio de trabajo. Dos jobs distintos no comparten nada — ni siquiera cuando uno espera al otro.
run frente a usessteps:
- uses: actions/checkout@v4 # ejecuta código empaquetado por otro
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci # ejecuta un comando de shell
- run: |
echo "varias líneas"
npm run build
uses trae comportamiento; with son sus parámetros. run es
literalmente una shell. Casi todos los fallos de principiante en un workflow son uno de estos dos:
poner with colgando de un run, o inventarse el nombre de una action que
no existe.
needsSin needs, los tres jobs arrancan a la vez. Con needs,
build espera — pero espera, no hereda: sigue arrancando en una máquina limpia y
tiene que volver a hacer checkout y volver a instalar dependencias. Lo único que cruza
esa frontera son los artifacts (upload-artifact / download-artifact) y los
outputs que el job declare explícitamente.
| Trigger | Cuándo dispara | Para qué se usa |
|---|---|---|
push | Al subir commits a una rama | Validar main y develop |
pull_request | Al abrir o actualizar un PR | Los checks del PR |
schedule | Cron, siempre en UTC | Auditorías nocturnas, backups |
workflow_dispatch | Un botón en la pestaña Actions | Despliegues y rollbacks manuales |
workflow_run | Cuando termina otro workflow | Encadenar CD detrás de CI |
push y pull_request declarados los dos sobre main disparan
dos ejecuciones del mismo commit en un PR contra main. No es un error de
configuración, es cómo funciona el modelo de eventos — y es una de las razones de que exista
concurrency.
run: |
echo "Rama: ${{ github.ref_name }}"
echo "Commit: ${{ github.sha }}"
env:
API_KEY: ${{ secrets.API_KEY }} # se pasa, no se imprime
| Contexto | Qué trae |
|---|---|
github | Evento, repositorio, rama, SHA, quién lo lanzó |
env | Variables definidas a nivel de workflow, job o step |
secrets | Valores cifrados del repositorio o del environment |
runner | Sistema operativo, arquitectura, directorio temporal |
needs | Los outputs y el resultado de los jobs de los que dependes |
Un secreto se pasa como variable de entorno y no se imprime nunca. GitHub enmascara en los logs los valores que conoce, pero esa red se rompe en cuanto el valor se transforma: si lo trocean, lo codifican en base64 o lo concatenan con otra cosa, lo que sale por el log ya no coincide con el patrón que el enmascarado busca, y aparece en claro.
ubuntu-latest es Ubuntu 22.04, que
macos-latest es macOS 14, y asigna «2000 min/mes (free)» por igual a las cuatro
filas. Dos preguntas antes de fiarse. ¿A qué fecha corresponde ese mapeo de latest,
si la etiqueta se mueve sola cada vez que GitHub promociona una imagen nueva — es decir, si el
dato caduca solo? Y sobre los minutos: ¿consumen igual los cuatro runners, o hay un multiplicador
que hace que un minuto de Windows o de macOS descuente más que uno de Ubuntu? Si lo hay, una tabla
con la misma cifra repetida cuatro veces induce a error justo en la decisión que más dinero
cuesta.
Escribe un workflow con dos jobs. El primero hace echo hola > prueba.txt. El
segundo lleva needs: [primero] y hace cat prueba.txt. Empújalo y mira
cómo falla.
Ese No such file or directory es la lección entera en una línea. Ahora arréglalo
subiendo el fichero con actions/upload-artifact y descargándolo en el segundo job: la
frontera entre jobs deja de ser algo que has leído y pasa a ser algo con lo que te has chocado.