Skip to content

Commit b340b15

Browse files
committed
Implement staged build pipelines
1 parent 936db46 commit b340b15

File tree

3 files changed

+881
-0
lines changed

3 files changed

+881
-0
lines changed
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
# Staged Azure Pipelines for .NET MAUI
2+
# This pipeline acts as an orchestrator that reuses existing pipeline templates
3+
# with proper staging and dependencies:
4+
# Stage 1: Core Build & Unit Tests - Fast feedback on compilation and unit tests
5+
# Stage 2: Device Tests - Platform-specific functionality validation (depends on Stage 1)
6+
# Stage 3: UI Tests - End-to-end UI validation (depends on Stage 2)
7+
8+
trigger:
9+
branches:
10+
include:
11+
- main
12+
- net10.0
13+
- release/*
14+
tags:
15+
include:
16+
- '*'
17+
paths:
18+
include:
19+
- '*'
20+
exclude:
21+
- .github/*
22+
- docs/*
23+
- CODE-OF-CONDUCT.md
24+
- CONTRIBUTING.md
25+
- LICENSE.TXT
26+
- PATENTS.TXT
27+
- README.md
28+
- THIRD-PARTY-NOTICES.TXT
29+
30+
pr:
31+
branches:
32+
include:
33+
- main
34+
- net10.0
35+
- release/*
36+
paths:
37+
include:
38+
- '*'
39+
exclude:
40+
- .github/*
41+
- docs/*
42+
- CODE-OF-CONDUCT.md
43+
- CONTRIBUTING.md
44+
- LICENSE.TXT
45+
- PATENTS.TXT
46+
- README.md
47+
- THIRD-PARTY-NOTICES.TXT
48+
49+
variables:
50+
- template: /eng/common/templates/variables/pool-providers.yml@self
51+
- template: /eng/pipelines/common/variables.yml@self
52+
- template: /eng/pipelines/arcade/variables.yml@self
53+
- group: DotNetBuilds storage account read tokens
54+
- group: AzureDevOps-Artifact-Feeds-Pats
55+
- name: AgentPoolAccessToken
56+
value: $(botdeploy--azdo--token--register--xamarin-public--untrusted)
57+
58+
parameters:
59+
- name: VM_IMAGE_HOST
60+
type: object
61+
default:
62+
name: NetCore1ESPool-Internal
63+
image: 1es-windows-2022
64+
os: windows
65+
66+
# Inherit all parameters from device-tests.yml
67+
- name: UseProvisionator
68+
type: boolean
69+
default: false
70+
71+
- name: BuildEverything
72+
type: boolean
73+
default: false
74+
75+
# Inherit all parameters from ui-tests.yml
76+
- name: BuildNativeAOT
77+
displayName: 'Build NativeAOT artifacts'
78+
type: boolean
79+
default: false
80+
81+
- name: RunNativeAOT
82+
displayName: 'Run NativeAOT UI Tests'
83+
type: boolean
84+
default: false
85+
86+
# Pool parameters from both device-tests.yml and ui-tests.yml
87+
- name: androidPool
88+
type: object
89+
default:
90+
name: $(androidTestsVmPool)
91+
vmImage: $(androidTestsVmImage)
92+
demands:
93+
- macOS.Name -equals Sequoia
94+
- macOS.Architecture -equals x64
95+
96+
- name: androidPoolLinux
97+
type: object
98+
default:
99+
name: $(1ESPTPool)
100+
vmImage: $(androidTestsVmImage)
101+
demands:
102+
- ImageOverride -equals 1ESPT-Ubuntu22.04
103+
104+
- name: iosPool
105+
type: object
106+
default:
107+
name: $(iosDeviceTestsVmPool)
108+
vmImage: $(iosDeviceTestsVmImage)
109+
demands:
110+
- macOS.Name -equals Sequoia
111+
112+
- name: catalystPool
113+
type: object
114+
default:
115+
name: $(iosDeviceTestsVmPool)
116+
vmImage: $(iosDeviceTestsVmImage)
117+
demands:
118+
- macOS.Name -equals Sequoia
119+
120+
- name: windowsPool
121+
type: object
122+
default:
123+
name: $(windowsTestsVmPool)
124+
vmImage: $(windowsTestsVmImage)
125+
126+
- name: windowsBuildPool
127+
type: object
128+
default:
129+
name: $(windowsVmPool)
130+
vmImage: $(windowsVmImage)
131+
132+
- name: macosPool
133+
type: object
134+
default:
135+
name: Azure Pipelines
136+
vmImage: macOS-14
137+
138+
- name: targetFrameworkVersions
139+
type: object
140+
default:
141+
- tfm: net9.0
142+
143+
resources:
144+
repositories:
145+
- repository: 1ESPipelineTemplates
146+
type: git
147+
name: 1ESPipelineTemplates/1ESPipelineTemplates
148+
ref: refs/tags/release
149+
150+
extends:
151+
${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
152+
template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
153+
${{ else }}:
154+
template: v1/1ES.Unofficial.PipelineTemplate.yml@1ESPipelineTemplates
155+
parameters:
156+
pool: ${{ parameters.VM_IMAGE_HOST }}
157+
sdl:
158+
binskim:
159+
scanOutputDirectoryOnly: true
160+
codeql:
161+
runSourceLanguagesInSourceAnalysis: true
162+
policheck:
163+
enabled: true
164+
spotBugs:
165+
enabled: false
166+
justification: 'Failing with "Could not successfully find the java tool launcher"'
167+
sourceRepositoriesToScan:
168+
exclude:
169+
- repository: yaml-templates
170+
suppression:
171+
suppressionFile: $(Build.SourcesDirectory)\eng\automation\guardian\source.gdnsuppress
172+
stages:
173+
174+
# =============================================================================
175+
# STAGE 1: Core Build & Unit Tests
176+
# Reuses existing azure-pipelines-internal.yml logic
177+
# =============================================================================
178+
- template: /eng/pipelines/arcade/stage-pack.yml@self
179+
parameters:
180+
pool: ${{ parameters.VM_IMAGE_HOST }}
181+
enableSourceIndex: false
182+
runAsPublic: false
183+
sourceIndexParams:
184+
sourceIndexBuildCommand: build.cmd -restore -build -ci /bl:$(Build.Arcade.LogsPath)sourceIndexBuild.binlog /p:OfficialBuildId=$(_BuildOfficalId) /p:_SkipUpdateBuildNumber=true
185+
binlogPath: $(Build.Arcade.LogsPath)sourceIndexBuild.binlog
186+
prepareSteps:
187+
- template: /eng/pipelines/common/provision.yml@self
188+
parameters:
189+
checkoutDirectory: '$(System.DefaultWorkingDirectory)'
190+
skipJdk: false
191+
skipAndroidCommonSdks: false
192+
skipAndroidPlatformApis: false
193+
onlyAndroidPlatformDefaultApis: true
194+
skipAndroidEmulatorImages: true
195+
skipAndroidCreateAvds: true
196+
skipProvisioning: true
197+
skipXcode: true
198+
199+
# Run Unit Tests as part of Stage 1 (always, not just PRs)
200+
- template: /eng/pipelines/arcade/stage-unit-tests.yml@self
201+
parameters:
202+
jobMatrix:
203+
- name: win_unit_tests
204+
displayName: Windows Unit Tests
205+
pool: ${{ parameters.VM_IMAGE_HOST }}
206+
timeout: 120
207+
testOS: Windows
208+
- name: mac_unit_tests
209+
displayName: macOS Unit Tests
210+
pool:
211+
name: Azure Pipelines
212+
vmImage: $(HostedMacImage)
213+
os: macOS
214+
timeout: 120
215+
testOS: macOS
216+
217+
# API Scan as part of Stage 1
218+
- template: /eng/pipelines/arcade/stage-api-scan.yml@self
219+
parameters:
220+
pool: ${{ parameters.VM_IMAGE_HOST }}
221+
dependsOnStage: UnitTests
222+
223+
# =============================================================================
224+
# STAGE 2: Device Tests
225+
# Reuses existing device-tests.yml logic with dependency on Stage 1
226+
# =============================================================================
227+
- ${{ each targetFrameworkVersion in parameters.targetFrameworkVersions }}:
228+
- template: common/device-tests-staged.yml
229+
parameters:
230+
androidPool: ${{ parameters.androidPool }}
231+
iosPool: ${{ parameters.iosPool }}
232+
catalystPool: ${{ parameters.catalystPool }}
233+
windowsPool: ${{ parameters.windowsPool }}
234+
targetFrameworkVersion: ${{ targetFrameworkVersion }}
235+
# Add external dependency on ApiScan stage
236+
externalDependencies:
237+
- ApiScan
238+
${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}:
239+
androidApiLevels: [ 33, 30, 29, 28, 27, 26, 25, 24, 23 ]
240+
iosVersions: [ 'simulator-18.0' ]
241+
catalystVersions: [ 'latest' ]
242+
windowsVersions: [ 'packaged', 'unpackaged' ]
243+
provisionatorChannel: latest
244+
skipProvisioning: ${{ or(not(parameters.UseProvisionator), false) }}
245+
${{ else }}:
246+
androidApiLevels: [ 33, 23 ]
247+
iosVersions: [ 'simulator-18.0' ]
248+
catalystVersions: [ 'latest' ]
249+
windowsVersions: [ 'packaged', 'unpackaged' ]
250+
provisionatorChannel: latest
251+
skipProvisioning: ${{ not(parameters.UseProvisionator) }}
252+
projects:
253+
- name: essentials
254+
desc: Essentials
255+
androidApiLevelsExclude: [ 25, 27 ] # Ignore for now API25 since the runs's are not stable
256+
androidConfiguration: 'Release'
257+
iOSConfiguration: 'Debug'
258+
windowsConfiguration: 'Debug'
259+
windowsPackageId: 'com.microsoft.maui.essentials.devicetests'
260+
android: $(System.DefaultWorkingDirectory)/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
261+
ios: $(System.DefaultWorkingDirectory)/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
262+
catalyst: $(System.DefaultWorkingDirectory)/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
263+
windows: $(System.DefaultWorkingDirectory)/src/Essentials/test/DeviceTests/Essentials.DeviceTests.csproj
264+
- name: graphics
265+
desc: Graphics
266+
androidApiLevelsExclude: [ 25, 28 ] # Ignore for now API25 and API28 since the runs's are not stable
267+
androidConfiguration: 'Release'
268+
iOSConfiguration: 'Debug'
269+
windowsConfiguration: 'Debug'
270+
windowsPackageId: 'com.microsoft.maui.graphics.devicetests'
271+
android: $(System.DefaultWorkingDirectory)/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
272+
ios: $(System.DefaultWorkingDirectory)/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
273+
catalyst: $(System.DefaultWorkingDirectory)/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
274+
windows: $(System.DefaultWorkingDirectory)/src/Graphics/tests/DeviceTests/Graphics.DeviceTests.csproj
275+
- name: core
276+
desc: Core
277+
androidApiLevelsExclude: [ 25 ] # Ignore for now API25 since the runs's are not stable
278+
androidConfiguration: 'Release'
279+
iOSConfiguration: 'Debug'
280+
windowsConfiguration: 'Debug'
281+
windowsPackageId: 'com.microsoft.maui.core.devicetests'
282+
android: $(System.DefaultWorkingDirectory)/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
283+
ios: $(System.DefaultWorkingDirectory)/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
284+
catalyst: $(System.DefaultWorkingDirectory)/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
285+
windows: $(System.DefaultWorkingDirectory)/src/Core/tests/DeviceTests/Core.DeviceTests.csproj
286+
- name: controls
287+
desc: Controls
288+
androidApiLevelsExclude: [ 27, 25 ] # Ignore for now API25 since the runs's are not stable
289+
androidConfiguration: 'Debug'
290+
iOSConfiguration: 'Debug'
291+
windowsConfiguration: 'Debug'
292+
windowsPackageId: 'com.microsoft.maui.controls.devicetests'
293+
android: $(System.DefaultWorkingDirectory)/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
294+
ios: $(System.DefaultWorkingDirectory)/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
295+
catalyst: $(System.DefaultWorkingDirectory)/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
296+
windows: $(System.DefaultWorkingDirectory)/src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
297+
- name: blazorwebview
298+
desc: BlazorWebView
299+
androidApiLevelsExclude: [ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21 ] # BlazorWebView requires a recent version of Chrome
300+
androidConfiguration: 'Release'
301+
iOSConfiguration: 'Debug'
302+
windowsConfiguration: 'Debug'
303+
windowsPackageId: 'Microsoft.Maui.MauiBlazorWebView.DeviceTests'
304+
android: $(System.DefaultWorkingDirectory)/src/BlazorWebView/tests/MauiDeviceTests/MauiBlazorWebView.DeviceTests.csproj
305+
ios: $(System.DefaultWorkingDirectory)/src/BlazorWebView/tests/MauiDeviceTests/MauiBlazorWebView.DeviceTests.csproj
306+
catalyst: $(System.DefaultWorkingDirectory)/src/BlazorWebView/tests/MauiDeviceTests/MauiBlazorWebView.DeviceTests.csproj
307+
windows: $(System.DefaultWorkingDirectory)/src/BlazorWebView/tests/MauiDeviceTests/MauiBlazorWebView.DeviceTests.csproj
308+
309+
# =============================================================================
310+
# STAGE 3: UI Tests
311+
# Reuses existing ui-tests.yml logic with dependency on Stage 2
312+
# =============================================================================
313+
- template: common/ui-tests-staged.yml
314+
parameters:
315+
androidPool: ${{ parameters.androidPool }}
316+
androidLinuxPool: ${{ parameters.androidPoolLinux }}
317+
iosPool: ${{ parameters.iosPool }}
318+
windowsPool: ${{ parameters.windowsPool }}
319+
windowsBuildPool: ${{ parameters.windowsBuildPool }}
320+
macosPool: ${{ parameters.macosPool }}
321+
# Add external dependencies on all device test stages
322+
externalDependencies:
323+
- android_device_tests_net9_0
324+
- ios_device_tests_net9_0
325+
- catalyst_device_tests_net9_0
326+
- windows_device_tests_net9_0
327+
# BuildNativeAOT is false by default, but true in devdiv environment
328+
BuildNativeAOT: ${{ or(parameters.BuildNativeAOT, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}
329+
RunNativeAOT: ${{ parameters.RunNativeAOT }}
330+
${{ if or(parameters.BuildEverything, and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['System.TeamProject'], 'devdiv'))) }}:
331+
androidApiLevels: [ 30 ]
332+
iosVersions: [ '18.0' ]
333+
${{ else }}:
334+
androidApiLevels: [ 30 ]
335+
iosVersions: [ '18.0' ]
336+
${{ if or(parameters.UseProvisionator, eq(variables['internalProvisioning'],'true') ) }}:
337+
skipProvisioning: false
338+
${{ else }}:
339+
skipProvisioning: true
340+
projects:
341+
- name: controls
342+
desc: Controls
343+
androidApiLevelsExclude: [25] # Ignore for now API25 since the runs's are not stable
344+
android: $(System.DefaultWorkingDirectory)/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj
345+
app: $(Pipeline.Workspace)/Controls.TestCases.HostApp/
346+
iosVersionsExclude: [ '12.4'] # Ignore iOS 12.4 while we can't make it work on CI
347+
ios: $(System.DefaultWorkingDirectory)/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj
348+
winui: $(System.DefaultWorkingDirectory)/src/Controls/tests/TestCases.WinUI.Tests/Controls.TestCases.WinUI.Tests.csproj
349+
mac: $(System.DefaultWorkingDirectory)/src/Controls/tests/TestCases.Mac.Tests/Controls.TestCases.Mac.Tests.csproj
350+
351+
# Publish and validation steps. Only run in official builds and after all tests complete
352+
- ${{ if ne(variables['Build.Reason'], 'PullRequest') }}:
353+
- template: /eng/common/templates-official/post-build/post-build.yml@self
354+
parameters:
355+
dependsOn:
356+
- android_ui_tests
357+
- ios_ui_tests_mono
358+
- winui_ui_tests
359+
- mac_ui_tests
360+
publishingInfraVersion: 3
361+
enableSymbolValidation: true
362+
enableSigningValidation: false
363+
# Disable for now as we test the new signing process
364+
enableSourceLinkValidation: false
365+
validateDependsOn:
366+
- android_ui_tests
367+
- ios_ui_tests_mono
368+
- winui_ui_tests
369+
- mac_ui_tests
370+
publishDependsOn:
371+
- Validate
372+
# This is to enable SDL runs part of Post-Build Validation Stage
373+
SDLValidationParameters:
374+
enable: false

0 commit comments

Comments
 (0)