Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
59324e1
[ci] Make dnceng-public the default PR pipeline; disable PR triggers …
jonathanpeppers Jun 4, 2026
ff746ad
Merge branch 'main' into jonathanpeppers/dnceng-public-default-pr
jonathanpeppers Jun 4, 2026
e7c6ed4
[build] Reset workload manifest mtimes after extract
jonathanpeppers Jun 4, 2026
6a6faa3
[build] Simplify Touch to wildcard all extracted files
jonathanpeppers Jun 4, 2026
f5b1243
[ci] Port MAUI Tests stage; match emulator slice count
jonathanpeppers Jun 8, 2026
fafa3a5
[ci] MAUI job: useAgentJdkPath=false on public Windows image
jonathanpeppers Jun 8, 2026
f2ee5c9
[ci] MAUI job: checkout self with submodules
jonathanpeppers Jun 8, 2026
92bb6fb
[ci] MAUI job: point ANDROID_HOME at xa-prepare SDK
jonathanpeppers Jun 8, 2026
e1c2491
[ci] MAUI job: install Node.js for TypeScript build
jonathanpeppers Jun 8, 2026
063c8bf
[ci] MAUI job: match dotnet/maui's 1es-windows-2022-open image
jonathanpeppers Jun 8, 2026
f308215
[ci] MAUI job: restore Gradle dependency cache between runs
jonathanpeppers Jun 8, 2026
4eaba03
Merge branch 'main' into jonathanpeppers/dnceng-public-default-pr
jonathanpeppers Jun 8, 2026
2e16aef
[ci] MAUI job: resolve ANDROID_HOME via Configuration.props rules
jonathanpeppers Jun 9, 2026
f2eb3ba
[ci] Retrigger: transient HTTP 500 rate-limit on NuGet feed in 1455280
jonathanpeppers Jun 9, 2026
83a9d08
[ci] Retrigger: transient HTTP 500 rate-limit on Windows in 1455352
jonathanpeppers Jun 9, 2026
86f90bb
[ci] Retry make jenkins / Prepare Solution on transient NuGet HTTP 500
jonathanpeppers Jun 9, 2026
f5df5d1
[ci] Reduce build retry count to 1; drop unused 'auto' skipTests value
jonathanpeppers Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 200 additions & 15 deletions build-tools/automation/azure-pipelines-public.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ pr:
parameters:
- name: macTestAgentsUseCleanImages # Test agents we do not need to clean up when finished because they are not reused
default: true
- name: skipTests # Skip all test stages (builds only). Use 'auto' to auto-skip for non-fork PRs.
- name: skipTests # Skip all test stages (builds only). Default 'false' so PRs run the full test matrix.
displayName: Skip Tests
type: string
default: 'auto'
default: 'false'
Comment thread
jonathanpeppers marked this conversation as resolved.
values:
Comment thread
jonathanpeppers marked this conversation as resolved.
- 'auto'
- 'true'
- 'false'

Expand All @@ -33,6 +32,11 @@ resources:
name: dotnet/android-tools
endpoint: public
ref: refs/heads/main
- repository: maui
type: github
name: dotnet/maui
endpoint: public
ref: net11.0

# Global variables
variables:
Expand All @@ -51,14 +55,10 @@ variables:
value: windows.vs2022.amd64.open
- name: LinuxPoolImageNetCorePublic
value: build.Ubuntu.2204.amd64.open
# Skip tests for non-fork PRs (they should use DevDiv pipeline) unless explicitly requested
# Skip tests when explicitly requested; otherwise run full PR test matrix.
- name: SkipTestStages
${{ if eq(parameters.skipTests, 'true') }}:
value: true
${{ elseif eq(parameters.skipTests, 'false') }}:
value: false
${{ elseif and(eq(variables['Build.Reason'], 'PullRequest'), ne(variables['System.PullRequest.IsFork'], 'True')) }}:
value: true
${{ else }}:
value: false

