From 1c4ca9082ab7b6420f936ebf399162b8201e402e Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 20 Mar 2026 15:47:05 -0500 Subject: [PATCH 1/3] [build] Cache Gradle downloads between CI runs Add a shared `cache-gradle.yaml` template using the Cache@2 task to persist `~/.gradle/caches` between pipeline runs. This prevents transient DNS/network failures from breaking builds when resolving Maven Central dependencies (e.g. javaparser for java-source-utils). The cache key includes `Agent.OS`, `gradle-wrapper.properties`, and all `build.gradle` files, so it auto-invalidates on Gradle version or dependency changes. Used by all three build step templates (macOS, Linux, Windows) which covers Xamarin.Android, Xamarin.Android-PR, and dnceng-public pipelines. Context: https://learn.microsoft.com/azure/devops/pipelines/release/caching Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../yaml-templates/build-linux-steps.yaml | 4 ++++ .../yaml-templates/build-macos-steps.yaml | 4 ++++ .../yaml-templates/build-windows-steps.yaml | 4 ++++ .../automation/yaml-templates/cache-gradle.yaml | 17 +++++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 build-tools/automation/yaml-templates/cache-gradle.yaml diff --git a/build-tools/automation/yaml-templates/build-linux-steps.yaml b/build-tools/automation/yaml-templates/build-linux-steps.yaml index bdc9c6a65c0..448999622c0 100644 --- a/build-tools/automation/yaml-templates/build-linux-steps.yaml +++ b/build-tools/automation/yaml-templates/build-linux-steps.yaml @@ -27,6 +27,10 @@ steps: - template: /build-tools/automation/yaml-templates/log-disk-space.yaml +- template: /build-tools/automation/yaml-templates/cache-gradle.yaml + parameters: + xaSourcePath: ${{ parameters.xaSourcePath }} + - script: make jenkins PREPARE_CI=1 PREPARE_AUTOPROVISION=1 CONFIGURATION=$(XA.Build.Configuration) MSBUILD_ARGS='${{ parameters.makeMSBuildArgs }}' workingDirectory: ${{ parameters.xaSourcePath }} displayName: make jenkins diff --git a/build-tools/automation/yaml-templates/build-macos-steps.yaml b/build-tools/automation/yaml-templates/build-macos-steps.yaml index f9d207ec43f..5c0af7a6ffe 100644 --- a/build-tools/automation/yaml-templates/build-macos-steps.yaml +++ b/build-tools/automation/yaml-templates/build-macos-steps.yaml @@ -30,6 +30,10 @@ steps: - template: /build-tools/automation/yaml-templates/log-disk-space.yaml +- template: /build-tools/automation/yaml-templates/cache-gradle.yaml + parameters: + xaSourcePath: ${{ parameters.xaSourcePath }} + # Prepare and Build everything - script: make jenkins CONFIGURATION=$(XA.Build.Configuration) PREPARE_CI=1 PREPARE_AUTOPROVISION=1 MSBUILD_ARGS='${{ parameters.makeMSBuildArgs }}' workingDirectory: ${{ parameters.xaSourcePath }} diff --git a/build-tools/automation/yaml-templates/build-windows-steps.yaml b/build-tools/automation/yaml-templates/build-windows-steps.yaml index 2227e7ae8fc..c8651b02d76 100644 --- a/build-tools/automation/yaml-templates/build-windows-steps.yaml +++ b/build-tools/automation/yaml-templates/build-windows-steps.yaml @@ -23,6 +23,10 @@ steps: parameters: remove_dotnet: true +- template: /build-tools/automation/yaml-templates/cache-gradle.yaml + parameters: + xaSourcePath: $(System.DefaultWorkingDirectory) + - task: DotNetCoreCLI@2 displayName: Prepare Solution inputs: diff --git a/build-tools/automation/yaml-templates/cache-gradle.yaml b/build-tools/automation/yaml-templates/cache-gradle.yaml new file mode 100644 index 00000000000..f92bd989b7c --- /dev/null +++ b/build-tools/automation/yaml-templates/cache-gradle.yaml @@ -0,0 +1,17 @@ +# Shared Gradle dependency cache template +# Caches Gradle downloads between pipeline runs to avoid transient network +# failures when resolving Maven dependencies. +# +# See: https://learn.microsoft.com/azure/devops/pipelines/release/caching + +parameters: + xaSourcePath: $(System.DefaultWorkingDirectory)/android + +steps: +- task: Cache@2 + displayName: cache Gradle downloads + inputs: + key: '"gradle" | "v1" | "$(Agent.OS)" | ${{ parameters.xaSourcePath }}/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/src/**/build.gradle | ${{ parameters.xaSourcePath }}/external/Java.Interop/**/build.gradle' + restoreKeys: | + "gradle" | "v1" | "$(Agent.OS)" + path: $(HOME)/.gradle/caches From abc1a0ea60b7ebb8115bb733f7dd30ea80a1bd74 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 20 Mar 2026 16:29:47 -0500 Subject: [PATCH 2/3] [build] Remove Java.Interop paths from Gradle cache key The external/Java.Interop submodule is not checked out when the cache step runs (submodules are initialized later during make jenkins). Use only the main repo gradle-wrapper.properties and build.gradle files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- build-tools/automation/yaml-templates/cache-gradle.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-tools/automation/yaml-templates/cache-gradle.yaml b/build-tools/automation/yaml-templates/cache-gradle.yaml index f92bd989b7c..aa0c4f7a973 100644 --- a/build-tools/automation/yaml-templates/cache-gradle.yaml +++ b/build-tools/automation/yaml-templates/cache-gradle.yaml @@ -11,7 +11,7 @@ steps: - task: Cache@2 displayName: cache Gradle downloads inputs: - key: '"gradle" | "v1" | "$(Agent.OS)" | ${{ parameters.xaSourcePath }}/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/external/Java.Interop/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/src/**/build.gradle | ${{ parameters.xaSourcePath }}/external/Java.Interop/**/build.gradle' + key: '"gradle" | "v1" | "$(Agent.OS)" | ${{ parameters.xaSourcePath }}/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/src/**/build.gradle' restoreKeys: | "gradle" | "v1" | "$(Agent.OS)" path: $(HOME)/.gradle/caches From 1f347868a3c77b3e8574b112a071f28a88e6fea3 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 20 Mar 2026 16:30:31 -0500 Subject: [PATCH 3/3] [build] Use Java.Interop submodule hash in Gradle cache key Write the submodule commit hash to a temp file before the cache step so the cache invalidates when Java.Interop is bumped (which may change its build.gradle dependencies). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- build-tools/automation/yaml-templates/cache-gradle.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build-tools/automation/yaml-templates/cache-gradle.yaml b/build-tools/automation/yaml-templates/cache-gradle.yaml index aa0c4f7a973..289f2d307b2 100644 --- a/build-tools/automation/yaml-templates/cache-gradle.yaml +++ b/build-tools/automation/yaml-templates/cache-gradle.yaml @@ -8,10 +8,14 @@ parameters: xaSourcePath: $(System.DefaultWorkingDirectory)/android steps: +- script: git submodule status --cached external/Java.Interop > $(Agent.TempDirectory)/java-interop-submodule-hash.txt + workingDirectory: ${{ parameters.xaSourcePath }} + displayName: get Java.Interop submodule hash + - task: Cache@2 displayName: cache Gradle downloads inputs: - key: '"gradle" | "v1" | "$(Agent.OS)" | ${{ parameters.xaSourcePath }}/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/src/**/build.gradle' + key: '"gradle" | "v1" | "$(Agent.OS)" | ${{ parameters.xaSourcePath }}/build-tools/gradle/gradle/wrapper/gradle-wrapper.properties | ${{ parameters.xaSourcePath }}/src/**/build.gradle | $(Agent.TempDirectory)/java-interop-submodule-hash.txt' restoreKeys: | "gradle" | "v1" | "$(Agent.OS)" path: $(HOME)/.gradle/caches