From c484224902e29f78f58a940cfb507a36bd513c8d Mon Sep 17 00:00:00 2001 From: aarroyo Date: Tue, 1 Sep 2026 11:17:50 -0500 Subject: [PATCH] fix(ci): que el verde del gate signifique que algo se construyo Ayer di por bueno que `skipped` pasara. El razonamiento era que un skip significa que fallo una suite previa, y esa ya lleva su propio check en rojo. La premisa era cierta y la conclusion era falsa: ese rojo no bloquea. `docker-services` depende de siete jobs de test, y dos de ellos --- `test-sdk-client` y `test-infra-providers` --- no son contextos requeridos ni en main ni en develop. Asi que un Dockerfile roto llegando junto a un solo flake en cualquiera de esas dos suites saltaba el build, reportaba este check en VERDE sin haber construido nada, y dejaba los ocho contextos requeridos satisfechos. Es exactamente el fallo que el job existe para impedir, ahora con chapa de check requerido. Un check requerido tiene que afirmar que el build CORRIO, no solo que no fallo. Dos rojos en vez de uno no es duplicar el reporte: es este check negandose a responder por algo que nunca vio. Segundo arreglo, del mismo cambio de ayer: `cache-to` escribia en cada PR. Tres imagenes en mode=max son cerca de un giga por run, y la cache de Actions es un unico pozo de 10 GB que ya guarda ~1.7 GB de los que dependen los tests. Cada PR escribiendo su copia habria desalojado por LRU las caches de npm, y eso se habria visto como las suites de test volviendose lentas sin motivo. Ahora todos leen y solo publican los refs que publican. Co-Authored-By: Claude Opus 5 Signed-off-by: aarroyo --- .github/workflows/ci-cd.yml | 42 ++++++++++++------- .../core/control-center/deploy/README.es.md | 3 +- .../core/control-center/deploy/README.md | 4 +- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 2a8e1444..f7b09007 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -926,8 +926,15 @@ jobs: # Now that this runs on every PR, an uncached three-image rebuild would # be the slowest thing in the pipeline. Scoped per service so the three # matrix legs do not evict each other. + # + # Everyone READS the cache; only publishing refs WRITE it. Three images + # at mode=max is roughly a gigabyte per run, and the repo's Actions + # cache is a single 10 GB pool already holding ~1.7 GB that the test + # jobs depend on. Letting every PR write its own copy would evict those + # npm caches by LRU and show up as the test suites mysteriously slowing + # down. This way a PR warms itself from main and writes nothing. cache-from: type=gha,scope=${{ matrix.service }} - cache-to: type=gha,mode=max,scope=${{ matrix.service }} + cache-to: ${{ env.PUBLISH == 'true' && format('type=gha,mode=max,scope={0}', matrix.service) || '' }} tags: | ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}:latest ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}:${{ github.sha }} @@ -937,6 +944,20 @@ jobs: # Those names change whenever a path or a service does, so they are a poor thing # for branch protection to name. This job collapses the three into one stable # context that CAN be marked required. + # + # ONLY `success` passes, and that is deliberate. The first version of this job + # let `skipped` through, reasoning that a skip means an upstream suite failed + # and that failure already carries its own red check. The premise was true and + # the conclusion was wrong: `docker-services` needs seven test jobs, and two of + # them -- `test-sdk-client` and `test-infra-providers` -- are NOT required + # contexts on main or develop. So a broken Dockerfile arriving together with a + # single flake in either suite would skip the build, report this check GREEN + # having built nothing, and leave all eight required contexts satisfied. That is + # the exact failure this job exists to prevent, wearing a required-check badge. + # + # A required check must assert that the build RAN, not merely that it did not + # fail. Two reds instead of one is not double-reporting; it is this check + # declining to vouch for something it never saw. docker-services-gate: name: Services build (GHCR) needs: [docker-services] @@ -947,20 +968,11 @@ jobs: run: | result='${{ needs.docker-services.result }}' echo "docker-services: ${result}" - case "${result}" in - success) - echo "las tres imagenes construyen" - ;; - skipped) - # An upstream test suite failed, so the build never ran. That - # failure already has its own red check; do not double-report it. - echo "no se construyo: una suite previa fallo y lo reporta su propio check" - ;; - *) - echo "::error::al menos una imagen de servicio no construye" - exit 1 - ;; - esac + if [ "${result}" != "success" ]; then + echo "::error::este check no puede afirmar nada: el build de imagenes termino en '${result}', no en 'success'" + exit 1 + fi + echo "las tres imagenes de servicio construyen" # GT-324 — deploy the freshly-pushed images to the Coolify runtime. # diff --git a/reference/core/control-center/deploy/README.es.md b/reference/core/control-center/deploy/README.es.md index 9cfc3f06..5f07100f 100644 --- a/reference/core/control-center/deploy/README.es.md +++ b/reference/core/control-center/deploy/README.es.md @@ -77,7 +77,8 @@ Fuente de verdad: `.github/workflows/ci-cd.yml`. un único check estable, **`Services build (GHCR)`** (job `docker-services-gate`), que es el contexto que nombra la protección de rama: los contextos de matrix llevan sus parámetros y cambian cada vez que cambia - una ruta. + una ruta. Pasa **solo** en `success`: un build saltado significa que el check + no vio nada, y entonces no puede responder por nada. 3. **`Deploy services (Coolify)`** (job `deploy`, `needs: [docker-services]`) — el paso de promoción. Su guarda es: diff --git a/reference/core/control-center/deploy/README.md b/reference/core/control-center/deploy/README.md index c045b441..c027959b 100644 --- a/reference/core/control-center/deploy/README.md +++ b/reference/core/control-center/deploy/README.md @@ -70,7 +70,9 @@ Source of truth: `.github/workflows/ci-cd.yml`. that would have caught it ran after they had already merged. The three matrix legs are collapsed into one stable check, **`Services build (GHCR)`** (job `docker-services-gate`), which is the context branch protection names — - matrix contexts carry their parameters and change whenever a path does. + matrix contexts carry their parameters and change whenever a path does. It + passes **only** on `success`: a skipped build means the check saw nothing and + must not vouch for anything. 3. **`Deploy services (Coolify)`** (job `deploy`, `needs: [docker-services]`) — the promotion step. Its guard is: