Módulo 2: Anatomy Of A Github Actions Workflow
3. Disparadores: `push`, `pull_request`, `workflow_dispatch`
Descripción
La lección 2 te mostró que on es la primera puerta que un evento tiene que cruzar. Esta lección profundiza en los tres disparadores más importantes de un pipeline de infraestructura como el de Andes Cargo: push (algo llegó a una rama), pull_request (alguien propone un cambio), y workflow_dispatch (un humano lo dispara a mano). Vas a correr los tres, con act, sobre el mismo archivo, y vas a descubrir —con una prueba real, no solo leída— un límite importante de lo que act puede simular: los filtros branches:/paths: que GitHub aplica del lado del servidor.
Conexión con el módulo
Esta lección usa el mismo anatomy-demo.yml de la lección 2, ahora mirado exclusivamente por su bloque on. La lección 4 hace lo mismo con un cuarto disparador, schedule, que merece su propia lección por la sintaxis cron y por una limitación distinta de act. La lección 6 —manos a la obra— retoma pull_request con un evento escrito a mano, más rico que el que act genera por defecto.
Analogía: la campana de la puerta de una tienda
Un disparador (on) es, literalmente, la campana de la puerta de una tienda: define qué tipo de entrada hace sonar la campana, no qué pasa después de que suena. push es la campana que suena cada vez que alguien entra cargando una caja nueva —un cambio que ya llegó a una rama—. pull_request es distinta: suena cuando alguien se para en la puerta proponiendo traer algo, antes de que ese algo esté realmente adentro —perfecto para revisar antes de aceptar, que es exactamente el patrón que vas a construir en el Módulo 3 con ci.yml—. workflow_dispatch es el botón que alguien de la tienda puede apretar manualmente, sin que nadie haya entrado por la puerta —"quiero que suene la campana ahora, aunque no entró nadie todavía"—.
Los tres disparadores, sobre el mismo archivo
Retomando el bloque on de anatomy-demo.yml (lección 2):
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
push — algo ya llegó a una rama
act push
Qué esperar (fragmento literal, ya visto completo en la lección 2):
[andes-cargo-ci-demo/inspect-environment] | Event that triggered this run: push
push es el disparador más directo: corre cada vez que uno o más commits llegan a una rama que el filtro permite. Es el disparador correcto para "algo cambió, ya está en el historial" — el que vas a usar para apply.yml en el Módulo 5, porque un apply de infraestructura solo debería correr sobre código que ya se fusionó, nunca sobre una propuesta todavía en revisión.
pull_request — alguien propone un cambio
act pull_request
Qué esperar (salida literal, ejecutada para escribir esta lección):
[andes-cargo-ci-demo/inspect-environment] | Event that triggered this run: pull_request
pull_request corre cuando se abre, actualiza, o reabre un Pull Request contra una rama que el filtro permite —sin que ese código haya llegado todavía a main—. Es el disparador de la mitad de CI del pipeline (Módulo 3): terraform plan corriendo sobre el cambio propuesto, como evidencia para quien lo revisa, antes de que exista la posibilidad de fusionarlo.
workflow_dispatch — un humano lo dispara a mano
act workflow_dispatch
Qué esperar (salida literal, ejecutada para escribir esta lección):
[andes-cargo-ci-demo/inspect-environment] | Event that triggered this run: workflow_dispatch
workflow_dispatch no espera ningún evento de Git — en un repositorio real de GitHub, aparece como un botón "Run workflow" en la pestaña Actions, que cualquier persona con permisos puede apretar cuando quiera. Vas a usarlo en el Módulo 5 para correr el job de detección de drift a mano, fuera de su horario programado, cuando quieras confirmarlo sin esperar al próximo disparo del cron.
El hallazgo de esta lección: act no aplica branches:/paths:
Hasta aquí, los tres disparadores se comportaron exactamente como esperarías. Pero hay una pregunta que todavía no respondiste: ¿qué pasa si le pides a act un push, y el evento describe una rama que el filtro branches: [main] no permite? Esta pregunta importa mucho para Andes Cargo — es, literalmente, la razón por la que apply.yml va a llevar branches: [main] en el Módulo 5: para que nunca corra sobre una rama de feature.
Un workflow de prueba, con el mismo filtro exacto que va a llevar apply.yml:
name: branch-filter-test
on:
push:
branches: [main]
jobs:
only-on-main:
runs-on: ubuntu-latest
steps:
- run: echo "This should only run for pushes to main"
Un evento de push escrito a mano, describiendo una rama que el filtro no permite:
{
"ref": "refs/heads/feature/add-shipment-tags",
"repository": { "default_branch": "main" }
}
act push -e push-feature-event.json -j only-on-main
Qué esperar (salida literal, ejecutada y verificada en esta máquina, hoy, contra act 0.2.89 — el hallazgo central de esta lección):
[branch-filter-test/only-on-main] ⭐ Run Main echo "This should only run for pushes to main"
[branch-filter-test/only-on-main] | This should only run for pushes to main
[branch-filter-test/only-on-main] ✅ Success - Main echo "This should only run for pushes to main" [66.615041ms]
[branch-filter-test/only-on-main] 🏁 Job succeeded
El job corrió, a pesar de que el evento describe explícitamente una rama distinta a main. Repetí exactamente la misma prueba con un filtro paths: ["terraform/**"] en vez de branches: —sobre un repositorio sin un solo archivo dentro de terraform/— y el resultado fue idéntico: el job corrió igual, sin que act evaluara el filtro de rutas en absoluto.
Esto no es un error de esta lección ni una mala configuración: es un comportamiento real y verificado de act. branches:/paths: son filtros que GitHub aplica del lado del servidor, antes incluso de asignarle un runner al job — GitHub mira el evento real (qué rama, qué archivos cambiaron) y decide si vale la pena arrancar el workflow siquiera. act no replica ese filtrado: toma el YAML, ve que el tipo de evento (push) coincide con algo que declaraste en on, y corre el job — sin mirar el contenido detallado de branches:/paths: para decidir si debería saltarlo.
La consecuencia práctica, honesta: branches: [main] en apply.yml (Módulo 5) sigue siendo la protección correcta y necesaria — funciona exactamente como esperas en GitHub real. Lo que no puedes hacer es usar act para demostrar que ese filtro funciona; act te va a mentir en ese punto específico, corriendo el job igual. Si algún día necesitas verificar de verdad que un filtro de rama funciona, la única forma confiable es probarlo contra un repositorio real de GitHub — exactamente el tipo de brecha que el Módulo 8 (lección 5) nombra sin rodeos.
Profundización: por qué apply.yml necesita branches: [main] de todas formas
Aunque act no pueda demostrarlo, el filtro sigue siendo indispensable en producción real. Sin branches: [main], un apply.yml que escucha push correría sobre cualquier rama —incluida una rama de feature con cambios a medio terminar—, aplicando infraestructura que nadie revisó todavía. El filtro convierte "corre en cualquier push" en "corre únicamente cuando el cambio llegó a la rama que representa el estado real de producción" — la pieza que hace que GitOps (Módulo 1, lección 4) sea cierto: Git, y específicamente main, es la fuente de verdad, no cualquier rama de trabajo en curso.
Errores comunes
Confiar en act push para "probar" que un filtro de rama funciona (el hallazgo central de esta lección, ahora como error común). Qué pasa: alguien escribe branches: [main] en un workflow, lo prueba con act push -e evento-de-otra-rama.json, ve que el job corre, y concluye —equivocadamente— que el filtro "no sirve" o que "algo está mal configurado". Por qué pasa: es razonable esperar que una herramienta que simula GitHub Actions replique todo el comportamiento de GitHub Actions. Cómo detectarlo: si tu prueba con act de un filtro de rama o de ruta corre el job cuando esperabas que lo saltara. Cómo corregirlo: recuerda que este es uno de los límites documentados de act —verificado en esta misma lección—: los filtros branches:/paths: son aplicados por el servidor de GitHub, no por el motor que corre el job. El filtro en sí está bien escrito; act, simplemente, no lo evalúa antes de arrancar.
Pedirle a act un evento que ningún job escucha (recap del Módulo 1, relevante otra vez aquí). Qué pasa: alguien corre act release sobre anatomy-demo.yml, que solo escucha push, pull_request y workflow_dispatch. Cómo detectarlo: el mensaje Error: Could not find any stages to run, ya visto en el Módulo 1. Cómo corregirlo: revisa act -l primero — la columna Events te dice, con precisión, qué eventos pedirle.
Ejercicios
Ejercicio 1 — Elige el disparador correcto para cada escenario. Para cada situación, indica si usarías push, pull_request o workflow_dispatch: (a) correr terraform plan cuando alguien propone un cambio de infraestructura, antes de fusionarlo; (b) correr terraform apply cuando un cambio ya se fusionó a main; (c) forzar una corrida del job de detección de drift ahora mismo, sin esperar su horario programado.
Ver solución
(a) pull_request — necesitas evidencia del cambio propuesto, antes de que exista la posibilidad de fusionarlo; es exactamente el rol de ci.yml en el Módulo 3. (b) push (con branches: [main]) — el apply solo debe correr sobre código que ya llegó a la rama real, nunca sobre una propuesta; es el rol de apply.yml en el Módulo 5. (c) workflow_dispatch — es el disparador manual, pensado exactamente para forzar una corrida fuera de su ciclo normal; vas a usarlo así en el Módulo 5, lección 7.
Ejercicio 2 — Explica el hallazgo de esta lección a un colega escéptico. Un colega te dice: "si act no aplica branches:, entonces act no sirve para nada, ¿no?". Respóndele en tres frases, sin exagerar en ningún sentido.
Ver solución
Una respuesta completa suena, más o menos, así: "No, act sigue siendo extremadamente útil — ejecuta de verdad el YAML, con las Actions reales, dentro de Docker, y eso cubre la inmensa mayoría de lo que necesitas verificar antes de subir un cambio. Lo único que no replica es un filtro muy específico —branches:/paths:— que GitHub aplica de forma centralizada antes de asignar un runner; para ese filtro puntual, confías en que está bien escrito y, si necesitas comprobarlo con certeza, lo pruebas contra un repositorio real de GitHub. No es 'no sirve para nada', es 'no reemplaza el 100% de lo que hace GitHub, y esta guía te dice exactamente en qué punto'."
Ejercicio 3 — Predice el resultado de un filtro combinado. Si apply.yml tuviera on: push: branches: [main] paths: ["andes-cargo-infra/**"], y corrieras act push con el evento por defecto (sin especificar -e) desde dentro de andes-cargo-infra/, ¿el job correría? ¿Por qué, según lo que aprendiste en esta lección?
Ver solución
Sí, correría — no porque el evento por defecto de act "cumpla" ambos filtros de forma correcta, sino porque, como viste en esta lección, act no evalúa ninguno de los dos filtros (branches: ni paths:) antes de decidir si el job corre. Mientras el tipo de evento (push) coincida con algo declarado en on, el job corre — sin importar qué rama o qué rutas describa el evento, sean el por defecto de act o uno escrito a mano.
Resumen y siguiente paso
En esta lección corriste los tres disparadores más comunes de un pipeline de infraestructura —push, pull_request, workflow_dispatch— y descubriste, con una prueba real y verificada, un límite concreto de act: los filtros branches:/paths: de un evento push no se aplican durante la simulación, porque son un mecanismo del lado del servidor de GitHub. Ese filtro sigue siendo la protección correcta para apply.yml en producción real; lo que cambia es que act, específicamente, no puede demostrártelo.
Antes de avanzar deberías poder: explicar la diferencia entre push y pull_request en una frase; elegir el disparador correcto para "revisar antes de fusionar" contra "aplicar después de fusionar"; y explicar, con precisión técnica, por qué act push corre un job aunque el evento describa una rama que el filtro branches: no permitiría en GitHub real.
La lección 4 cierra el trío de disparadores de infraestructura con el cuarto y último: schedule, con su propia sintaxis cron y su propia limitación de simulación.
Recursos
- GitHub Docs — Events that trigger workflows — la referencia oficial completa de
push,pull_request,workflow_dispatchy todos los demás eventos. - GitHub Docs — Triggering a workflow — documentación oficial de
branches:/paths:como filtros aplicados por GitHub. - nektosact.com — User Guide — documentación oficial de cómo
actinterpreta el nombre del evento pasado en la línea de comandos.