From 4377017e2b4eb619e3eb36b429db13aaeed4289e Mon Sep 17 00:00:00 2001 From: Vikrant Puppala Date: Mon, 29 Jun 2026 10:03:52 +0000 Subject: [PATCH 1/2] Explicitly resolve surefire-junit-platform in Maven cache warmer The warm-cache workflow pre-populates ~/.m2 so forked PRs can build in offline mode. It relied on its filtered test steps (4-6) to lazily pull the Surefire JUnit Platform provider (surefire-junit-platform), but those steps fail early with "No tests matching pattern" (no compiled test classes), masked by `|| true`. Surefire prints "No tests to run" and never loads the provider, so the jar is never cached. Forked PR jobs then fail in offline mode with: surefire-junit-platform:jar:3.1.2 (absent): Cannot access central ... in offline mode Add an explicit `dependency:get` for the provider so it is cached deterministically regardless of whether any filtered test run executes. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala --- .github/workflows/warmMavenCache.yml | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/.github/workflows/warmMavenCache.yml b/.github/workflows/warmMavenCache.yml index b21ee4073..46308fe82 100644 --- a/.github/workflows/warmMavenCache.yml +++ b/.github/workflows/warmMavenCache.yml @@ -143,30 +143,42 @@ jobs: # mirrors a real CI step from prCheck.yml, prIntegrationTests.yml, # or coverageReport.yml. - echo "=== 1/8: spotless:check (formatting-check job) ===" + echo "=== 1/9: spotless:check (formatting-check job) ===" mvn -B --errors spotless:check || true - echo "=== 2/8: install all modules (packaging-tests job) ===" + echo "=== 2/9: install all modules (packaging-tests job) ===" mvn -B -pl jdbc-core,assembly-uber,assembly-thin clean install -DskipTests -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Ddependency-check.skip=true - echo "=== 3/8: Arrow Patch Tests (unit-tests job, JDK 17+) ===" + echo "=== 3/9: Arrow Patch Tests (unit-tests job, JDK 17+) ===" mvn -B -Pjdk21-NioNotOpen -pl jdbc-core test -Dgroups='Jvm17PlusAndArrowToNioReflectionDisabled' -Ddependency-check.skip=true || true - echo "=== 4/8: Arrow Allocator Tests (unit-tests job, JDK 17+) ===" + echo "=== 4/9: Arrow Allocator Tests (unit-tests job, JDK 17+) ===" mvn -B -Pjdk21-NioNotOpen -pl jdbc-core test -Dgroups='Jvm17PlusAndArrowToNioReflectionDisabled' -Dtest="ArrowBufferAllocatorNettyManagerTest,ArrowBufferAllocatorUnsafeManagerTest,ArrowBufferAllocatorUnknownManagerTest" -DforkCount=1 -DreuseForks=false -Ddependency-check.skip=true || true - echo "=== 5/8: Arrow Memory Tests (unit-tests job) ===" + echo "=== 5/9: Arrow Memory Tests (unit-tests job) ===" mvn -B -Plow-memory -pl jdbc-core test -Dtest='DatabricksArrowPatchMemoryUsageTest' -Ddependency-check.skip=true || true - echo "=== 6/8: Unit Tests with jacoco (unit-tests job) ===" + echo "=== 6/9: Unit Tests with jacoco (unit-tests job) ===" mvn -B -pl jdbc-core clean test -Dtest="DatabricksParameterMetaDataTest#testInitialization" -Dgroups='!Jvm17PlusAndArrowToNioReflectionDisabled' jacoco:report -Ddependency-check.skip=true || true - echo "=== 7/8: Integration test compile (prIntegrationTests job) ===" + echo "=== 7/9: Integration test compile (prIntegrationTests job) ===" mvn -B -pl jdbc-core compile test-compile -Ddependency-check.skip=true || true - echo "=== 8/8: Resolve all declared plugins ===" + echo "=== 8/9: Resolve all declared plugins ===" mvn -B -pl jdbc-core dependency:resolve-plugins -Ddependency-check.skip=true || true + # The Surefire JUnit Platform provider (surefire-junit-platform) is + # resolved LAZILY by Surefire only when it actually executes tests + # against JUnit Platform. The filtered test runs above can fail before + # reaching that point (e.g. "No tests matching pattern"), so the + # provider never lands in the cache and offline PR jobs then fail with + # "surefire-junit-platform:jar:... (absent)". Resolve it explicitly. + echo "=== 9/9: Resolve Surefire JUnit Platform provider explicitly ===" + SUREFIRE_VERSION=$(mvn -B -pl jdbc-core help:evaluate \ + -Dexpression=maven-surefire-plugin.version -q -DforceStdout 2>/dev/null \ + || echo "3.1.2") + mvn -B dependency:get -Dartifact="org.apache.maven.surefire:surefire-junit-platform:${SUREFIRE_VERSION}" || true + echo "Dependency resolution complete" - name: Normalize _remote.repositories before saving cache From 5768b0614b8ece09dce6b1457895a7b468504e8c Mon Sep 17 00:00:00 2001 From: Vikrant Puppala Date: Mon, 29 Jun 2026 10:29:55 +0000 Subject: [PATCH 2/2] Fix Maven cache restore key so fork PRs get the warmed cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The warmer saved caches as maven-deps--, but consumers restore with exact key maven-deps- and fall back to the unscoped prefix restore-keys: maven-deps-. The timestamp segment means the exact key never matches, so restore always fell through to the prefix — which GitHub resolves to the most-recently-created maven-deps-* entry across ALL poms, frequently a main-branch cache that lacks fork-specific artifacts (and, before the prior commit, the surefire-junit-platform provider). Result: fork PRs restored the wrong cache and failed offline. Fix: - Warmer key layout -> maven-deps-- (hash first). - Consumer restore-keys -> maven-deps- (hash-scoped prefix), so the fallback only matches caches warmed for the same pom and picks the newest by timestamp. Requires a fresh warmer run after merge so caches are saved under the new key layout; old maven-deps-- entries no longer match and expire after 7 days. Co-authored-by: Isaac Signed-off-by: Vikrant Puppala --- .github/actions/setup-maven/action.yml | 8 ++++++-- .github/workflows/warmMavenCache.yml | 12 +++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/actions/setup-maven/action.yml b/.github/actions/setup-maven/action.yml index 7e302decc..2a109dd35 100644 --- a/.github/actions/setup-maven/action.yml +++ b/.github/actions/setup-maven/action.yml @@ -19,7 +19,10 @@ runs: with: path: ~/.m2/repository key: maven-deps-${{ hashFiles('**/pom.xml') }} - restore-keys: maven-deps- + # Scope the prefix fallback to this pom's hash so we never restore a + # cache warmed for a different pom (e.g. main). The warmer saves keys as + # maven-deps--, so this matches the newest such entry. + restore-keys: maven-deps-${{ hashFiles('**/pom.xml') }} - name: Configure Maven for cache-only resolution (fork) if: inputs.is-fork == 'true' @@ -109,4 +112,5 @@ runs: with: path: ~/.m2 key: maven-deps-${{ hashFiles('**/pom.xml') }} - restore-keys: maven-deps- + # Scope the prefix fallback to this pom's hash (see fork path above). + restore-keys: maven-deps-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/warmMavenCache.yml b/.github/workflows/warmMavenCache.yml index 46308fe82..7f06156d3 100644 --- a/.github/workflows/warmMavenCache.yml +++ b/.github/workflows/warmMavenCache.yml @@ -198,13 +198,15 @@ jobs: id: cache-key shell: bash run: | - # Include timestamp so each warmer run creates a new cache entry - # (GitHub Actions caches are immutable — can't overwrite existing keys). - # The restore step uses prefix 'maven-deps-' to match the latest entry. - # Old entries auto-expire after 7 days of no access. + # Key layout: maven-deps-- + # The pom hash comes FIRST so the consumer's hash-scoped restore-keys + # prefix (maven-deps-) matches only caches warmed for the + # same pom, and picks the newest by timestamp. The timestamp keeps each + # warmer run a distinct entry (GitHub Actions caches are immutable — + # keys can't be overwritten). Old entries auto-expire after 7 days. TIMESTAMP=$(date -u +%Y%m%d%H%M%S) POM_HASH=${{ hashFiles('**/pom.xml') }} - echo "key=maven-deps-${TIMESTAMP}-${POM_HASH}" >> $GITHUB_OUTPUT + echo "key=maven-deps-${POM_HASH}-${TIMESTAMP}" >> $GITHUB_OUTPUT - name: Save Maven dependency cache uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4