From 81edc40ce9f1df7b41e38912c09867ceb126979c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 9 Nov 2026 22:48:47 +0000 Subject: [PATCH 1/2] Cache the pinned Gradle zip for e2e legs Both install-gradle.sh origins are served by github.com releases (services.gradle.org redirects there). On 2026-11-09 05:43-05:47 UTC release downloads returned 504 for longer than curl's ~30 s of retries, and 9 gradle legs of the nightly failed in the install step (run 42568829044). The 9.8.0 legs run on every PR and in the merge queue, where the same window would evict the entry. Restore gradle--bin.zip from the actions cache before the install step and save it from main on a miss, as #2039 does for vexctl. install-gradle.sh now uses a zip already in place when it matches the pinned sha256, and deletes and re-downloads one that does not. gradle-compatibility.yml restores the same keys and its nightly saves the macOS and Windows zips ci.yml never fetches. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_011f9aeT4udaLUf9uZoDNXAx --- .github/workflows/ci.yml | 31 ++++++++++++++++ .github/workflows/gradle-compatibility.yml | 23 ++++++++++++ scripts/install-gradle.sh | 41 +++++++++++++++------- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60cef3186..c2e61d75c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1847,6 +1847,24 @@ jobs: if [ "$RUNNER_OS" = Windows ]; then launcher="${launcher}.cmd"; fi echo "SOCKET_PATCH_MAVEN_E2E_MVN=$launcher" >> "$GITHUB_ENV" + - name: Restore the Gradle ${{ matrix.gradle }} distribution + # Both of install-gradle.sh's origins are served by github.com + # releases (services.gradle.org redirects there). On 2026-11-09 + # those returned 504 for minutes at a time, longer than curl's + # ~30 s of retries, and failed 9 gradle legs of the nightly (run + # 42568829044); the 9.8.0 legs run in the merge queue too. The zip + # is pinned by sha256, which the script checks on a restored copy + # as well, so cache it per version. Saved from main only. + id: gradle-dist-cache + if: matrix.gradle != '' + uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 + # A miss only means downloading the zip. + timeout-minutes: 5 + continue-on-error: true + with: + path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip + key: gradle-dist-${{ matrix.gradle }}-${{ runner.os }} + - name: Install Gradle ${{ matrix.gradle }} if: matrix.gradle != '' shell: bash @@ -1855,6 +1873,19 @@ jobs: # Pinned digest, GitHub-release origin: see the script. run: scripts/install-gradle.sh "$GRADLE_VERSION" "$RUNNER_TEMP" >> "$GITHUB_ENV" + - name: Save the Gradle ${{ matrix.gradle }} distribution + if: >- + matrix.gradle != '' + && github.ref == 'refs/heads/main' + && steps.gradle-dist-cache.outputs.cache-hit != 'true' + && steps.gradle-dist-cache.outcome == 'success' + uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 + # Several legs share a version: the first save of a key wins and + # the others only log a warning, as the action does for any taken key. + with: + path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip + key: ${{ steps.gradle-dist-cache.outputs.cache-primary-key }} + - name: Setup .NET SDK if: matrix.dotnet != '' # Installs next to the runner's preinstalled SDKs; the suite writes diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index a3a555035..fc709a252 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -345,6 +345,18 @@ jobs: echo "SOCKET_PATCH_MAVEN_E2E_REQUIRED=1" } >> "$GITHUB_ENV" + - name: Restore the Gradle ${{ matrix.gradle }} distribution + # ci.yml's e2e legs save this pinned zip from main; restoring it + # keeps a github.com release outage from failing these legs. See + # the matching step there. + id: gradle-dist-cache + uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 + timeout-minutes: 5 + continue-on-error: true + with: + path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip + key: gradle-dist-${{ matrix.gradle }}-${{ runner.os }} + - name: Install Gradle ${{ matrix.gradle }} shell: bash env: @@ -352,6 +364,17 @@ jobs: # Pinned digest, GitHub-release origin: see the script. run: scripts/install-gradle.sh "$GRADLE_VERSION" "$RUNNER_TEMP" >> "$GITHUB_ENV" + - name: Save the Gradle ${{ matrix.gradle }} distribution + # The nightly saves the macOS and Windows zips ci.yml never fetches. + if: >- + github.ref == 'refs/heads/main' + && steps.gradle-dist-cache.outputs.cache-hit != 'true' + && steps.gradle-dist-cache.outcome == 'success' + uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 + with: + path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip + key: ${{ steps.gradle-dist-cache.outputs.cache-primary-key }} + - name: Run the ${{ matrix.mode }} suites shell: bash env: diff --git a/scripts/install-gradle.sh b/scripts/install-gradle.sh index d0285d180..47d4945ba 100755 --- a/scripts/install-gradle.sh +++ b/scripts/install-gradle.sh @@ -9,7 +9,9 @@ # alone answering HTTP 500 for ~30 s used to fail a merge-queue leg. It is # only tried after the release download fails. The sha256 is pinned below # (from https://gradle.org/release-checksums/), so no checksum fetch can fail -# either; a version without a pin fails closed. +# either; a version without a pin fails closed. A zip already at +# /gradle--bin.zip (CI restores one from the actions cache) +# is used without any download when it matches that pin. # # Prints (stdout): # SOCKET_PATCH_GRADLE_E2E_GRADLE= @@ -36,25 +38,40 @@ esac mkdir -p "$DIR" zip="$DIR/gradle-$VERSION-bin.zip" file="gradle-$VERSION-bin.zip" + +# python, not sha256sum: the macOS runners have only shasum. +verify() { + python -c 'import hashlib, sys; d = hashlib.sha256(open(sys.argv[1], "rb").read()).hexdigest(); sys.exit(0 if d == sys.argv[2] else "sha256 mismatch: got " + d)' "$zip" "$sha" +} + fetched="" -# --ssl-revoke-best-effort: Windows curl (schannel) otherwise fails when the -# CA's revocation endpoint is unreachable. -for url in \ - "https://github.com/gradle/gradle-distributions/releases/download/v$VERSION/$file" \ - "https://services.gradle.org/distributions/$file"; do - if curl -fsSL --retry 5 --retry-all-errors --ssl-revoke-best-effort "$url" -o "$zip"; then +if [ -f "$zip" ]; then + if verify; then + echo "install-gradle.sh: using the cached $file" >&2 fetched=1 - break + else + rm -f "$zip" fi - echo "install-gradle.sh: download from $url failed" >&2 -done +fi +# --ssl-revoke-best-effort: Windows curl (schannel) otherwise fails when the +# CA's revocation endpoint is unreachable. +if [ -z "$fetched" ]; then + for url in \ + "https://github.com/gradle/gradle-distributions/releases/download/v$VERSION/$file" \ + "https://services.gradle.org/distributions/$file"; do + if curl -fsSL --retry 5 --retry-all-errors --ssl-revoke-best-effort "$url" -o "$zip"; then + fetched=1 + break + fi + echo "install-gradle.sh: download from $url failed" >&2 + done +fi if [ -z "$fetched" ]; then echo "install-gradle.sh: every origin failed for Gradle $VERSION" >&2 exit 1 fi -# python, not sha256sum: the macOS runners have only shasum. -python -c 'import hashlib, sys; d = hashlib.sha256(open(sys.argv[1], "rb").read()).hexdigest(); sys.exit(0 if d == sys.argv[2] else "sha256 mismatch: got " + d)' "$zip" "$sha" +verify unzip -q "$zip" -d "$DIR" launcher="$DIR/gradle-$VERSION/bin/gradle" case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) launcher="$launcher.bat" ;; esac From dc6dd8e4ecebc3ea4ce43718f51b7e5bb6e2a350 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 9 Nov 2026 22:51:35 +0000 Subject: [PATCH 2/2] Key the Gradle cache on the pins, restore-only compat Address review: include a hash of install-gradle.sh (which holds the sha256 pins) in the cache key so a fixed pin saves a fresh entry; let gradle-compatibility.yml only restore, keeping ~1 GB of per-OS zips out of the repo cache; print the whole usage header; and unzip with -o so a second run into the same directory reuses the cached zip. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_011f9aeT4udaLUf9uZoDNXAx --- .github/workflows/ci.yml | 3 ++- .github/workflows/gradle-compatibility.yml | 22 ++++++---------------- scripts/install-gradle.sh | 4 ++-- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2e61d75c..d9e8812f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1863,7 +1863,8 @@ jobs: continue-on-error: true with: path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip - key: gradle-dist-${{ matrix.gradle }}-${{ runner.os }} + # The script holds the pins: a changed pin starts a fresh key. + key: gradle-dist-${{ matrix.gradle }}-${{ runner.os }}-${{ hashFiles('scripts/install-gradle.sh') }} - name: Install Gradle ${{ matrix.gradle }} if: matrix.gradle != '' diff --git a/.github/workflows/gradle-compatibility.yml b/.github/workflows/gradle-compatibility.yml index fc709a252..98a85e546 100644 --- a/.github/workflows/gradle-compatibility.yml +++ b/.github/workflows/gradle-compatibility.yml @@ -346,16 +346,17 @@ jobs: } >> "$GITHUB_ENV" - name: Restore the Gradle ${{ matrix.gradle }} distribution - # ci.yml's e2e legs save this pinned zip from main; restoring it - # keeps a github.com release outage from failing these legs. See - # the matching step there. - id: gradle-dist-cache + # ci.yml's e2e legs save this pinned zip from main (every version + # on Linux, 8.14.3 on Windows); restoring it keeps a github.com + # release outage from failing these legs. See the matching step + # there. Restore only: saving every OS x version here would add + # ~1 GB of near-duplicate zips to the repo's cache. uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 timeout-minutes: 5 continue-on-error: true with: path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip - key: gradle-dist-${{ matrix.gradle }}-${{ runner.os }} + key: gradle-dist-${{ matrix.gradle }}-${{ runner.os }}-${{ hashFiles('scripts/install-gradle.sh') }} - name: Install Gradle ${{ matrix.gradle }} shell: bash @@ -364,17 +365,6 @@ jobs: # Pinned digest, GitHub-release origin: see the script. run: scripts/install-gradle.sh "$GRADLE_VERSION" "$RUNNER_TEMP" >> "$GITHUB_ENV" - - name: Save the Gradle ${{ matrix.gradle }} distribution - # The nightly saves the macOS and Windows zips ci.yml never fetches. - if: >- - github.ref == 'refs/heads/main' - && steps.gradle-dist-cache.outputs.cache-hit != 'true' - && steps.gradle-dist-cache.outcome == 'success' - uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 - with: - path: ${{ runner.temp }}/gradle-${{ matrix.gradle }}-bin.zip - key: ${{ steps.gradle-dist-cache.outputs.cache-primary-key }} - - name: Run the ${{ matrix.mode }} suites shell: bash env: diff --git a/scripts/install-gradle.sh b/scripts/install-gradle.sh index 47d4945ba..0dfc44bed 100755 --- a/scripts/install-gradle.sh +++ b/scripts/install-gradle.sh @@ -18,7 +18,7 @@ set -euo pipefail if [ $# -ne 2 ]; then - sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//' >&2 + sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//' >&2 exit 2 fi VERSION="$1" @@ -72,7 +72,7 @@ if [ -z "$fetched" ]; then fi verify -unzip -q "$zip" -d "$DIR" +unzip -oq "$zip" -d "$DIR" launcher="$DIR/gradle-$VERSION/bin/gradle" case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) launcher="$launcher.bat" ;; esac echo "SOCKET_PATCH_GRADLE_E2E_GRADLE=$launcher"