Skip to content

[release/10.0.1xx] Route Gradle dependencies through dotnet-public-maven - #12395

Closed
jonathanpeppers wants to merge 6 commits into
dotnet:release/10.0.1xxfrom
jonathanpeppers:jonathanpeppers-public-maven-backport
Closed

[release/10.0.1xx] Route Gradle dependencies through dotnet-public-maven#12395
jonathanpeppers wants to merge 6 commits into
dotnet:release/10.0.1xxfrom
jonathanpeppers:jonathanpeppers-public-maven-backport

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Summary

  • centralize Gradle plugin and dependency repositories under �ng/gradle`n- route CI and test Maven resolution through the anonymous dotnet-public-maven mirror
  • add the mirror-seeding helper and route XASdk/test artifacts through approved feeds
  • preserve the release branch's Gradle 8.12 and AGP 8.7 behavior

Backports #11711, #11717, #12055, #12199, and #12368.

Validation

  • RUNNINGONCI=true: src/r8 build passed
  • RUNNINGONCI=true: src/proguard-android extractProguardFiles passed
  • RUNNINGONCI=true: JavaLib �ssembleRelease passed with the configured Android SDK
  • all affected Gradle projects configured successfully through dotnet-public-mavenn- release-specific missing artifacts were seeded using �ng/gradle/mirror-dependencies.ps1n
    src/manifestmerger build retains its pre-existing Java 8 compatibility failure with manifest-merger:31.12.2; the same failure reproduces offline without mirror routing.

jonathanpeppers and others added 6 commits August 14, 2026 14:41
…es.gradle (dotnet#11711)

All Gradle projects in this repo (`src/manifestmerger`, `src/r8`, `src/proguard-android`) previously declared their own ad-hoc mix of `mavenCentral()`, `google()`, `jcenter()`, and `kotlin.bintray.com` repositories. That's a maintenance hazard and blocks any future CFSClean network-isolation work (see https://aka.ms/1es/netiso/CFS), which requires all Maven dependencies to flow through the dnceng `dotnet-public-maven` Azure Artifacts feed.

## Approach

A single shared file `eng/gradle/repositories.gradle` is now the only place repository URLs are declared. Each `settings.gradle` applies it twice via `apply from: ..., to: <block>` to populate both `pluginManagement.repositories` and `dependencyResolutionManagement.repositories`. The `build.gradle` files no longer declare any `repositories {}` block.

The shared file switches on `System.getenv('RunningOnCI')`:
- **`RunningOnCI=true`** (set by `build-tools/automation/yaml-templates/variables.yaml` in our AzDO pipeline): the dnceng `dotnet-public-maven` feed, plus the anonymous AzureArtifacts feed for the credprovider Gradle plugin.
- **unset** (local builds, Dependabot, GitHub Actions): `google()` + `mavenCentral()` + `gradlePluginPortal()` so contributors and Dependabot need no credentials.

Adapted from dotnet/maui ([72cc860](dotnet/maui@72cc860)).

## Dependabot workflow

This preserves Dependabot for the Gradle ecosystem (`/src/r8/`, `/src/manifestmerger/` in `.github/dependabot.yml`):
1. Dependabot opens a PR against public repos -> sees the latest upstream version.
2. CI runs with `RunningOnCI=true`. If the new version isn't cached in the dnceng feed yet, CI fails 401.
3. A maintainer runs `$env:RunningOnCI='true'; ./build-tools/gradle/gradlew.bat --project-dir src/<project> build` locally; the artifacts-credprovider plugin device-flow-logs-in once, the feed proxies + caches the package, and anonymous reads work from then on.
4. Re-run CI -> green. No PR edit required.

CI itself reads the feed **anonymously** -- no PAT secret or pipeline auth setup is required.

## Notes for reviewers

- All three projects (`manifestmerger`, `r8`, `proguard-android`) were verified to build through both code paths (`RunningOnCI` set and unset) on Windows.
- `proguard-android/build.gradle` keeps the modern `plugins { id 'com.android.application' version '8.7.0' }` DSL; AGP is resolvable from both `gradlePluginPortal()` locally and `dotnet-public-maven` in CI.
- `.github/instructions/gradle.instructions.md` (scoped via frontmatter to `**/*.gradle`) documents the pattern so Copilot picks it up when editing Gradle files.
- The credprovider plugin is declared unconditionally in each `settings.gradle` because Gradle disallows wrapping `plugins {}` in `if (...)`. It is a no-op on the local path (no AzDO repos for it to authenticate).
…roid (dotnet#11717)

Bumps com.android.application from 8.7.0 to 9.2.1.

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.android.application&package-manager=gradle&previous-version=8.7.0&new-version=9.2.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

</details>
PR dotnet#11711 centralized Gradle repository configuration, but applying the Azure Artifacts credential provider during ordinary builds caused authentication dialogs for local developers. CI does not need that provider because it reads packages already cached in `dotnet-public-maven` anonymously.

This keeps repository selection and authentication as separate controls:

- `RUNNINGONCI=true` selects `dotnet-public-maven` for Azure DevOps builds.
- `ANDROID_MIRROR_MAVEN_DEPENDENCIES=true` loads the credential provider only while `mirror-dependencies.ps1` seeds uncached packages.
- Local builds use Google, Maven Central, and the Gradle Plugin Portal without loading Azure authentication code.

The credential provider is loaded through an applied script so it can be gated dynamically. Gradle cannot resolve a plugin by ID from that script's isolated `buildscript` classpath, so this context requires its implementation class.

- [x] Useful description of *why the change is necessary*.
- [x] Links to issues fixed: Follow-up to dotnet#11711
- [x] Unit tests: Configured all four Gradle projects in local, anonymous CI, and authenticated mirror-helper modes.
…otnet#12199)

CFSClean reports test jobs that resolve Maven dependencies and Gradle plugins directly from public services. CI agents are network-isolated and can only reach the anonymous `dotnet-public-maven` Azure Artifacts feed, which mirrors both Maven Central and Google Maven.

This routes every test Maven and Gradle resolution through that feed. Crucially, it does so **unconditionally** rather than only when `RUNNINGONCI` is set — a CI-only code path means a local run exercises different URLs than CI, so a test can pass locally and then fail in the pipeline. Making local and CI identical is the same principle applied to the mirror-seeding tool below.

- `Xamarin.ProjectTools` exposes a single `TestEnvironment.DotNetPublicMaven` constant. Test download URLs and `<AndroidMavenLibrary Repository="...">` metadata are built from it directly, replacing the old `GetTestDownloadUrl`/`GetMavenRepository` helpers and their table of public-repository prefixes. A missing prefix in that table used to fail silently on CI only.
- `AndroidGradleProject` writes a `settings.gradle.kts` that applies the shared `eng/gradle` repository scripts, and copies the repository Gradle wrapper instead of downloading an alternate distribution.
- Java.Interop `java-source-utils` no longer declares `mavenCentral()` independently, and parallel Kotlin Gradle builds are isolated so they don't race.

`eng/gradle/mirror-dependencies.ps1` now runs Gradle exactly the way CI does — anonymously, with the configuration cache enabled — instead of loading an Azure Artifacts credential-provider plugin behind an env var. That plugin forced the seeding run to differ from the real run, so lazily-resolved Kotlin and lint classpaths resolved differently and the feed was seeded with the wrong packages. Authentication moved out of Gradle entirely: 401 URLs are re-fetched over plain HTTP with an Azure DevOps OAuth token, which makes the feed's upstream connector cache them for anonymous reads. `eng/gradle/credential-provider.gradle` is removed. A `-MavenArtifact` mode seeds coordinates directly for tests that don't use Gradle.

- `TestEnvironment.IsWindows`/`IsMacOS`/`IsLinux` are annotated `[SupportedOSPlatformGuard]` so CA1416 can see through them. The properties were always correct at runtime; the analyzer just couldn't recognize an arbitrary `bool` as a platform guard. Annotating the shared helper fixes every current and future caller instead of rewriting call sites.
- `Xamarin.Google.Android.InstallReferrer` is bumped to 2.2.0.8 to match Facebook SDK 18.3.0, which requires `com.android.installreferrer:2.2`.

- Built `Xamarin.ProjectTools`, `Xamarin.Android.Build.Tests`, and `MSBuildDeviceIntegration` — 0 errors.
- All 17 `MavenDownloadTests` pass locally, including the three that download through the mirror. Because the mirror is now used locally too, this exercises the same URLs CI does.
- Verified every artifact referenced by a test resolves on the feed (`HEAD` → 200), so nothing 401s on CI.
- Routing all downloads through a repository URL would leave the `Repository="Central"`/`"Google"` shorthands unexercised, so that mapping is extracted to `MavenDownload.GetKnownRepository` and covered by new tests that need no network and therefore run under CI isolation.
- Passed 106 Java.Interop Maven tests; `java-source-utils` resolves through the feed.
- `GradleFBProj` passes on device after the InstallReferrer bump.
- Full pipeline green apart from the pre-existing, unrelated `JnienvArrayMarshaling.GetObjectArray` JNI peer-registration flake.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The original Kotlin artifact is now mirrored through dotnet-public-maven, so keep the existing package while routing it through the approved feed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep the release branch on its existing Gradle 8.12 wrapper and AGP 8.7 while retaining the public Maven repository routing from the backported mirror series.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 14, 2026 20:16
@jonathanpeppers

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
1 pipeline(s) were filtered out due to trigger conditions.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Routes Gradle plugin/dependency resolution (and test Maven/Gradle downloads) through the anonymous dotnet-public-maven mirror to satisfy CI network isolation requirements, while keeping local builds on public repositories.

Changes:

  • Centralize Gradle pluginManagement/dependencyResolutionManagement repositories via eng/gradle/*.gradle and update Gradle subprojects to consume them.
  • Route test-time Maven downloads and <AndroidMavenLibrary Repository=...> metadata through TestEnvironment.DotNetPublicMaven.
  • Add eng/gradle/mirror-dependencies.ps1 helper for seeding missing artifacts into the mirror and adjust test Gradle project plumbing (wrapper usage / stable artifact paths).

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs Bump Facebook SDK version and route related Maven libraries through the mirror in device integration tests.
tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/Xamarin.Android.LibraryProjectZip-LibBinding.csproj Update binding input JAR path to a stable location not tied to AGP intermediates.
tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/java/JavaLib/settings.gradle Apply shared repository scripts for plugin/dependency resolution.
tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/java/JavaLib/library/src/main/AndroidManifest.xml Remove manifest package in favor of Gradle namespace.
tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/java/JavaLib/library/build.gradle Modernize Android library module config and add task to extract classes.jar to a stable path.
tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/java/JavaLib/build.gradle Switch to plugins DSL and adjust clean task for newer Gradle/AGP behavior.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/TestEnvironment.cs Add DotNetPublicMaven constant, platform guard attributes, and IsRunningOnCI helper.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/AndroidGradleProject.cs Generate settings.gradle.kts applying shared repo scripts and copy the repo Gradle wrapper into generated projects.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs Route test web downloads and Maven library metadata through DotNetPublicMaven.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs Adjust tests for mirror behavior, add coverage for repository shorthand mapping, and harden null handling.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs Route AAR downloads through DotNetPublicMaven.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildWithLibraryTests.cs Route AAR downloads through DotNetPublicMaven.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs Route AAR downloads through DotNetPublicMaven.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs Route Maven Central/Google Maven downloads through DotNetPublicMaven.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs Route binding test downloads and <AndroidMavenLibrary> repository metadata through DotNetPublicMaven.
src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidGradleProjectTests.cs Pin Facebook SDK version to a specific release for test stability.
src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs Factor repository-shorthand mapping into GetKnownRepository and reuse in repository resolution.
src/r8/settings.gradle Apply shared repository scripts for plugin/dependency resolution.
src/r8/build.gradle Remove per-project repositories block in favor of centralized settings.gradle configuration.
src/proguard-android/settings.gradle Apply shared repository scripts for plugin/dependency resolution.
src/proguard-android/build.gradle Remove per-project repositories block in favor of centralized settings.gradle configuration.
src/manifestmerger/settings.gradle Apply shared repository scripts for plugin/dependency resolution.
src/manifestmerger/build.gradle Remove per-project repositories block in favor of centralized settings.gradle configuration.
eng/gradle/plugin-repositories.gradle New shared plugin repository list switching on RUNNINGONCI.
eng/gradle/dependency-repositories.gradle New shared dependency repository list switching on RUNNINGONCI.
eng/gradle/mirror-dependencies.ps1 New script to seed missing Gradle/Maven artifacts into the mirror via authenticated refetch.
.github/instructions/gradle.instructions.md Document the centralized Gradle repo pattern and mirror-seeding workflow.
.github/dependabot.yml Consolidate Gradle Dependabot coverage to include additional Gradle projects/directories.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread eng/gradle/plugin-repositories.gradle
Comment thread eng/gradle/dependency-repositories.gradle
@jonathanpeppers

Copy link
Copy Markdown
Member Author

Superseded by #12397, which uses a branch hosted directly in dotnet/android.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants