Módulo 1: De tu máquina al pipeline: por qué CI
8. Mini-proyecto: mapea tus pasos manuales a un pipeline
Descripción
Este es el capstone del módulo. Hasta aquí entendiste el problema ("en mi máquina funciona"), el concepto (la Integración Continua), su economía (el bucle de feedback), su anatomía (las etapas del pipeline), su propósito (la rama principal verde) y su frontera con el CD. Ahora vas a juntar todo eso en un ejercicio concreto y personal: tomar tu propio flujo manual de probar Reservo —lo que haces con tus manos cuando quieres saber si la suite está verde— y mapear cada paso a la etapa del pipeline que lo automatizaría. Al terminar vas a tener, escrito de tu puño, el plano de tu primer pipeline: qué hace hoy un humano que mañana hará una máquina, y por qué.
No vas a escribir todavía el archivo YAML —eso es el módulo 2, y con toda intención—. Vas a producir algo más valioso para llegar a ese módulo: el entendimiento de qué va a hacer ese YAML y por qué. Un pipeline escrito sin este entendimiento es un copiar-y-pegar que no sabrías depurar; un pipeline escrito después de este ejercicio es la automatización de un flujo que ya comprendes paso a paso. Vas a apoyarte en la suite real de Reservo, corriéndola de verdad para ver el verde que el CI va a custodiar, y en el caso "en mi máquina funciona" para identificar el riesgo de entorno que un pipeline borra.
Conexión con el módulo: esta lección no introduce conceptos nuevos; ejerce los siete anteriores sobre un caso que es tuyo. El mapa que produzcas es literalmente la lista de steps que escribirás en el módulo 2, solo que en prosa en vez de en YAML. Te quedas, al cerrar, con el problema y el concepto tan claros que el primer workflow del módulo 2 se va a sentir como transcribir algo que ya sabes, no como aprender algo nuevo. Ese es el objetivo: entrar al módulo 2 con el terreno preparado.
El encargo
Vas a entregar un expediente de automatización de tu flujo de testing de Reservo, con cinco piezas. Léelas completas antes de empezar; luego, más abajo, tienes una solución de referencia con la que comparar la tuya (pero intenta la tuya primero: el valor está en pensarlo, no en leerlo).
-
Tu flujo manual, paso a paso. Escribe, en orden, lo que haces con tus manos cuando quieres saber si la suite de Reservo está verde en una máquina nueva —desde que no tienes nada hasta que decides si el código está listo—. Sé concreto: comandos, no vaguedades.
-
La marca de "olvidable". Para cada paso, marca si es de los que un humano puede olvidar o hacer distinto cada vez (correr la suite, acordarse de instalar algo). Esos son los que más gana con la automatización: la máquina no olvida.
-
El mapeo a las cuatro etapas. Asigna cada paso de tu flujo a una de las etapas del pipeline de la lección 5: checkout, instalar, testear, reportar. Algún paso puede caer entre dos; decide y justifica.
-
El riesgo "en mi máquina". Identifica el único punto de tu flujo donde una fuga de entorno (lección 2) podría hacer que tu verde local no valga en otra máquina. Di cuál de las fugas es (variable, versión, dependencia, ruta, reloj, orden) y cómo un entorno limpio del CI la borra.
-
La justificación: qué se rompe hoy sin CI. Cierra con un párrafo que responda: si tu equipo sigue con este flujo manual, sin CI, ¿qué falla, y cuándo? Usa los conceptos del módulo —el olvido, la fuga de entorno, el bucle de feedback largo, la rama que se rompe—.
Prepara el terreno: corre la suite de verdad
Antes de escribir el mapa, corre la suite de Reservo tú mismo, para tener frente a ti el verde que el pipeline va a custodiar. Con la carpeta reservo/ y los test_*.py, y pytest instalado:
Qué esperar (el verde que el CI protegerá). Con Python 3.14.0 y pytest 9.1.1:
============================= test session starts ==============================
platform darwin -- Python 3.14.0, pytest-9.1.1, pluggy-1.6.0
rootdir: /private/tmp/reservo-ci
collected 12 items
test_pricing.py .... [ 33%]
test_refunds.py ..... [ 75%]
test_scheduling.py ... [100%]
============================== 12 passed in 0.04s ==============================
Ese 12 passed es tu punto de partida: el estado "verde" que el pipeline del módulo 2 va a repetir en cada push. Todo tu expediente es el plan para que ese verde deje de vivir solo en tu máquina.
Solución de referencia
Intenta tu versión antes de abrir esto. Aquí tienes un expediente completo, para Reservo, con el que contrastar el tuyo. Tu flujo puede diferir en detalles —quizá uses un gestor de dependencias distinto—; lo que importa es que las cinco piezas estén y que el razonamiento se sostenga.
Ver la solución de referencia completa
Pieza 1 — El flujo manual, paso a paso
Esto es lo que hago con mis manos para probar Reservo en una máquina nueva:
1. git clone <repo-de-reservo> # traer el código
2. cd reservo-ci # entrar al proyecto
3. python3 -m venv .venv # crear un entorno aislado
4. source .venv/bin/activate # activarlo
5. pip install -r requirements.txt # instalar pytest y demás
6. python3 -m pytest # correr la suite
7. (leer el resumen: "12 passed" o "N failed")
8. (decidir: si verde, el codigo esta listo para mergear; si rojo, arreglar)
Pieza 2 — La marca de "olvidable"
| Paso | ¿Olvidable / variable entre veces? | Por qué |
|---|---|---|
| 1. clonar | No (una vez por máquina) | Sin código no hay nada; no se olvida porque sin él no empiezas |
| 3–5. venv + install | Sí | Es fácil olvidar recrear el venv, o instalar con una versión distinta, o saltarse el requirements.txt "porque ya lo tenía instalado" |
| 6. correr la suite | Sí, el más olvidable | Es el paso que la gente se salta con prisa —"es un cambio chico, seguro no rompe nada"— y es justo el que importa |
| 7–8. leer y decidir | Sí | Un humano cansado puede leer mal el resumen, o mergear "confiando" sin haber corrido el paso 6 |
Los pasos marcados "Sí" son los que más gana la automatización: una máquina los hace siempre, igual, sin cansarse (pilar 1 de la lección 3, la grieta del olvido).
Pieza 3 — El mapeo a las cuatro etapas
| Mi paso manual | Etapa del pipeline |
|---|---|
1. git clone / traer el commit del cambio | Checkout |
2. cd al proyecto | (parte del checkout: situarse en el código) |
3–5. crear venv, activar, pip install -r requirements.txt | Instalar (construir el entorno limpio y reproducible) |
6. python3 -m pytest | Testear (el mismo comando que correrá el CI) |
| 7–8. leer el resumen y decidir | Reportar (en el CI, automático: nace del código de salida) |
Un detalle que decidí: los pasos 3–4 (crear y activar el venv) los pongo en instalar, no en una etapa aparte, porque su propósito es preparar el entorno donde instalar. En el CI, el runner ya arranca con un entorno aislado y limpio, así que la etapa de instalar es más simple todavía: no hay que crear un venv, la máquina entera es efímera.
Pieza 4 — El riesgo "en mi máquina"
El punto frágil de mi flujo está en el paso 5 (instalar) y, sobre todo, en lo que no aparece en mi flujo: nunca declaré qué versión de Python uso. Corro python3 -m pytest con la que tenga instalada —hoy 3.14.0, como muestra la cabecera de la salida—. Si un compañero tiene 3.11, o el runner usa 3.12, mi verde local no garantiza el suyo. La fuga es la versión de Python (y, en segundo lugar, la de las dependencias si el requirements.txt no está pinneado).
Un segundo riesgo, más sutil: si en algún momento el código llegara a depender de una variable de entorno —como el price_with_env frágil de la lección 2—, mi flujo la heredaría de mi shell sin que yo lo note. Lo compruebo corriendo ese caso en un entorno limpio:
$ env -u RESERVO_PRO_DISCOUNT python3 -m pytest test_env_pricing.py
============================== 1 failed in 0.03s ==============================
E AssertionError: assert 7500 == 6000
Ahí está la fuga en acción: sin la variable, el mismo test que en mi shell pasa, falla. Cómo la borra el CI: el runner arranca limpio, sin mis variables de shell y con la versión de Python declarada explícitamente. Corre el "caso B" por rutina, así que cualquier supuesto invisible de mi entorno sale a la luz como un rojo en el pipeline —hoy, en un PR— en vez de esconderse hasta la máquina de otro o hasta producción.
Pieza 5 — La justificación: qué se rompe hoy sin CI
Si el equipo sigue con este flujo manual, sin CI, tres cosas fallan, tarde o temprano:
- El olvido. El paso 6 —correr la suite— depende de que alguien se acuerde. Un viernes con prisa, alguien mergea "un cambio chico" sin correrlo. El bug entra a
main. - La fuga de entorno. Aunque sí corra la suite, la corre en su máquina, con su versión de Python y sus variables. Su verde no vale para el runner ni para el compañero. El bug del descuento pro puede pasar en su shell y romperse en otro lado —"en mi máquina funciona"—.
- El bucle largo y la rama rota. Cuando esas dos grietas se juntan, el bug no lo caza nadie hasta que otro clona
main, o hasta producción. Para entonces el contexto se enfrió (lección 4), el arreglo cuesta diez veces más,mainestá roto y frena a todo el equipo, y empieza el "¿quién rompió main?".
El CI cierra las tres de una vez: corre la suite automáticamente (mata el olvido), en un entorno limpio y declarado (mata la fuga), en cada PR antes de mergear (mantiene main verde y caza el bug mientras el contexto está tibio). Mi expediente de arriba es, literalmente, la lista de pasos que ese pipeline va a ejecutar por mí —el mismo flujo, hecho por una máquina que no olvida y que arranca sin mis supuestos—.
Criterios de una buena entrega
Tu expediente está bien si cumple esto —es la "memoria de cálculo" de tu primer pipeline—:
- Las cinco piezas están. Flujo, marca de olvidable, mapeo a etapas, riesgo de entorno, y justificación. Sin la pieza 4 (el riesgo "en mi máquina"), el expediente miente por omisión: todo flujo manual tiene al menos una fuga.
- El flujo es concreto. Comandos de verdad (
git clone,pip install -r requirements.txt,python3 -m pytest), no "instalo las cosas y corro los tests". El pipeline del módulo 2 se escribe con comandos, así que tu mapa debe estar en comandos. - El mapeo cubre las cuatro etapas. Cada etapa —checkout, instalar, testear, reportar— tiene al menos un paso tuyo asignado. Si te falta una, o tu flujo está incompleto o no reconociste una etapa.
- El riesgo está nombrado con precisión. No "podría fallar en otra máquina" a secas, sino cuál fuga (versión, variable, dependencia, ruta, reloj, orden) y cómo el entorno limpio la borra.
- La justificación usa los conceptos del módulo. El olvido, la fuga de entorno, el bucle de feedback, la rama verde. Si puedes explicar qué se rompe sin CI usando esas palabras, dominas el módulo.
Errores comunes
Entregar el flujo sin la pieza 4 (el riesgo de entorno). Qué pasa: alguien lista sus pasos, los mapea a etapas prolijamente, y omite identificar dónde su flujo depende del entorno —porque "en mi máquina todo funciona"—. El expediente se ve completo pero le falta justo lo que le da sentido al CI. Por qué pasa: la fuga de entorno es invisible desde dentro de tu propia máquina, que es donde todo funciona. Cómo detectarlo: si tu expediente no nombra ni una sola fuga, no es que no tengas ninguna; es que no la buscaste. Cómo corregirlo: todo flujo manual tiene al menos una fuga —empieza por la más común, la versión de Python, que tu propia salida de pytest delata en la cabecera platform ... -- Python X—. Compruébala corriendo algo en un entorno limpio (env -u, o pensando en qué versión usa el runner).
Mapear los pasos pero no marcar los "olvidables". Qué pasa: alguien hace el mapeo a etapas correctamente pero se salta la pieza 2, así que no distingue los pasos que un humano hace fiablemente de los que se le olvidan. Pierde el argumento central de por qué automatizar. Por qué pasa: el mapeo se siente como "la respuesta", y la marca de olvidable parece un extra. Cómo detectarlo: si no sabrías decir cuál de tus pasos es el que la gente más se salta, te falta la pieza 2. Cómo corregirlo: pregúntate, paso por paso, "¿alguien con prisa un viernes podría saltarse esto o hacerlo distinto?". El paso que más veces responde "sí" —correr la suite— es la razón número uno de existir del CI. Automatizar es, sobre todo, quitarle al humano los pasos olvidables.
Meter el despliegue en el expediente. Qué pasa: alguien, entusiasmado, añade un paso final "desplegar Reservo a producción" a su flujo. Pero Reservo no tiene app que desplegar, y el despliegue es CD, fuera de la frontera del módulo (lección 7). El expediente se sale del alcance. Por qué pasa: "CI/CD" invita a pensar en el despliegue como el final natural. Cómo detectarlo: si tu flujo termina en "desplegar" o "publicar", cruzaste al CD. Cómo corregirlo: tu expediente es del CI de los tests: termina en reportar el veredicto (verde/rojo) y decidir el merge, no en desplegar. La rama verde es la meta de este módulo; lo que se hace con esa rama verde después (CD) es otro camino, y con Reservo ni siquiera hay dónde demostrarlo.
Ejercicios
Ejercicio 1 — El paso que más importa automatizar. De tu flujo manual, elige el único paso que, si tuvieras que automatizar solo uno, automatizarías primero, y defiende la elección con dos argumentos del módulo. Luego di qué grieta de un verde local cierra ese paso automatizado.
Ver solución
El paso a automatizar primero es correr la suite (python3 -m pytest), el paso 6. Dos argumentos:
- Es el más olvidable y el más importante a la vez. Es el paso que la gente se salta con prisa —"es un cambio chico"— y es justo el que decide si el código funciona. Automatizarlo garantiza que la suite se corra siempre, no cuando alguien se acuerde.
- Es el corazón del bucle de feedback (lección 4). Correrlo automáticamente en cada push es lo que hace que el aviso de un fallo llegue en el escalón 3, temprano y con el contexto tibio, en vez de en producción.
La grieta que cierra: la del olvido (pilar 1 de la lección 3). La máquina corre la suite en cada cambio sin depender de que un humano se acuerde.
(Nota: automatizar "correr la suite" arrastra consigo instalar el entorno, porque sin entorno no hay suite; por eso en la práctica el primer pipeline hace checkout + instalar + testear juntos. Pero el motivo por el que lo montas es el paso 6.)
Ejercicio 2 — Reproduce tu propia fuga. Toma el riesgo de entorno que identificaste en la pieza 4 y diseña un experimento de una línea que lo demuestre en tu máquina —que haga que tu verde local se vuelva rojo simulando el entorno limpio del CI—. Descríbelo y predice el resultado. (Pista: la lección 2 usó env -u VARIABLE para quitar una variable; ¿qué usarías para tu fuga?)
Ver solución
Depende de tu fuga. Ejemplos de experimentos de una línea que simulan el entorno limpio:
- Fuga de variable de entorno:
env -u RESERVO_PRO_DISCOUNT python3 -m pytest. Quita la variable de tu shell para esa corrida, como haría el runner limpio. Predicción: si algún test dependía de ella, pasa de verde a rojo (lo vimos:assert 7500 == 6000). - Fuga de versión de Python: correr la suite con otra versión, por ejemplo
python3.11 -m pytest(si la tienes instalada) o dentro de un contenedor con la versión del runner. Predicción: si el código usa algo que no existe en esa versión, rojo; si no, verde —y entonces esa fuga concreta no aplica—. - Fuga de dependencia no declarada: crear un venv limpio, instalar solo lo que dice
requirements.txt, y correr. Predicción: si el código importaba un paquete que tenías "por casualidad" pero no está declarado, rojo con unImportError.
La lección: reproducir la fuga en tu propia máquina —quitándole a tu shell el supuesto invisible— es la forma más barata de comprobar que existe, y es exactamente la técnica que el módulo 3 desarrolla para reproducir fallos de CI. Si puedes volver tu verde rojo con una línea, acabas de encontrar lo que el CI habría encontrado por ti.
Ejercicio 3 — De la prosa al YAML (adelanto). Sin escribir YAML (eso es el módulo 2), predice: cuando en el módulo 2 traduzcas tu expediente a un workflow de GitHub Actions, ¿a cuántos steps (pasos) corresponderá tu flujo, aproximadamente, y qué hará cada uno? Enuméralos en una frase cada uno.
Ver solución
Tu expediente se traducirá, aproximadamente, a estos pasos de workflow (los nombres exactos y la sintaxis son del módulo 2; aquí solo el qué):
- Checkout: traer el código del commit que disparó el pipeline a la máquina limpia. (Corresponde a tu
git clone.) - Preparar Python: poner en la máquina la versión de Python declarada —aquí se cierra tu fuga de versión de la pieza 4—.
- Instalar dependencias:
pip install -r requirements.txtsobre la máquina limpia. (Tu paso 5; el venv ya no hace falta porque la máquina entera es efímera.) - Correr la suite:
python -m pytest, el mismo comando de tu paso 6, el corazón del pipeline. - Reportar: esto no es un
stepque escribas; GitHub lo hace solo, leyendo el código de salida de pytest para pintar el check verde o rojo (tus pasos 7–8, automáticos).
O sea: unos cuatro pasos escritos (checkout, preparar Python, instalar, testear) más el reporte automático. Fíjate en lo bonito: tu expediente en prosa ya es el workflow, solo le falta la sintaxis. Por eso hiciste este ejercicio antes del YAML —para que el módulo 2 sea transcribir algo que ya entiendes, no aprender algo nuevo—.
La lección: hay casi una correspondencia uno a uno entre los pasos manuales que mapeaste y los steps de tu primer workflow. El módulo 1 te dio el plano; el módulo 2 te da la sintaxis para construirlo.
Resumen y siguiente paso
En este mini-proyecto juntaste los siete conceptos del módulo en un expediente que es tuyo: tomaste tu flujo manual de probar Reservo —clonar, crear el entorno, instalar, correr pytest, leer, decidir— y lo mapeaste a las cuatro etapas del pipeline —checkout, instalar, testear, reportar—, marcando los pasos olvidables que más ganan con la automatización, nombrando con precisión el riesgo "en mi máquina" de tu flujo (empezando por la versión de Python que tu propia salida delata), y justificando qué se rompe hoy sin CI: el olvido, la fuga de entorno, el bucle largo y la rama rota. Corriste la suite de verdad para ver el 12 passed que el pipeline va a custodiar, y reprodujiste una fuga para comprobar que tu verde local no es universal.
Lo más importante que te llevas es esto: tu expediente en prosa ya es tu primer pipeline, solo le falta la sintaxis. Hay casi una correspondencia uno a uno entre los pasos que mapeaste y los steps que escribirás en el módulo 2. Ese es el propósito del ejercicio: entrar al módulo 2 con el problema y el concepto tan claros que escribir el YAML sea transcribir algo que ya sabes.
Con esto cierras el módulo 1. Sabes por qué existe el CI (el problema "en mi máquina funciona"), qué es (correr la suite automática, limpia y compartida en cada cambio), por qué conviene (el bucle de feedback), cómo funciona por dentro (las etapas y el código de salida), qué protege (la rama verde) y dónde termina (la frontera con el CD). Lo que sigue es hacerlo realidad: en el módulo 2 escribes tu primer workflow de GitHub Actions —el archivo YAML que declara las etapas que acabas de mapear— y lo ves correr tu suite de Reservo en cada push, con su log de verdad. El plano está listo; toca construir.
Recursos
- Construir y probar Python — documentación de GitHub — la guía oficial para correr
pytesten GitHub Actions: el workflow concreto al que tu expediente se traducirá en el módulo 2. Ojéala como adelanto de dónde vas. - Cómo invocar pytest — documentación de pytest — la referencia del comando de la etapa "testear", el mismo que correrá tu pipeline. El paso 6 de tu flujo manual.
- Códigos de salida de pytest — documentación de pytest — la señal (0 = verde, 1 = rojo) de la que nace la etapa "reportar" automática de tu pipeline. Confirma qué mira el CI para pintar el check.
venv— documentación de Python — los entornos virtuales de los pasos 3–4 de tu flujo manual, que en el CI se vuelven innecesarios porque la máquina entera es efímera. Útil para entender qué automatiza (y qué simplifica) el runner limpio.