Expand All @@ -67,7 +67,6 @@ stages:
# macOS Build Stage
- stage: mac_build
displayName: Mac
condition: eq(variables['System.PullRequest.IsFork'], 'True')
jobs:
- job: mac_build_create_installers
displayName: macOS > Build
Expand Down Expand Up @@ -104,7 +103,6 @@ stages:
- stage: win_build_test
displayName: Windows
dependsOn: []
condition: eq(variables['System.PullRequest.IsFork'], 'True')
jobs:
- job: win_build_test
displayName: Windows > Build & Smoke Test
Expand All @@ -126,7 +124,6 @@ stages:
- stage: linux_build
displayName: Linux
dependsOn: []
condition: eq(variables['System.PullRequest.IsFork'], 'True')
jobs:
- job: linux_build_create_sdk_pack
displayName: Linux > Build
Expand Down Expand Up @@ -174,7 +171,7 @@ stages:
dependsOn:
- mac_build
- linux_build
condition: and(succeeded(), eq(variables['System.PullRequest.IsFork'], 'True'), ne(variables['SkipTestStages'], 'true'))
condition: and(succeeded(), ne(variables['SkipTestStages'], 'true'))
jobs:
- job: linux_tests_smoke_1
displayName: Linux > Tests > MSBuild 1
Expand Down Expand Up @@ -270,7 +267,7 @@ stages:
- stage: msbuild_dotnet
displayName: MSBuild Tests
dependsOn: mac_build
condition: and(succeeded(), eq(variables['System.PullRequest.IsFork'], 'True'), ne(variables['SkipTestStages'], 'true'))
condition: and(succeeded(), ne(variables['SkipTestStages'], 'true'))
jobs:
- job: mac_msbuild_tests
strategy:
Expand Down Expand Up @@ -362,11 +359,11 @@ stages:
- stage: msbuilddevice_tests
displayName: MSBuild Emulator Tests
dependsOn: mac_build
condition: and(succeeded(), eq(variables['System.PullRequest.IsFork'], 'True'), ne(variables['SkipTestStages'], 'true'))
condition: and(succeeded(), ne(variables['SkipTestStages'], 'true'))
jobs:
- job: mac_dotnetdevice_tests
strategy:
parallel: 8
parallel: 12
displayName: "macOS > Tests > MSBuild+Emulator"
# NOTE: AcesShared pool cannot boot Android emulators, so these jobs must use hosted images
pool:
Expand Down Expand Up @@ -415,3 +412,191 @@ stages:
- template: /build-tools/automation/yaml-templates/fail-on-issue.yaml
parameters:
condition: true

# MAUI Tests Stage
- stage: maui_tests
displayName: MAUI Tests
dependsOn: mac_build
condition: and(succeeded(), ne(variables['SkipTestStages'], 'true'))
Comment thread
jonathanpeppers marked this conversation as resolved.
jobs:
- job: maui_tests_integration
displayName: MAUI Integration
pool:
name: $(NetCorePublicPoolName)
demands:
- ImageOverride -equals 1es-windows-2022-open
os: windows
timeoutInMinutes: 180
workspace:
clean: all
variables:
BuildVersion: $(Build.BuildId)
# Ignore MAUI's public API analyzer errors (RS0016) - dotnet/android does not care about those
PublicApiType: Generate
steps:
- checkout: self
clean: true
submodules: recursive
path: s/android
persistCredentials: false

- checkout: maui
clean: true
submodules: recursive
path: s/maui
persistCredentials: true

# Restore ~/.gradle/caches between runs so MAUI's Gradle resolution
# for android-gradle-plugin/sdklib/ddmlib is not gated on the
# dotnet-public-maven Maven feed every build. The dnceng-public Maven
# feed periodically rate-limits ('exceeding usage of resource Concurrency
# in namespace IPAddress', HTTP 500), which deterministically fails
# MAUI's ./build.ps1 --target=dotnet-pack.
# Adapted from upstream dotnet/maui, which adopted the pattern from us:
# https://github.com/dotnet/maui/blob/net11.0/eng/pipelines/common/cache-gradle.yml
- template: /build-tools/automation/yaml-templates/cache-gradle.yaml
parameters:
xaSourcePath: $(Build.SourcesDirectory)/android

- template: /build-tools/automation/yaml-templates/setup-test-environment-steps.yaml
parameters:
xaSourcePath: $(Build.SourcesDirectory)/android
androidSdkPlatforms: $(DefaultTestSdkPlatforms)
dotnetVersion: $(DotNetSdkVersion)
dotnetQuality: $(DotNetSdkQuality)
useAgentJdkPath: false
use1ESTemplate: false

- task: DownloadPipelineArtifact@2
inputs:
artifactName: $(NuGetArtifactName)
downloadPath: $(Build.StagingDirectory)/android-packs

- pwsh: |
$searchPath = Join-Path $(Build.StagingDirectory) android-packs
$wlmanPack = Get-ChildItem $searchPath -Filter *Android*Manifest*.nupkg | Select-Object -First 1
$dest = Join-Path $searchPath "tmp-wlman" "$($wlmanPack.BaseName)"
Expand-Archive -LiteralPath $wlmanPack -DestinationPath $dest
$wlmanJsonPath = Join-Path $dest "data" "WorkloadManifest.json"
$json = Get-Content $wlmanJsonPath | ConvertFrom-Json -AsHashtable
Write-Host "Setting variable ANDROID_PACK_VERSION = $($json["version"])"
Write-Host "##vso[task.setvariable variable=ANDROID_PACK_VERSION;]$($json["version"])"
displayName: Set ANDROID_PACK_VERSION

- pwsh: >-
$(Build.SourcesDirectory)/maui/eng/scripts/update-version-props.ps1
-xmlFileName "$(Build.SourcesDirectory)/maui/eng/Versions.props"
-androidVersion $(ANDROID_PACK_VERSION)
displayName: Update MAUI's Android dependency

- task: DotNetCoreCLI@2
displayName: Update Android SDK band in Workloads.csproj
inputs:
projects: $(Build.SourcesDirectory)/android/Xamarin.Android.sln
arguments: -t:UpdateMauiWorkloadsProj -c $(XA.Build.Configuration) --no-restore -v:n -bl:$(Build.StagingDirectory)/logs/update-maui-workloadsproj.binlog

- pwsh: ./build.ps1 --target=dotnet --configuration="$(XA.Build.Configuration)" --nugetsource="$(Build.StagingDirectory)\android-packs" --verbosity=diagnostic
displayName: Install .NET
retryCountOnTaskFailure: 3
workingDirectory: $(Build.SourcesDirectory)/maui

- task: NodeTool@0
displayName: Install Node.js
# MAUI's TypeScript build steps for the BlazorWebView project shell out
# to node.exe; the dnceng-public windows.vs2022.amd64.open image does
# not preinstall Node, so install it explicitly.
inputs:
versionSpec: '20.x'

- pwsh: |
# Match Configuration.props: prefer ANDROID_SDK_ROOT if set+exists,
# else $(HOME)\android-toolchain\sdk, else $env:USERPROFILE fallback.
$candidates = @()
if ($env:ANDROID_SDK_ROOT) { $candidates += $env:ANDROID_SDK_ROOT }
if ($env:ANDROID_HOME) { $candidates += $env:ANDROID_HOME }
if ($env:HOME) { $candidates += "$env:HOME\android-toolchain\sdk" }
if ($env:USERPROFILE) { $candidates += "$env:USERPROFILE\android-toolchain\sdk" }
$sdk = $candidates | Where-Object { $_ -and (Test-Path (Join-Path $_ 'platforms')) } | Select-Object -First 1
if (-not $sdk) {
Write-Error "Could not find an Android SDK install with a 'platforms' subdir. Tried:`n$($candidates -join "`n")"
exit 1
}
Write-Host "Setting ANDROID_HOME / ANDROID_SDK_ROOT to '$sdk'"
Get-ChildItem (Join-Path $sdk 'platforms') | ForEach-Object { Write-Host " platforms\$($_.Name)" }
Write-Host "##vso[task.setvariable variable=ANDROID_HOME]$sdk"
Write-Host "##vso[task.setvariable variable=ANDROID_SDK_ROOT]$sdk"
displayName: Point ANDROID_HOME at xa-prepare SDK
# androidsdk.csproj's install path follows Configuration.props rules:
# ANDROID_SDK_ROOT if it exists, otherwise %HOME%\android-toolchain\sdk.
# On the 1es-windows-2022-open image, ANDROID_SDK_ROOT is preset to
# the agent's preinstalled SDK (e.g. C:\Program Files (x86)\Android\android-sdk),
# so xa-prepare ends up extending that location with the requested
# API levels. Whichever path it picked, MAUI's build needs the same
# ANDROID_HOME / ANDROID_SDK_ROOT so it sees API 37, etc.

- pwsh: ./build.ps1 --target=dotnet-pack --configuration="$(XA.Build.Configuration)" --nugetsource="$(Build.StagingDirectory)\android-packs" --verbosity=diagnostic
displayName: Pack .NET Maui
workingDirectory: $(Build.SourcesDirectory)/maui

- task: DotNetCoreCLI@2
displayName: Install MAUI workload packs
retryCountOnTaskFailure: 3
inputs:
projects: $(Build.SourcesDirectory)/android/Xamarin.Android.sln
arguments: -t:InstallMaui -p:MauiUseLocalPacks=true -p:MauiWorkloadToInstall=maui -p:MauiManifestDiagnosticsPath=$(Build.StagingDirectory)/logs/maui-manifest -c $(XA.Build.Configuration) --no-restore -v:n -bl:$(Build.StagingDirectory)/logs/install-maui.binlog

- template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml
parameters:
command: new
arguments: maui -o $(Build.StagingDirectory)/MauiTestProj
xaSourcePath: $(Build.SourcesDirectory)/android
displayName: Create MAUI template
continueOnError: false

- powershell: |
$project = '$(Build.StagingDirectory)/MauiTestProj/MauiTestProj.csproj'
[xml] $xml = Get-Content $project
$node = $xml.SelectSingleNode('/Project/PropertyGroup/TargetFrameworks')
$node.InnerText = '$(DotNetTargetFramework)-android'
$xml.Save($project)
displayName: set TargetFrameworks to Android-only

- template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml
parameters:
project: $(Build.StagingDirectory)/MauiTestProj/MauiTestProj.csproj
arguments: >-
-f $(DotNetTargetFramework)-android -c Debug
--configfile $(Build.SourcesDirectory)/maui/NuGet.config
-bl:$(Build.StagingDirectory)/logs/MauiTestProj-Debug.binlog
xaSourcePath: $(Build.SourcesDirectory)/android
displayName: Build MAUI template - Debug

- template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml
parameters:
project: $(Build.StagingDirectory)/MauiTestProj/MauiTestProj.csproj
arguments: >-
-f $(DotNetTargetFramework)-android -c Release
--configfile $(Build.SourcesDirectory)/maui/NuGet.config
-bl:$(Build.StagingDirectory)/logs/MauiTestProj-Release.binlog
xaSourcePath: $(Build.SourcesDirectory)/android
displayName: Build MAUI template - Release

- task: CopyFiles@2
displayName: copy build logs
condition: always()
inputs:
Contents: |
$(Build.SourcesDirectory)/android/bin/*$(XA.Build.Configuration)/*.*log
$(Build.SourcesDirectory)/maui/artifacts/logs/**
TargetFolder: $(Build.StagingDirectory)/logs
flattenFolders: true

- template: /build-tools/automation/yaml-templates/publish-artifact.yaml
parameters:
displayName: upload build and test results
artifactName: Test Results - MAUI Integration
targetPath: $(Build.StagingDirectory)/logs
condition: or(ne(variables['Agent.JobStatus'], 'Succeeded'), eq(variables['XA.PublishAllLogs'], 'true'))
use1ESTemplate: false

- template: /build-tools/automation/yaml-templates/fail-on-issue.yaml
2 changes: 2 additions & 0 deletions build-tools/automation/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ trigger:
- release/*
- feature/*

pr: none

# External sources, scripts, tests, and yaml template files.
resources:
repositories:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ steps:
- script: make jenkins PREPARE_CI=1 PREPARE_AUTOPROVISION=1 CONFIGURATION=$(XA.Build.Configuration) MSBUILD_ARGS='${{ parameters.makeMSBuildArgs }}'
workingDirectory: ${{ parameters.xaSourcePath }}
displayName: make jenkins
retryCountOnTaskFailure: 1

- script: make create-nupkgs CONFIGURATION=$(XA.Build.Configuration)
workingDirectory: ${{ parameters.xaSourcePath }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ steps:
- script: make jenkins CONFIGURATION=$(XA.Build.Configuration) PREPARE_CI=1 PREPARE_AUTOPROVISION=1 MSBUILD_ARGS='${{ parameters.makeMSBuildArgs }}'
workingDirectory: ${{ parameters.xaSourcePath }}
displayName: make jenkins
retryCountOnTaskFailure: 1

- script: make create-installers CONFIGURATION=$(XA.Build.Configuration) MSBUILD_ARGS='${{ parameters.makeMSBuildArgs }}'
workingDirectory: ${{ parameters.xaSourcePath }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ steps:

- task: DotNetCoreCLI@2
displayName: Prepare Solution
retryCountOnTaskFailure: 1
inputs:
projects: Xamarin.Android.sln
arguments: '-c $(XA.Build.Configuration) -t:Prepare --no-restore -p:AutoProvision=true -bl:$(System.DefaultWorkingDirectory)\bin\Build$(XA.Build.Configuration)\dotnet-build-prepare.binlog'
Expand Down
13 changes: 13 additions & 0 deletions build-tools/create-packs/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,19 @@
</ItemGroup>
<Move SourceFiles="@(_WLExtractedFiles)" DestinationFolder="$(_SdkManifestsFolder)microsoft.net.sdk.android\$(AndroidPackVersionLong)\" />
<RemoveDir Directories="$(_SdkManifestsFolder)temp\" />
<!--
Reset timestamps to "now" on the local agent. The zip entries inside
Microsoft.NET.Sdk.Android.Manifest-*.nupkg carry the pack agent's local
clock, which on the dnceng-public ACES_VM_SharedPool_Tahoe macOS pool
can be ~5 hours ahead of the test agent. If we leave the extracted
mtimes as-is, $(MSBuildAllProjects) imports WorkloadManifest.targets
with a future mtime and every Android incremental target re-runs on
subsequent builds, breaking "target should be skipped" assertions.
-->
<ItemGroup>
<_WLExtractedDestFiles Include="$(_SdkManifestsFolder)microsoft.net.sdk.android\$(AndroidPackVersionLong)\*" />
</ItemGroup>
<Touch Files="@(_WLExtractedDestFiles)" />

<!-- Parse NuGet.config -->
<XmlPeek
Expand Down
Loading