Skip to content

Commit 94bc715

Browse files
Bump com.android.application from 8.7.0 to 9.2.1 in /src/proguard-android (#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>
1 parent 63cae52 commit 94bc715

11 files changed

Lines changed: 205 additions & 64 deletions

File tree

.github/dependabot.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ updates:
4545
- "/src/r8"
4646
- "/src/manifestmerger"
4747
- "/src/proguard-android"
48+
- "/tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/java/JavaLib"
4849
schedule:
4950
interval: "weekly"
5051
- package-ecosystem: "gitsubmodule"

.github/instructions/gradle.instructions.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,22 @@ Test the CI path locally: `$env:RunningOnCI='true'` (PowerShell) or `RunningOnCI
3434

3535
## When CI fails 401 on a Dependabot bump
3636

37-
The new package isn't cached in the feed yet. One-time setup, then ingest:
37+
The new package isn't cached in the dnceng `dotnet-public-maven` feed yet. CI agents only do anonymous reads, so someone has to authenticate once locally to make the feed pull the package (and its transitive deps) from upstream.
3838

39-
1. `iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) }"` (or the `.sh` equivalent)
40-
2. `$env:RunningOnCI='true'; ./build-tools/gradle/gradlew.bat --project-dir src/<project> build` — sign in via the device-flow prompt; the feed proxies + caches the package.
41-
3. Re-run CI on the Dependabot PR. No PR edit needed.
39+
Use the helper script — it runs the build, parses any 401 URLs out of the log, re-fetches each one with an Azure DevOps bearer token (so the feed mirrors it), and loops until the build succeeds:
4240

43-
The credprovider plugin is a no-op when no AzDO repos are configured (i.e. local builds without `RunningOnCI`).
41+
```powershell
42+
az login # one-time, corp account with MFA satisfied
43+
44+
pwsh ./eng/gradle/mirror-dependencies.ps1 `
45+
-ProjectDir <path-to-failing-gradle-project> `
46+
-Task <gradle-task-CI-runs> `
47+
-AndroidHome <path-to-Android-SDK> # required for any com.android.* project
48+
```
49+
50+
The mirror must run in the project that actually needs the new package — a sibling project's build won't trigger a mirror for someone else's deps. Typical convergence is 2-5 iterations as the resolver walks the dep graph breadth-first.
51+
52+
After it succeeds, just re-run the failed CI job. No PR edits needed — the packages are now anonymous-readable forever.
4453

4554
## Don'ts
4655

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

eng/gradle/mirror-dependencies.ps1

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env pwsh
2+
<#
3+
.SYNOPSIS
4+
Mirrors a gradle project's dependencies into the dnceng dotnet-public-maven
5+
Azure Artifacts feed so CI can resolve them anonymously.
6+
7+
.DESCRIPTION
8+
When Dependabot bumps a gradle dependency (or its transitive graph changes),
9+
CI fails with 401 errors because the new package(s) haven't been pulled
10+
from upstream into the dnceng feed yet. CI agents only do anonymous reads,
11+
so a developer has to authenticate locally once to seed the feed.
12+
13+
This script does that by running the requested gradle build in a loop:
14+
1. Run gradle with RunningOnCI=true so it points at the dnceng feed.
15+
2. Parse any 'Could not GET' URLs out of the build log.
16+
3. Re-fetch each failing URL with an Azure DevOps OAuth bearer token
17+
(obtained via `az account get-access-token`). The feed's upstream
18+
connector then pulls the package and caches it for anonymous reads.
19+
4. Repeat until the build succeeds or no more 401s appear.
20+
21+
After the loop converges, no PR edits are needed — just re-run the failing
22+
CI job, since the packages are now anonymous-readable.
23+
24+
.PARAMETER ProjectDir
25+
Path to the gradle project (the one containing the failing dependency).
26+
Mirroring must run in the project that actually requires the package;
27+
a sibling project's build won't trigger a mirror for someone else's deps.
28+
29+
.PARAMETER Task
30+
Gradle task(s) to run. Should be one that resolves the new dependency
31+
graph (e.g. 'assembleDebug', 'build', 'extractProguardFiles').
32+
33+
.PARAMETER AndroidHome
34+
Optional path to the Android SDK. Required when the gradle build needs it
35+
(any project using the com.android.* plugins). Defaults to the value of
36+
`$env:ANDROID_HOME` if set.
37+
38+
.PARAMETER MaxIterations
39+
Cap on build/mirror cycles. Default 15. Typical convergence is 2-5
40+
iterations as the resolver walks the dep graph breadth-first.
41+
42+
.EXAMPLE
43+
pwsh ./eng/gradle/mirror-dependencies.ps1 `
44+
-ProjectDir tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/java/JavaLib `
45+
-Task assembleDebug `
46+
-AndroidHome D:\android-toolchain\sdk
47+
48+
.EXAMPLE
49+
pwsh ./eng/gradle/mirror-dependencies.ps1 -ProjectDir src/proguard-android -Task extractProguardFiles
50+
#>
51+
[CmdletBinding()]
52+
param(
53+
[Parameter(Mandatory=$true)]
54+
[string] $ProjectDir,
55+
56+
[Parameter(Mandatory=$true)]
57+
[string] $Task,
58+
59+
[string] $AndroidHome = $env:ANDROID_HOME,
60+
61+
[int] $MaxIterations = 15
62+
)
63+
64+
$ErrorActionPreference = 'Stop'
65+
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '../..') | Select-Object -ExpandProperty Path
66+
$projectDirAbs = Resolve-Path (Join-Path $repoRoot $ProjectDir) -ErrorAction Stop | Select-Object -ExpandProperty Path
67+
$gradlew = if ($IsWindows -or $env:OS -eq 'Windows_NT') {
68+
Join-Path $repoRoot 'build-tools/gradle/gradlew.bat'
69+
} else {
70+
Join-Path $repoRoot 'build-tools/gradle/gradlew'
71+
}
72+
if (-not (Test-Path $gradlew)) { throw "gradlew not found at $gradlew" }
73+
74+
# Azure DevOps resource id — same for every AzDO tenant.
75+
$azDevOpsResource = '499b84ac-1321-427f-aa17-267ca6975798'
76+
77+
function Get-AzDevOpsToken {
78+
$token = az account get-access-token --resource $azDevOpsResource --query accessToken -o tsv 2>$null
79+
if ([string]::IsNullOrEmpty($token)) {
80+
throw "Could not get an Azure DevOps access token. Run 'az login' first."
81+
}
82+
return $token
83+
}
84+
85+
function Invoke-Mirror($logPath) {
86+
$urls = Select-String -Path $logPath -Pattern "Could not GET 'https://pkgs\.dev\.azure\.com/dnceng/[^']+'" -AllMatches |
87+
ForEach-Object { $_.Matches } |
88+
ForEach-Object { $_.Value -replace "^Could not GET '", "" -replace "'$", "" } |
89+
Sort-Object -Unique
90+
if ($urls.Count -eq 0) { return 0 }
91+
$token = Get-AzDevOpsToken
92+
$headers = @{ Authorization = "Bearer $token" }
93+
$ok = 0; $fail = 0
94+
foreach ($u in $urls) {
95+
try {
96+
$r = Invoke-WebRequest -Uri $u -Headers $headers -SkipHttpErrorCheck -ErrorAction Stop
97+
if ($r.StatusCode -eq 200) { $ok++ } else { $fail++; Write-Host " $($r.StatusCode) $u" -ForegroundColor Yellow }
98+
} catch {
99+
$fail++
100+
Write-Host " ERR $u : $_" -ForegroundColor Yellow
101+
}
102+
}
103+
Write-Host " -> mirrored OK=$ok, not-found=$fail (of $($urls.Count))" -ForegroundColor Cyan
104+
return $urls.Count
105+
}
106+
107+
Write-Host "Repo root: $repoRoot"
108+
Write-Host "Project: $projectDirAbs"
109+
Write-Host "Task: $Task"
110+
if ($AndroidHome) { Write-Host "ANDROID_HOME: $AndroidHome" }
111+
112+
# Verify az is available and authenticated up front so we fail fast.
113+
Get-AzDevOpsToken | Out-Null
114+
115+
if ($AndroidHome) { $env:ANDROID_HOME = $AndroidHome }
116+
$env:RunningOnCI = 'true'
117+
118+
Push-Location $projectDirAbs
119+
try {
120+
for ($i = 1; $i -le $MaxIterations; $i++) {
121+
Write-Host "`n=== iteration $i ===" -ForegroundColor Green
122+
$log = Join-Path ([IO.Path]::GetTempPath()) "gradle-mirror-iter-$i.log"
123+
& $gradlew $Task --no-daemon --refresh-dependencies *>&1 | Tee-Object -FilePath $log | Out-Null
124+
if (Select-String -Path $log -Pattern 'BUILD SUCCESSFUL' -SimpleMatch -Quiet) {
125+
Write-Host "`nBUILD SUCCESSFUL after $i iteration(s). The feed now has the packages CI needs." -ForegroundColor Green
126+
return
127+
}
128+
$count = Invoke-Mirror $log
129+
if ($count -eq 0) {
130+
Write-Host "`nGradle failed but no 401s to mirror — see $log" -ForegroundColor Red
131+
Get-Content $log -Tail 30
132+
exit 1
133+
}
134+
}
135+
Write-Host "`nExhausted $MaxIterations iterations without success. Last log:" -ForegroundColor Red
136+
Get-Content $log -Tail 30
137+
exit 1
138+
}
139+
finally {
140+
Pop-Location
141+
}

eng/gradle/plugin-repositories.gradle

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,11 @@
1515
// reads work forever after. CI therefore does NOT need credentials — it just
1616
// reads anonymously from packages already cached in the feed.
1717
//
18-
// =================== TESTING / INGESTING LOCALLY ===================
19-
//
20-
// To exercise the CI code path locally (or to ingest a new package that
21-
// Dependabot brought in but isn't yet cached in the feed):
22-
//
23-
// 1. Install the Azure Artifacts credential provider (one-time):
24-
//
25-
// PowerShell: iex "& { $(irm https://aka.ms/install-artifacts-credprovider.ps1) }"
26-
// bash: wget -qO- https://aka.ms/install-artifacts-credprovider.sh | bash
27-
//
28-
// 2. Flip the switch and run the gradle build that needs the package:
29-
//
30-
// PowerShell: $env:RunningOnCI='true'; ./build-tools/gradle/gradlew.bat --project-dir src/r8 build
31-
// bash: RunningOnCI=true ./build-tools/gradle/gradlew --project-dir src/r8 build
32-
//
33-
// On first authenticated request, you'll get a device-flow login prompt
34-
// pointing at https://aka.ms/devicelogin — sign in with your Microsoft
35-
// account. The credprovider caches the token; the feed caches the
36-
// package; future CI runs read it anonymously and pass.
37-
//
38-
// =================== WORKFLOW FOR DEPENDABOT PRs ===================
39-
//
40-
// 1. Dependabot opens a PR bumping a Gradle dep (uses public repos, so it
41-
// always sees the latest upstream version).
42-
// 2. CI runs with RunningOnCI=true, hits the feed, and fails with 401 if
43-
// the new package version isn't ingested yet.
44-
// 3. A maintainer follows the steps above to ingest the package, then
45-
// re-runs CI. No PR edit is required.
18+
// When a Dependabot PR's CI fails with 401 because a new package isn't yet
19+
// cached in the feed, run the helper script described in
20+
// .github/instructions/gradle.instructions.md (TL;DR: `az login` once, then
21+
// `pwsh ./eng/gradle/mirror-dependencies.ps1 -ProjectDir <path> -Task <task>`).
22+
// After it succeeds, just re-run the failed CI job — no PR edit is needed.
4623

4724
repositories {
4825
// Anonymous public Azure Artifacts feed that hosts the

src/proguard-android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
plugins {
2-
id 'com.android.application' version '8.7.0'
2+
id 'com.android.application' version '9.2.1'
33
}
44

55
android {

tests/CodeGen-Binding/Xamarin.Android.LibraryProjectZip-LibBinding/Xamarin.Android.LibraryProjectZip-LibBinding.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<LibraryProjectZip Include="$(OutputPath)JavaLib.aar" />
2323
</ItemGroup>
2424
<ItemGroup>
25-
<InputJar Include="java\JavaLib\library\build\intermediates\aar_main_jar\debug\classes.jar">
25+
<InputJar Include="java\JavaLib\library\build\libs\classes.jar">
2626
<Link>Jars\classes.jar</Link>
2727
</InputJar>
2828
</ItemGroup>
Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,10 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

3-
buildscript {
4-
repositories {
5-
google()
6-
mavenCentral()
7-
}
8-
dependencies {
9-
classpath 'com.android.tools.build:gradle:7.4.2'
10-
11-
// NOTE: Do not place your application dependencies here; they belong
12-
// in the individual module build.gradle files
13-
}
14-
}
15-
16-
allprojects {
17-
repositories {
18-
google()
19-
mavenCentral()
20-
}
3+
plugins {
4+
id 'com.android.library' version '9.2.1' apply false
215
}
226

237
task clean(type: Delete) {
24-
delete rootProject.buildDir
8+
delete rootProject.layout.buildDirectory
259
}
2610

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,40 @@
1-
apply plugin: 'com.android.library'
1+
plugins {
2+
id 'com.android.library'
3+
}
24

35
android {
4-
compileSdkVersion 25
6+
namespace 'com.example.javalib'
7+
compileSdk 35
58

69
defaultConfig {
7-
minSdkVersion 19
8-
targetSdkVersion 25
10+
minSdk 21
11+
targetSdk 35
912
versionCode 1
1013
versionName "1.0"
11-
12-
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13-
1414
}
1515
buildTypes {
1616
release {
1717
minifyEnabled false
18-
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
1919
}
2020
}
2121
}
2222

2323
dependencies {
2424
implementation fileTree(dir: 'libs', include: ['*.jar'])
2525
}
26+
27+
// Extract classes.jar from the AAR to a stable path that the binding
28+
// project (../../../Xamarin.Android.LibraryProjectZip-LibBinding.csproj)
29+
// can reference without depending on AGP intermediates/ layout, which
30+
// Google reorganizes between major AGP versions.
31+
tasks.register('extractClassesJar', Copy) {
32+
dependsOn 'assembleDebug'
33+
def aar = layout.buildDirectory.file('outputs/aar/library-debug.aar')
34+
from({ zipTree(aar) }) {
35+
include 'classes.jar'
36+
}
37+
into layout.buildDirectory.dir('libs')
38+
}
39+
40+
tasks.matching { it.name == 'assembleDebug' }.configureEach { finalizedBy 'extractClassesJar' }
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.javalib">
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
22

33
</manifest>

0 commit comments

Comments
 (0)