Centralize Gradle Maven repositories via shared eng/gradle/repositories.gradle#11711
Conversation
All Gradle projects in this repo (manifestmerger, r8, proguard-android) now resolve Maven dependencies through a single dnceng Azure Artifacts feed (dotnet-public-maven), which proxies Maven Central, Google Maven, and the Gradle Plugin Portal. Repository configuration is centralized in eng/gradle/repositories.gradle (a gradle.ext.dotnetPublicMaven closure) and applied from each build.gradle. Each settings.gradle inlines pluginManagement + the com.microsoft.azure.artifacts.credprovider plugin (Gradle disallows pluginManagement/plugins blocks in applied scripts, so the contents must be duplicated). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refactor eng/gradle/repositories.gradle to conditionally point at the dnceng dotnet-public-maven feed only when RunningOnCI=true (Azure DevOps CI). Locally and from GitHub Actions / Dependabot, standard public repos (google, mavenCentral, gradlePluginPortal) are used so contributors and Dependabot need no feed credentials. CI reads the feed anonymously; new packages are pre-ingested on a maintainer's machine by setting RunningOnCI=true locally and letting the artifacts-credprovider Gradle plugin authenticate. Detailed workflow and testing instructions are inline in eng/gradle/repositories.gradle. Add .github/instructions/gradle.instructions.md (scoped to **/*.gradle) so the conventions are surfaced to Copilot when editing Gradle files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR centralizes Gradle repository configuration for the repo’s src/* Gradle builds by introducing a shared eng/gradle/repositories.gradle, enabling Azure DevOps CFSClean-friendly Maven resolution via the dotnet-public-maven feed while keeping local/Dependabot builds working against public repos.
Changes:
- Added
eng/gradle/repositories.gradleand switched repositories based onRunningOnCI. - Updated each
src/*/settings.gradleto apply the shared repositories to bothpluginManagementanddependencyResolutionManagement, and added the Azure Artifacts credprovider plugin. - Removed per-project
repositories {}blocks frombuild.gradlefiles; added Gradle-editing guidance via.github/instructions/gradle.instructions.md.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/r8/settings.gradle |
Adds shared repo wiring for plugin + dependency resolution and credprovider plugin declaration. |
src/r8/build.gradle |
Removes ad-hoc repositories to rely on centralized settings-based resolution. |
src/proguard-android/settings.gradle |
Replaces inline plugin repos with shared repository script and adds dependencyResolutionManagement. |
src/proguard-android/build.gradle |
Removes ad-hoc repositories to rely on centralized settings-based resolution. |
src/manifestmerger/settings.gradle |
Adds shared repo wiring for plugin + dependency resolution and credprovider plugin declaration. |
src/manifestmerger/build.gradle |
Removes hard-coded/mixed repositories (incl. legacy ones) in favor of centralized config. |
eng/gradle/repositories.gradle |
Introduces the shared repository list and CI-vs-local switching logic. |
.github/instructions/gradle.instructions.md |
Documents the centralized repository pattern for future Gradle edits. |
AzDO uppercases pipeline variables when exporting them as environment variables on Linux/macOS agents, so System.getenv('RunningOnCI') returns null there. Check both spellings.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Code Review — ⚠️ Minor suggestions (non-blocking)
Solid, well-documented build-plumbing change. Centralizing the Maven repo list into eng/gradle/repositories.gradle and applying it to both pluginManagement and dependencyResolutionManagement is the established dotnet/maui pattern and works on this repo's Gradle 8.12. I formed an independent read of the diff first, then verified the PR's claims:
Verified ✅
RunningOnCIreally is exported bybuild-tools/automation/yaml-templates/variables.yaml, and theSystem.getenv('RunningOnCI') ?: System.getenv('RUNNINGONCI')+== 'true'check correctly mirrors the hard-won lesson already encoded inCodeBehindTests.cs— AzDO uppercases the env var toRUNNINGONCIon Linux/macOS agents while the value stays lowercasetrue. Good defensive handling of both spellings.- Dependabot still covers all three projects (
/src/r8,/src/manifestmerger,/src/proguard-android) in.github/dependabot.yml. - Nice cleanup: the old
manifestmergerblock resolved from the long-deadjcenter()andkotlin.bintray.com/kotlinx— both correctly dropped here. - The
apply from "${rootDir}/../../eng/gradle/repositories.gradle"relative path is correct from eachsrc/<project>/location, and the credprovider plugin version is pinned (1.1.1), so Dependabot can bump it.
CI
- The Azure DevOps run (
buildId 1477428) is green across all legs (MSBuild, Emulator, Package, Linux, Windows Smoke, MAUI). A fresh re-run kicked off alongside this/review.mergeable_state: blockedreflects the pending required review (simonrozsival), not a CI failure.
Findings (see inline)
⚠️ 1 warning — the instruction glob**/*.gradleover-claims relative to thesrc/*-only migration: a CI-built test fixture (tests/CodeGen-Binding/.../JavaLib/build.gradle) still hard-codes public repos.- 💡 1 suggestion — the
AzureArtifactsfeed is also injected intodependencyResolutionManagement, where it only adds a 404 round-trip per project dependency.
Neither is merge-blocking. Nice work — this is a clean, future-proofing refactor.
Generated by Android PR Reviewer for issue #11711 · 929 AIC · ⌖ 48.2 AIC · ⊞ 37.8K
Comment /review to run again
| // Required even on the local path so the plugin is resolvable; harmless | ||
| // in dependencyResolutionManagement (it hosts no project dependencies). | ||
| maven { | ||
| url = 'https://pkgs.dev.azure.com/artifacts-public/PublicTools/_packaging/AzureArtifacts/maven/v1' |
There was a problem hiding this comment.
🤖 💡 Performance — This AzureArtifacts feed is declared first and unconditionally, so the shared script injects it into dependencyResolutionManagement too. It only hosts the artifacts-credprovider plugin, yet now every project-dependency lookup (manifest-merger, r8, and their transitives) queries it first and 404s before falling through to google()/mavenCentral() (or dotnet-public-maven in CI) — an extra round-trip per dependency on every build, including local and Dependabot. Since the credprovider is a plugin, consider scoping this feed to pluginManagement only. Functionally harmless (as the comment notes); this is purely an optimization.
Rule: Don't inject a repository into scopes that never resolve from it
There was a problem hiding this comment.
Confirmed and fixed. Split the shared file: eng/gradle/plugin-repositories.gradle still includes the AzureArtifacts feed (the credprovider plugin lives there), and the new eng/gradle/dependency-repositories.gradle omits it so project-dependency lookups skip that 404 round-trip. Each settings.gradle now applies the right file to each scope.
The AzureArtifacts public feed only hosts the artifacts-credprovider Gradle plugin, so listing it in dependencyResolutionManagement.repositories added a 404 round-trip to every project dependency lookup. Split the shared file in two: plugin-repositories.gradle (includes AzureArtifacts) and dependency-repositories.gradle (does not). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All Gradle projects in this repo (
src/manifestmerger,src/r8,src/proguard-android) previously declared their own ad-hoc mix ofmavenCentral(),google(),jcenter(), andkotlin.bintray.comrepositories. 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 dncengdotnet-public-mavenAzure Artifacts feed.Approach
A single shared file
eng/gradle/repositories.gradleis now the only place repository URLs are declared. Eachsettings.gradleapplies it twice viaapply from: ..., to: <block>to populate bothpluginManagement.repositoriesanddependencyResolutionManagement.repositories. Thebuild.gradlefiles no longer declare anyrepositories {}block.The shared file switches on
System.getenv('RunningOnCI'):RunningOnCI=true(set bybuild-tools/automation/yaml-templates/variables.yamlin our AzDO pipeline): the dncengdotnet-public-mavenfeed, plus the anonymous AzureArtifacts feed for the credprovider Gradle plugin.google()+mavenCentral()+gradlePluginPortal()so contributors and Dependabot need no credentials.Adapted from dotnet/maui (72cc860).
Dependabot workflow
This preserves Dependabot for the Gradle ecosystem (
/src/r8/,/src/manifestmerger/in.github/dependabot.yml):RunningOnCI=true. If the new version isn't cached in the dnceng feed yet, CI fails 401.$env:RunningOnCI='true'; ./build-tools/gradle/gradlew.bat --project-dir src/<project> buildlocally; the artifacts-credprovider plugin device-flow-logs-in once, the feed proxies + caches the package, and anonymous reads work from then on.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 (RunningOnCIset and unset) on Windows.proguard-android/build.gradlekeeps the modernplugins { id 'com.android.application' version '8.7.0' }DSL; AGP is resolvable from bothgradlePluginPortal()locally anddotnet-public-mavenin 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.gradlebecause Gradle disallows wrappingplugins {}inif (...). It is a no-op on the local path (no AzDO repos for it to authenticate).Useful description of why the change is necessary.
Links to issues fixed
Unit tests (N/A -- build-system plumbing only; verified by building all three Gradle projects through both code paths)