From 1fb8497f2f2d0fda36d39a64f5c4dfd38ecaf339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patxi=20Gort=C3=A1zar?= Date: Sat, 31 Oct 2026 15:17:36 +0100 Subject: [PATCH] Seed the test-time artifacts and re-check failed lookups in CI Run 40870887229 failed one build job on an artifact that exists: maven-surefire-plugin:3.5.5:test: The following artifacts could not be resolved: org.apache.maven.surefire:common-java5:jar:3.5.5 (absent): Could not find artifact ... in central Correcting the first reading of this, which said the shared cache had carried a bad marker into the job. It had not. One build job failed while 85 of the 86 projects use the same surefire 3.5.5, so a poisoned shared cache would have taken all of them down, not one. The cache the build jobs restore is also never written back: actions/cache only saves on a key miss, and the warm job is the only miss. The failure was local to that job. What it really is: dependency:go-offline does not resolve what surefire pulls at test time, so every build job was fetching the JUnit Platform provider from Central on its own. 86 jobs asking for the same nine artifacts at the same time is the burst this whole job exists to avoid, and one of them came back as not found. So the warm job now runs the tests of one project, which leaves the provider in the cache for everyone else. Measured in a clean local repository with Maven 3.10.0, the version on the runners: - parte_4/tema_4.2/ejemplo-2 pulls all nine surefire artifacts, common-java5 among them. - A Spring Boot project built afterwards on that same repository needs zero additional surefire artifacts, so seeding once covers the rest. ejemplo-2 is the seed because it is the only project with no Spring and no containers: one test, fractions of a second. Unlike the warming loop, this step has a precise expectation, so it asserts the provider landed and fails if it did not; warming that silently stops warming puts the burst back without anyone noticing. -U is the second, separate change, and it addresses a failure that has not happened yet: if a bad marker ever does reach the shared cache, every job inherits a permanent "not found" for an artifact that is really there. Reproduced with a repository that returns 404 for one artifact: Maven 3.10.0 writes .lastUpdated files with an empty .error, and a later resolution reports (absent) and refuses to fetch even once the artifact is available again. -U clears it. On a complete cache it costs no extra requests and about a second. Co-Authored-By: Claude Opus 5 --- .github/workflows/maven-build.yml | 38 +++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml index 7b07624..c503683 100644 --- a/.github/workflows/maven-build.yml +++ b/.github/workflows/maven-build.yml @@ -86,7 +86,7 @@ jobs: while read -r p; do echo "::group::$p" - if ! mvn -B -ntp -f "$p/pom.xml" \ + if ! mvn -B -ntp -U -f "$p/pom.xml" \ -Dmaven.wagon.http.retryHandler.count=5 \ dependency:go-offline; then echo "::warning title=Cache warming::No se pudieron resolver las dependencias de $p" @@ -99,6 +99,36 @@ jobs: # veredicto lo da la matriz. Un fallo aqui no corta el flujo. echo "Proyectos sin resolver: $fallos" >> "$GITHUB_STEP_SUMMARY" + # go-offline no resuelve lo que surefire pide en tiempo de test: el + # proveedor de JUnit Platform y sus nueve artefactos lo bajaba cada job + # de build por su cuenta, y uno de ellos (common-java5) es el que fallo + # en el run 40870887229. Ejecutar los tests de un proyecto los deja en + # la cache, y a partir de ahi ningun job tiene que pedirlos. + # + # Se siembra con tema_4.2/ejemplo-2 porque es el unico proyecto sin + # Spring ni contenedores: un test, decimas de segundo. El proveedor que + # deja es el mismo que necesitan los otros 85. + - name: Seed the test-time artifacts + run: | + set -euo pipefail + + mvn -B -ntp -U -f parte_4/tema_4.2/ejemplo-2/pom.xml \ + -Dmaven.wagon.http.retryHandler.count=5 \ + test + + # A diferencia del paso anterior, aqui si hay una expectativa + # concreta que comprobar, asi que un fallo corta: si la siembra deja + # de sembrar en silencio, volvemos a tener 86 jobs pidiendo lo mismo + # a Central a la vez y nadie se entera hasta que falle. + proveedor=$HOME/.m2/repository/org/apache/maven/surefire + if ! find "$proveedor" -name 'surefire-junit-platform-*.jar' | grep -q .; then + echo "::error title=Cache seeding::La siembra no dejo el proveedor de surefire en la cache" + exit 1 + fi + + echo "Artefactos de surefire en la cache:" >> "$GITHUB_STEP_SUMMARY" + find "$proveedor" -name '*.jar' | sed "s|$proveedor/|- |" >> "$GITHUB_STEP_SUMMARY" + build: name: Build - ${{ matrix.project }} needs: [discover, warm-cache] @@ -124,8 +154,12 @@ jobs: distribution: 'temurin' cache: maven + # -U obliga a reintentar las resoluciones que fallaron antes. Sin el, + # una ausencia anotada en la cache compartida se convierte en un "no + # existe" permanente para los 86 jobs, aunque el artefacto este en + # Central. Con la cache completa no cuesta ninguna peticion extra. - name: Build with Maven - run: mvn -B -ntp -Dmaven.wagon.http.retryHandler.count=3 clean verify + run: mvn -B -ntp -U -Dmaven.wagon.http.retryHandler.count=3 clean verify working-directory: ${{ matrix.project }} result: