@@ -64,19 +64,60 @@ jobs:
6464 # fresh entry; the next run finds the most recent via prefix
6565 # fallback. The cache grows with new @Grab coordinates over time and
6666 # never gets invalidated by older ones being removed.
67- - name : " 🍇 Cache @Grab artifacts (~/.groovy/grapes)"
67+ - name : " 🍇 Cache @Grab artifacts (~/.groovy/grapes + ~/.m2/repository )"
6868 uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
6969 with :
70- path : ~/.groovy/grapes
70+ # ~/.groovy/grapes is what Grape/Ivy reads from at test time (via the
71+ # bridge in org.apache.groovy-tested.gradle). ~/.m2/repository is what
72+ # the pre-warm step below populates with mvn dependency:get — the bridge
73+ # also copies it into the test JVM's isolated localm2 root.
74+ path : |
75+ ~/.groovy/grapes
76+ ~/.m2/repository
7177 key : ${{ runner.os }}-grape-${{ github.run_id }}
7278 restore-keys : |
7379 ${{ runner.os }}-grape-
7480 - name : " 🐘 Setup Gradle"
7581 uses : gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
7682 - name : " 🔍 Setup TestLens"
7783 uses : testlens-app/setup-testlens@v1
84+ # Pre-warm the @Grab artifact cache by fetching each unique Maven-shorthand
85+ # coordinate referenced in test sources via `mvn dependency:get`. Maven uses
86+ # Apache HttpClient (vs Ivy's java.net.URLConnection), so it currently
87+ # passes Cloudflare's WAF in front of Maven Central while Ivy gets HTTP 404.
88+ # Once any run succeeds, actions/cache saves ~/.m2/repository for the next
89+ # run, and the org.apache.groovy-tested.gradle bridge copies the artifacts
90+ # into each test task's isolated localm2 root so tests stay off the network.
91+ # Failures here are non-fatal — Ivy will retry at test time and may succeed
92+ # on any individual artifact even when bursts are throttled.
93+ - name : " 🌡 Pre-warm @Grab artifacts via Maven"
94+ shell : bash
95+ run : |
96+ set +e
97+ coords=$(grep -rhEo "@Grab\(\s*(value\s*=\s*)?['\"][^'\"]+['\"]" src/test subprojects/*/src/test 2>/dev/null \
98+ | sed -E "s/.*@Grab\(\s*(value\s*=\s*)?['\"]([^'\"]+)['\"].*/\2/" \
99+ | grep -E '^[a-zA-Z0-9._-]+:[a-zA-Z0-9._-]+:[a-zA-Z0-9._+-]+$' \
100+ | sort -u)
101+ if [ -z "$coords" ]; then
102+ echo "No @Grab coords discovered — skipping pre-warm"
103+ exit 0
104+ fi
105+ n=$(printf '%s\n' "$coords" | wc -l | tr -d ' ')
106+ echo "Pre-warming $n @Grab coords via mvn dependency:get"
107+ ok=0; fail=0
108+ while IFS= read -r coord; do
109+ if mvn -B -q dependency:get -Dartifact="$coord" -Dtransitive=true >/dev/null 2>&1; then
110+ ok=$((ok+1))
111+ else
112+ fail=$((fail+1))
113+ echo " ⚠ $coord"
114+ fi
115+ done <<< "$coords"
116+ echo "Pre-warm complete: $ok ok / $fail failed (failures retried by Ivy at test time)"
117+ exit 0
118+ timeout-minutes : 15
78119 - name : " 🏃Test with Gradle"
79- run : ./gradlew test ${{ matrix.junit-network }} -Ptarget.java.home="$JAVA_HOME_${{ matrix.java }}_${{ runner.arch }}"
120+ run : ./gradlew test ${{ matrix.junit-network }} -Pgroovy.grape.bridge-cache=true - Ptarget.java.home="$JAVA_HOME_${{ matrix.java }}_${{ runner.arch }}"
80121 shell : bash
81122 timeout-minutes : 60
82123 - name : " 🚀Upload reports"
@@ -105,14 +146,38 @@ jobs:
105146 check-latest : true
106147 # See the lts job for rationale; same prefix lets both jobs share
107148 # the cache.
108- - name : " 🍇 Cache @Grab artifacts (~/.groovy/grapes)"
149+ - name : " 🍇 Cache @Grab artifacts (~/.groovy/grapes + ~/.m2/repository )"
109150 uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
110151 with :
111- path : ~/.groovy/grapes
152+ path : |
153+ ~/.groovy/grapes
154+ ~/.m2/repository
112155 key : ${{ runner.os }}-grape-${{ github.run_id }}
113156 restore-keys : |
114157 ${{ runner.os }}-grape-
115158 - uses : gradle/actions/setup-gradle@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2
159+ - name : " 🌡 Pre-warm @Grab artifacts via Maven"
160+ shell : bash
161+ run : |
162+ set +e
163+ coords=$(grep -rhEo "@Grab\(\s*(value\s*=\s*)?['\"][^'\"]+['\"]" src/test subprojects/*/src/test 2>/dev/null \
164+ | sed -E "s/.*@Grab\(\s*(value\s*=\s*)?['\"]([^'\"]+)['\"].*/\2/" \
165+ | grep -E '^[a-zA-Z0-9._-]+:[a-zA-Z0-9._-]+:[a-zA-Z0-9._+-]+$' \
166+ | sort -u)
167+ [ -z "$coords" ] && { echo "No @Grab coords — skipping"; exit 0; }
168+ n=$(printf '%s\n' "$coords" | wc -l | tr -d ' ')
169+ echo "Pre-warming $n coords"
170+ ok=0; fail=0
171+ while IFS= read -r c; do
172+ if mvn -B -q dependency:get -Dartifact="$c" -Dtransitive=true >/dev/null 2>&1; then
173+ ok=$((ok+1))
174+ else
175+ fail=$((fail+1)); echo " ⚠ $c"
176+ fi
177+ done <<< "$coords"
178+ echo "Pre-warm: $ok ok / $fail failed"
179+ exit 0
180+ timeout-minutes : 15
116181 - name : " 🏃Test with Gradle"
117- run : ./gradlew test -Ptarget.java.home="$JAVA_HOME_${{ matrix.java }}_X64"
182+ run : ./gradlew test -Pgroovy.grape.bridge-cache=true - Ptarget.java.home="$JAVA_HOME_${{ matrix.java }}_X64"
118183 timeout-minutes : 60
0 commit comments