Repository navigation
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 <[email protected]>
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 <[email protected]>
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
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 <[email protected]>
|
/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 <[email protected]>
PR #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 #11711 - [x] Unit tests: Configured all four Gradle projects in local, anonymous CI, and authenticated mirror-helper modes.
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)