diff --git a/README.md b/README.md index f71fb44..d5b7930 100644 --- a/README.md +++ b/README.md @@ -71,13 +71,13 @@ Los unitarios y los e2e corren en CI como jobs separados en cada Pull Request; l flowchart LR A["git push a rama de feature"] --> B["Pull Request a main"] B --> C{"ci.yml: Lint + Unit tests + E2E tests"} - C -- "falla" --> X["PR no se integra (Andon Cord)"] - C -- "pasa" --> D["Merge a main"] + C -- " falla " --> X["PR no se integra (Andon Cord)"] + C -- " pasa " --> D["Merge a main"] D --> E["git tag vX.Y.Z + push del tag"] E --> F["release.yml"] F --> G{"Job ci: reutiliza ci.yml"} - G -- "falla" --> Y["No se construye ni se publica imagen"] - G -- "pasa" --> H["Job docker: build y push a Docker Hub con tag vX.Y.Z"] + G -- " falla " --> Y["No se construye ni se publica imagen"] + G -- " pasa " --> H["Job docker: build y push a Docker Hub con tag vX.Y.Z"] H --> I["Job deploy: deploy hook de Render con imgURL del tag exacto"] I --> J["Render descarga la imagen y despliega"] ``` @@ -91,20 +91,22 @@ _Esa captura corresponde a la primera corrida (release `v0.1.0`), con el job `De descrita en Fase 4. Las releases `v0.2.0` y `v0.3.0` corrieron el pipeline completo sin ese error; falta reemplazar la captura por una corrida en verde._ - +![Pull Request con los tres checks de CI requeridos en verde](docs/images/pr-checks.png) + +_PR #21: `Lint`, `Unit tests` y `E2E tests` aparecen como `Required` y en verde antes de habilitar el merge._ #### Componentes -| Componente | Herramienta | -|------------------------|-------------------------------------------------------------------| -| Control de versiones | GitHub (GitHub Flow, `main` protegida, Pull Requests) | -| Linter | oxlint (`npm run lint`) | -| Tests | Vitest (`npm test`) | -| Runner de CI | GitHub Actions (`ubuntu-latest`) | -| Registro de imágenes | Docker Hub — repo público `adrianberriel/curso-devops-api` | -| Plataforma de hosting | Render, plan Free — imagen `v0.3.0` corriendo en producción | -| Instrumentación | OpenTelemetry (zero-code, export OTLP directo, sin agente) | -| Monitoreo | Grafana Cloud — Application Observability | +| Componente | Herramienta | +|-----------------------|-------------------------------------------------------------| +| Control de versiones | GitHub (GitHub Flow, `main` protegida, Pull Requests) | +| Linter | oxlint (`npm run lint`) | +| Tests | Vitest (`npm test`) | +| Runner de CI | GitHub Actions (`ubuntu-latest`) | +| Registro de imágenes | Docker Hub — repo público `adrianberriel/curso-devops-api` | +| Plataforma de hosting | Render, plan Free — imagen `v0.3.0` corriendo en producción | +| Instrumentación | OpenTelemetry (zero-code, export OTLP directo, sin agente) | +| Monitoreo | Grafana Cloud — Application Observability | #### Workflows @@ -177,8 +179,8 @@ estructura a completar en lugar de depender de que el autor se acuerde: ```markdown ## Description - ## Test evidence + ``` @@ -232,10 +234,10 @@ tienen test quedan fuera de la cuenta y el porcentaje sale inflado. Con esa conf 100 %, y midiendo todo `src/` el número real era 79 %. Por eso `vitest.config.ts` declara `coverage.include` explícitamente, y excluye solo lo que no tiene lógica que probar: -| Excluido | Motivo | -|---|---| -| `src/main.ts` | Bootstrap: levanta el servidor, sin lógica propia | -| `src/**/*.module.ts` | Solo declaran `controllers` y `providers` | +| Excluido | Motivo | +|----------------------|---------------------------------------------------| +| `src/main.ts` | Bootstrap: levanta el servidor, sin lógica propia | +| `src/**/*.module.ts` | Solo declaran `controllers` y `providers` | Con ese denominador la cobertura es de 100 % en statements y funciones. El 90 % en ramas corresponde a una sola rama sin cubrir, que es el decorador `@Controller()` de `app.controller.ts`: un artefacto de la instrumentación, no un @@ -279,7 +281,8 @@ llegan a la imagen final. incorporado. **Evidencia:** las imágenes publicadas son `linux/amd64`. `v0.1.0` pesa 61.32 MiB, `v0.2.0` 70.12 MiB y `v0.3.0` (la -que corre en producción) 79.61 MiB comprimida (Docker Hub las muestra en MB decimales: 64.3, 73.5 y 83.5) — el crecimiento viene de las dependencias de OpenTelemetry +que corre en producción) 79.61 MiB comprimida (Docker Hub las muestra en MB decimales: 64.3, 73.5 y 83.5) — el +crecimiento viene de las dependencias de OpenTelemetry agregadas entre releases. @@ -360,16 +363,16 @@ descartó desplegar un agente intermedio (Grafana Alloy) porque agregaría un co replicar en Render, cuando la app puede hablar OTLP por su cuenta. No se copió el comando del asistente tal cual: se verificó primero contra la documentación de OpenTelemetry y -probándolo, porque el comando que sugiere deja la instrumentación incompleta en este proyecto. El detalle técnico -(por qué hace falta un hook de ESM y cómo se carga en Node 24) está comentado en `otel-hook.mjs`, junto al código. +probándolo, porque el comando que sugiere deja la instrumentación incompleta en este proyecto. El detalle técnico (por +qué hace falta un hook de ESM y cómo se carga en Node 24) está comentado en `otel-hook.mjs`, junto al código. **Dónde vive cada variable.** El criterio es qué es secreto y qué tiene que valer igual en los dos entornos: -| Variable | Dónde | Por qué | -|---|---|---| -| `NODE_OPTIONS`, `OTEL_SERVICE_NAME`, `OTEL_*_EXPORTER`, `OTEL_EXPORTER_OTLP_PROTOCOL` | `Dockerfile` | No son secretos y deben valer igual en local y en Render: quedan dentro de la imagen | -| `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS` | `.env` (local) / variables del servicio (Render) | El header lleva el token. `.env` está en `.gitignore` y en `.dockerignore` | -| `OTEL_RESOURCE_ATTRIBUTES` (`deployment.environment`) | `docker-compose.yaml` (`development`) / Render (`production`) | Es lo único que cambia entre entornos | +| Variable | Dónde | Por qué | +|---------------------------------------------------------------------------------------|---------------------------------------------------------------|--------------------------------------------------------------------------------------| +| `NODE_OPTIONS`, `OTEL_SERVICE_NAME`, `OTEL_*_EXPORTER`, `OTEL_EXPORTER_OTLP_PROTOCOL` | `Dockerfile` | No son secretos y deben valer igual en local y en Render: quedan dentro de la imagen | +| `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS` | `.env` (local) / variables del servicio (Render) | El header lleva el token. `.env` está en `.gitignore` y en `.dockerignore` | +| `OTEL_RESOURCE_ATTRIBUTES` (`deployment.environment`) | `docker-compose.yaml` (`development`) / Render (`production`) | Es lo único que cambia entre entornos | Las dependencias van en `dependencies`, no en `devDependencies`, porque el Dockerfile hace `npm prune --omit=dev` antes de armar la imagen final (verificado: el prune no remueve ningún paquete de OpenTelemetry). @@ -437,7 +440,8 @@ Primera release publicada: `adrianberriel/curso-devops-api:v0.1.0`. Release actu ![Tags del repositorio en Docker Hub](docs/images/dockerhub-tags.png) -_Esa captura es de cuando solo existía el tag `v0.1.0`; falta actualizarla para que muestre también `v0.2.0` y `v0.3.0`._ +_Esa captura es de cuando solo existía el tag `v0.1.0`; falta actualizarla para que muestre también `v0.2.0` y +`v0.3.0`._ ### 3. Aplicación de la Filosofía DevOps @@ -507,5 +511,6 @@ _Borrador — a revisar y completar con la evidencia final._ 2. **Defectos detectados tarde.** `ci.yml` corre lint y tests en cada Pull Request, y el mismo CI se vuelve a ejecutar sobre el tag antes de publicar (`needs: ci`), de modo que un defecto se frena antes de llegar al registro. 3. **Retrabajo por diferencias de entorno.** Un `Dockerfile` multi-stage con base pineada, usado igual en local y en - CI, evita el "en mi máquina funciona"; además la imagen final es liviana (61.32 MiB comprimida en `v0.1.0`), lo que reduce la + CI, evita el "en mi máquina funciona"; además la imagen final es liviana (61.32 MiB comprimida en `v0.1.0`), lo que + reduce la transferencia en cada publicación y despliegue. \ No newline at end of file diff --git a/docs/estado-del-proyecto.md b/docs/estado-del-proyecto.md index ab3d039..ef78cf3 100644 --- a/docs/estado-del-proyecto.md +++ b/docs/estado-del-proyecto.md @@ -65,7 +65,7 @@ las capturas van al final porque dependen de que lo demás exista. 2. [ ] **Experimento de falla controlada** (Tercera Forma). Genera además la evidencia `falla-controlada-1.png`. 3. [ ] **Principios Lean** y cierre de la Segunda/Tercera Forma con la evidencia real. 4. [ ] **Capturas** de la tabla de abajo. -5. [ ] **Cierre:** commitear y abrir PR de esta documentación, y limpieza de ramas (ver Housekeeping). +5. [ ] **Cierre:** PR de la captura `pr-checks.png` y limpieza de ramas (ver Housekeeping). ## Decisiones tuyas pendientes @@ -98,8 +98,8 @@ Cada una trae una recomendación; ninguna bloquea el plan de arriba. - [ ] Actualizar `main` local (está atrás de `origin/main`) y borrar las ramas ya mergeadas, locales y remotas (hay unas 20, incluida `docs/update-readme-status`). No hay PRs ni issues abiertos. -- [ ] Rama `docs/note-commit-convention-exceptions` con cambios sin commitear (README y este archivo): falta - commitear con `docs: ...` y abrir el PR. +- [x] PR #21 (excepciones de Conventional Commits y plan de trabajo) mergeado. Falta borrar su rama + `docs/note-commit-convention-exceptions`. ## Imágenes pendientes @@ -109,7 +109,7 @@ Van en `docs/images/`; los nombres deben coincidir con las referencias del infor |-----------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| | `pipeline-release.png` | ⚠️ desactualizada | Muestra la corrida fallida de `v0.1.0` (Deploy to Render en rojo). Reemplazar por una corrida `Release` completa en verde (ideal: la de `v0.3.0`) | | `dockerhub-tags.png` | ⚠️ desactualizada | Solo muestra `v0.1.0`. Reemplazar por una que incluya `v0.2.0` y `v0.3.0` | -| `pr-checks.png` | ❌ falta | Pull Request con los checks de CI (Lint, Unit tests y E2E tests) en verde | +| `pr-checks.png` | ✅ lista | PR #21 con los checks de CI (Lint, Unit tests y E2E tests) en verde; ya referenciada en el README | | `branch-protection.png` | ❌ falta | Settings > Branches: protección de `main` con los status checks requeridos | | `dockerhub-tag-detalle.png` | ❌ falta | Detalle de `v0.3.0` (linux/amd64, tamaño) | | `render-servicio.png` | ❌ falta | Servicio en Render corriendo la imagen `v0.3.0` | diff --git a/docs/images/pr-checks.png b/docs/images/pr-checks.png new file mode 100644 index 0000000..bf77fd5 Binary files /dev/null and b/docs/images/pr-checks.png differ