11
type: boolean
12
default: false
13
14
+ - name: traceLoggingConfig
15
+ type: string
16
+ default: ''
17
+
18
- name: nugetPackages
19
type: object
20
default:
21
- Microsoft.WSL.PluginApi.nuspec
22
19
- - name: traceLoggingConfig
20
- type: string
21
- default: ''
23
+ - name: includePackageStage
24
+ type: boolean
25
+ default: true
26
27
- name: targets
28
type: object
34
- target: "msipackage"
35
pattern: "wsl.msi"
36
33
- - name: platforms
34
- type: object
35
- default:
36
- - x64
37
- - arm64
38
-
37
- name: pool
38
type: string
39
default: ''
60
EsrpClientId: $(EsrpClientId)
61
62
stages:
65
- - stage: build
63
+ # ── x64 build stage ──────────────────────────────────────────────────
64
+ # Runs in parallel with build_arm64. Tests depend on this stage.
65
+ - stage: build_x64
66
+ dependsOn: []
67
jobs:
67
- - job:
68
-
68
+ - template: build-job.yml
69
+ parameters:
70
+ platform: x64
71
+ artifactSuffix: '_build'
72
+ isRelease: ${{ parameters.isRelease }}
73
+ isNightly: ${{ parameters.isNightly }}
74
+ packageVersion: ${{ parameters.packageVersion }}
75
+ traceLoggingConfig: ${{ parameters.traceLoggingConfig }}
76
+ targets: ${{ parameters.targets }}
77
+ pool: ${{ parameters.pool }}
78
+ vsoOrg: ${{ parameters.vsoOrg }}
79
+ vsoProject: ${{ parameters.vsoProject }}
80
+ esrp: ${{ parameters.esrp }}
81
+ includeTestArtifacts: true
82
+
83
+ # ── arm64 build stage (runs in parallel with build_x64) ──────────────
84
+ # Includes formatting/localization checks as a first job, then arm64 build.
85
+ - stage: build_arm64
86
+ dependsOn: []
87
+ jobs:
88
+ - job: checks
89
displayName: "Formatting & localization checks"
90
timeoutInMinutes: 30
91
121
arguments: "-ModifiedOnly $false -Verify $true"
122
displayName: "Clang-format check"
123
104
- - job: build
105
- displayName: "Build WSL package"
106
- timeoutInMinutes: 120
107
-
108
- ${{ if eq(parameters.pool, '') }}:
109
- pool: {'type': 'windows'}
110
-
111
- ${{ else }}:
124
+ - template: build-job.yml
125
+ parameters:
126
+ platform: arm64
127
+ artifactSuffix: '_build_arm64'
128
+ dependsOn: checks
129
+ isRelease: ${{ parameters.isRelease }}
130
+ isNightly: ${{ parameters.isNightly }}
131
+ packageVersion: ${{ parameters.packageVersion }}
132
+ traceLoggingConfig: ${{ parameters.traceLoggingConfig }}
133
+ targets: ${{ parameters.targets }}
134
pool: ${{ parameters.pool }}
113
-
114
- variables:
115
- NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS: 60
116
- NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS: 60
117
- ob_outputDirectory: '$(Build.SourcesDirectory)\out'
118
- ob_artifactBaseName: 'drop_wsl'
119
- ob_artifactSuffix: '_build'
120
- ob_sdl_codeSignValidation_excludes: -|**testbin\**
121
- Codeql.PublishDatabaseLog: true
122
- Codeql.SourceRoot: src
123
- packageStagingDir: '$(Build.SourcesDirectory)\packageStagingDir'
124
- ${{ if eq(parameters.isRelease, 'true') }}:
125
- packageInputDirArg: '-DPACKAGE_INPUT_DIR=$(packageStagingDir)'
126
- ${{ else }}:
127
- packageInputDirArg: ''
128
-
129
- steps:
130
-
131
- - task: CodeQL3000Init@0
132
- inputs:
133
- Enabled: ${{ and(parameters.isNightly, eq(variables['Build.SourceBranch'], 'refs/heads/main'))}}
134
-
135
- - task: UseDotNet@2
136
- displayName: Install .NET Core SDK (required by EsrpCodeSigning)
137
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
138
- inputs:
139
- packageType: "sdk"
140
-
141
- - task: PowerShell@2
142
- displayName: Set trace logging configuration
143
- condition: ne('${{ parameters.traceLoggingConfig }}', '')
144
- inputs:
145
- targetType: 'inline'
146
- script: 'Set-Content -Path src/windows/inc/traceloggingconfig.h -Value $env:config.replace("\n", "`n")'
147
- env:
148
- config: '${{ parameters.traceLoggingConfig }}'
149
-
150
- - task: PowerShell@2
151
- displayName: "Compute package version"
152
- name: version
153
- inputs:
154
- targetType: inline
155
- ${{ if eq(parameters.packageVersion, '') }}:
156
- script: |
157
- $gitversion_version = (Select-Xml -Path packages.config -XPath '/packages/package[@id=''GitVersion.CommandLine'']/@version').Node.Value
158
- $env:path = "packages/GitVersion.CommandLine.$gitversion_version/tools;$env:path"
159
- . .\tools\devops\version_functions.ps1
160
- $version = Get-VersionInfo -Nightly $${{ parameters.isNightly }}
161
- Write-Host "##vso[task.setvariable variable=WSL_PACKAGE_VERSION;isOutput=true]$($version.MsixVersion)"
162
- Write-Host "##vso[task.setvariable variable=WSL_NUGET_PACKAGE_VERSION;isOutput=true]$($version.NugetVersion)"
163
-
164
- ${{ else }}:
165
- script: |
166
- Write-Host "##vso[task.setvariable variable=WSL_PACKAGE_VERSION;isOutput=true]$([string]('${{ parameters.packageVersion }}' + '.0'))"
167
- Write-Host "##vso[task.setvariable variable=WSL_NUGET_PACKAGE_VERSION;isOutput=true]$([string]('${{ parameters.packageVersion }}'))"
168
-
169
- - ${{ each platform in parameters.platforms }}:
170
- - task: CMake@1
171
- displayName: "CMake ${{ platform }}"
172
- inputs:
173
- workingDirectory: "."
174
- cmakeArgs: . --fresh -A ${{ platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true $(packageInputDirArg)\${{ platform }}
175
-
176
- # This additional Restore NuGet package task is added as a workaround for WSL Settings to have its packages restored properly.
177
- # Without this, building wsl settings may encounter the following error:
178
- #
179
- # The plugin credential provider could not acquire credentials. Authentication may require manual action.
180
- # Consider re-running the command with --interactive for `dotnet`, /p:NuGetInteractive="true" for MSBuild or removing the -NonInteractive switch for `NuGet`
181
- # Response status code does not indicate success: 401 (Unauthorized)
182
- - script: _deps\nuget.exe restore -NonInteractive
183
-
184
- - ${{ each target in parameters.targets }}:
185
- - script: cmake --build . --config Release --target ${{ target.target }} -- -m
186
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
187
- displayName: "Build ${{ target.target }} (${{ platform }})"
188
-
189
- - ${{ if eq(parameters.isRelease, 'true') }}:
190
- - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5
191
- displayName: "Sign ${{ target.target }} (${{ platform }})"
192
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
193
- inputs:
194
- ConnectedServiceName: ${{ parameters.esrp.ConnectedServiceName}}
195
- signConfigType: ${{ parameters.esrp.signConfigType }}
196
- SessionTimeout: ${{ parameters.esrp.SessionTimeout }}
197
- MaxConcurrency: ${{ parameters.esrp.MaxConcurrency }}
198
- MaxRetryAttempts: ${{ parameters.esrp.MaxRetryAttempts }}
199
- ServiceEndpointUrl: ${{ parameters.esrp.ServiceEndpointUrl }}
200
- AuthAKVName: ${{ parameters.esrp.AuthAKVName }}
201
- AuthSignCertName: ${{ parameters.esrp.AuthSignCertName }}
202
- AppRegistrationClientId: ${{ parameters.esrp.AppRegistrationClientId }}
203
- AppRegistrationTenantId: ${{ parameters.esrp.AppRegistrationTenantId }}
204
- FolderPath: "bin\\${{ platform }}\\Release"
205
- Pattern: "${{ target.pattern }}"
206
- UseMSIAuthentication: true
207
- EsrpClientId: ${{ parameters.esrp.EsrpClientId }}
208
- inlineOperation: |
209
- [
210
- {
211
- "KeyCode": "CP-230012",
212
- "OperationCode": "SigntoolSign",
213
- "Parameters" : {
214
- "OpusName" : "Microsoft",
215
- "OpusInfo" : "http://www.microsoft.com",
216
- "FileDigest" : "/fd \"SHA256\"",
217
- "PageHash" : "/NPH",
218
- "TimeStamp" : "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
219
- },
220
- "ToolName" : "sign",
221
- "ToolVersion" : "1.0"
222
- },
223
- {
224
- "KeyCode" : "CP-230012",
225
- "OperationCode" : "SigntoolVerify",
226
- "Parameters" : {},
227
- "ToolName" : "sign",
228
- "ToolVersion" : "1.0"
229
- }
230
- ]
231
-
232
- - task: PowerShell@2
233
- displayName: "Copy signed ${{ target.target }} to staging (${{ platform }})"
234
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
235
- inputs:
236
- targetType: inline
237
- script: |
238
- $arch = '${{ platform }}'
239
- $pattern = '${{ target.pattern }}'
240
- $inputDir = "bin\$arch\Release"
241
- $outputDir = "$(packageStagingDir)\$arch"
242
- New-Item -ItemType Directory -Path "$outputDir\wslsettings" -Force
243
- foreach ($file in $pattern.Split(',')) {
244
- $sourcePath = Join-Path $inputDir $file
245
- if (Test-Path $sourcePath) {
246
- $destPath = Join-Path $outputDir $file
247
- Write-Host "Copying signed file: $sourcePath -> $destPath"
248
- Copy-Item -Path $sourcePath -Destination $destPath -Force
249
- } else {
250
- Write-Warning "File not found: $sourcePath"
251
- }
252
- }
253
-
254
- - script: cmake --build . --config Release -- -m
255
- displayName: "Build installer msix and tests (${{ platform }})"
256
-
257
- - task: PowerShell@2
258
- displayName: "Move ${{ platform }} installer msi to output directory"
259
- inputs:
260
- targetType: inline
261
- script: |
262
- New-Item -ItemType Directory -Path "$(ob_outputDirectory)\bundle" -Force
263
- $arch = '${{ platform }}'
264
- Copy-Item -Path "bin\$arch\release\wsl.msi" -Destination "$(ob_outputDirectory)\bundle\wsl.$(version.WSL_PACKAGE_VERSION).$arch.msi"
265
-
266
- - ${{ if eq(parameters.isRelease, 'true') }}:
267
- - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5
268
- displayName: "Sign the bundle"
269
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
270
- inputs:
271
- ConnectedServiceName: ${{ parameters.esrp.ConnectedServiceName}}
272
- signConfigType: ${{ parameters.esrp.signConfigType }}
273
- SessionTimeout: ${{ parameters.esrp.SessionTimeout }}
274
- MaxConcurrency: ${{ parameters.esrp.MaxConcurrency }}
275
- MaxRetryAttempts: ${{ parameters.esrp.MaxRetryAttempts }}
276
- ServiceEndpointUrl: ${{ parameters.esrp.ServiceEndpointUrl }}
277
- AuthAKVName: ${{ parameters.esrp.AuthAKVName }}
278
- AuthSignCertName: ${{ parameters.esrp.AuthSignCertName }}
279
- AppRegistrationClientId: ${{ parameters.esrp.AppRegistrationClientId }}
280
- AppRegistrationTenantId: ${{ parameters.esrp.AppRegistrationTenantId }}
281
- FolderPath: "bundle"
282
- Pattern: "*.msixbundle"
283
- UseMSIAuthentication: true
284
- EsrpClientId: ${{ parameters.esrp.EsrpClientId }}
285
- inlineOperation: |
286
- [
287
- {
288
- "KeyCode": "CP-230012",
289
- "OperationCode": "SigntoolSign",
290
- "Parameters" : {
291
- "OpusName" : "Microsoft",
292
- "OpusInfo" : "http://www.microsoft.com",
293
- "FileDigest" : "/fd \"SHA256\"",
294
- "PageHash" : "/NPH",
295
- "TimeStamp" : "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256"
296
- },
297
- "ToolName" : "sign",
298
- "ToolVersion" : "1.0"
299
- },
300
- {
301
- "KeyCode" : "CP-230012",
302
- "OperationCode" : "SigntoolVerify",
303
- "Parameters" : {},
304
- "ToolName" : "sign",
305
- "ToolVersion" : "1.0"
306
- }
307
- ]
308
-
309
- - script: md.exe $(ob_outputDirectory)\bin\nuget
310
- displayName: "Create the nuget directory"
311
-
312
- - ${{ each package in parameters.nugetPackages }}:
313
- - script: nuget.exe pack ${{ package }} -OutputDirectory $(ob_outputDirectory)\bin\nuget -NonInteractive
314
- displayName: Build ${{ package }}
315
-
316
- - ${{ if eq(parameters.isRelease, 'true') }}:
317
- - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5
318
- displayName: "Sign nuget packages"
319
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
320
- inputs:
321
- ConnectedServiceName: ${{ parameters.esrp.ConnectedServiceName}}
322
- signConfigType: ${{ parameters.esrp.signConfigType }}
323
- SessionTimeout: ${{ parameters.esrp.SessionTimeout }}
324
- MaxConcurrency: ${{ parameters.esrp.MaxConcurrency }}
325
- MaxRetryAttempts: ${{ parameters.esrp.MaxRetryAttempts }}
326
- ServiceEndpointUrl: ${{ parameters.esrp.ServiceEndpointUrl }}
327
- AuthAKVName: ${{ parameters.esrp.AuthAKVName }}
328
- AuthSignCertName: ${{ parameters.esrp.AuthSignCertName }}
329
- AppRegistrationClientId: ${{ parameters.esrp.AppRegistrationClientId }}
330
- AppRegistrationTenantId: ${{ parameters.esrp.AppRegistrationTenantId }}
331
- FolderPath: '$(ob_outputDirectory)\bin\nuget'
332
- Pattern: "*.nupkg"
333
- UseMSIAuthentication: true
334
- EsrpClientId: ${{ parameters.esrp.EsrpClientId }}
335
- inlineOperation: |
336
- [
337
- {
338
- "KeyCode": "CP-401405",
339
- "OperationCode": "NuGetSign",
340
- "Parameters" : {},
341
- "ToolName" : "sign",
342
- "ToolVersion" : "1.0"
343
- },
344
- {
345
- "KeyCode" : "CP-401405",
346
- "OperationCode" : "NuGetVerify",
347
- "Parameters" : {},
348
- "ToolName" : "sign",
349
- "ToolVersion" : "1.0"
350
- }
351
- ]
352
-
353
- - powershell: |
354
- foreach ($arch in @("x64", "ARM64"))
355
- {
356
- $binFolder = ".\bin\$arch\Release"
357
- $pdbFolder = Join-Path $(ob_outputDirectory) "pdb\$arch\Release"
358
- mkdir $pdbFolder
359
- foreach ($filter in @("*.pdb", "*.debug"))
360
- {
361
- foreach ($e in (Get-ChildItem -Recurse -Path $binFolder -Filter $filter)) {Move-Item -Path $e.fullname -Destination (Join-Path $pdbFolder $e.name)}
362
- }
363
- }
364
-
365
- displayName: Collect symbols
366
-
367
- - powershell: |
368
- mkdir appxsym
369
- foreach ($arch in @("x64", "ARM64"))
370
- {
371
- Get-ChildItem -Path $(ob_outputDirectory)\pdb\$arch\release\*.pdb -Exclude wsltests.pdb | Compress-Archive -DestinationPath appxsym/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_$arch.zip
372
- Copy-Item -Path appxsym/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_$arch.zip -Destination appxsym/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_$arch.appxsym
373
- }
374
- mkdir $(ob_outputDirectory)/appxupload
375
- Get-ChildItem -Path appxsym/*.appxsym,bundle/release/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_x64_ARM64.msixbundle | Compress-Archive -DestinationPath $(ob_outputDirectory)/appxupload/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_x64_ARM64.zip
376
- Move-Item -Path $(ob_outputDirectory)/appxupload/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_x64_ARM64.zip -Destination $(ob_outputDirectory)/appxupload/Microsoft.WSL_$(version.WSL_PACKAGE_VERSION)_x64_ARM64.appxupload
377
- rm appxsym/*.appxsym
378
-
379
- displayName: Create appxupload
380
- condition: and(succeeded(), eq('${{ parameters.isRelease }}', true))
381
-
382
- - powershell: |
383
- $taefVersion = (Select-Xml -Path packages.config -XPath '/packages/package[@id=''Microsoft.Taef'']/@version').Node.Value
384
- New-Item -ItemType Directory -Path "$(ob_outputDirectory)\bundle" -Force
385
- # TODO: Add "ARM64" to this list once arm64 testing is supported
386
- foreach ($arch in @("x64"))
387
- {
388
- mkdir $(ob_outputDirectory)\testbin\$arch\release
389
-
390
- Move-Item -Path "bin\$arch\release\wsltests.dll" -Destination "$(ob_outputDirectory)\testbin\$arch\release\wsltests.dll"
391
- Move-Item -Path "bin\$arch\release\testplugin.dll" -Destination "$(ob_outputDirectory)\testbin\$arch\release\testplugin.dll"
392
- Move-Item -Path "packages\Microsoft.Taef.$taefVersion\build\Binaries\$arch" -Destination "$(ob_outputDirectory)\testbin\$arch\release\taef"
393
- Move-Item -Path "bin\$arch\cloudtest" -Destination "$(ob_outputDirectory)\testbin\$arch\cloudtest"
394
-
395
- $TestDistroVersion = (Select-Xml -Path packages.config -XPath '/packages/package[@id=''Microsoft.WSL.TestDistro'']/@version').Node.Value
396
- Copy-Item "packages\Microsoft.WSL.TestDistro.$TestDistroVersion\$arch\test_distro.tar.xz" "$(ob_outputDirectory)\testbin\$arch"
397
- }
398
-
399
- Move-Item -Path "tools\test\test-setup.ps1" -Destination "$(ob_outputDirectory)\testbin\test-setup.ps1"
400
- Move-Item -Path "tools\test\CloudTest-Setup.bat" -Destination "$(ob_outputDirectory)\testbin\CloudTest-Setup.bat"
401
- Move-Item -Path "diagnostics\wsl.wprp" -Destination "$(ob_outputDirectory)\testbin\wsl.wprp"
402
- Move-Item -Path "test\linux\unit_tests" -Destination "$(ob_outputDirectory)\testbin\unit_tests"
403
-
404
- Move-Item -Path bundle\release\* -Destination $(ob_outputDirectory)\bundle
405
-
406
- displayName: Move artifacts to drop directory
407
-
408
- - task: PublishSymbols@2
409
- displayName: Publish symbols
410
- inputs:
411
- SymbolServerType: "TeamServices"
412
- TreatNotIndexedAsWarning: true
413
- SymbolsProduct: WSL
414
- SymbolsVersion: $(version.WSL_PACKAGE_VERSION)
415
- SearchPattern: |
416
- $(ob_outputDirectory)/pdb/**/*.pdb
417
- $(ob_outputDirectory)/bin/**/*.exe
418
- $(ob_outputDirectory)/bin/**/*.dll
419
-
420
- - ${{ if ne(parameters.pool, '') }}:
421
- - task: PublishPipelineArtifact@1
422
- inputs:
423
- targetPath: $(ob_outputDirectory)
424
- artifactName: $(ob_artifactBaseName)$(ob_artifactSuffix)
425
-
426
- - task: CodeQL3000Finalize@0
427
- condition: ${{ and(parameters.isNightly, eq(variables['Build.SourceBranch'], 'refs/heads/main'))}}
428
-
135
+ vsoOrg: ${{ parameters.vsoOrg }}
136
+ vsoProject: ${{ parameters.vsoProject }}
137
+ esrp: ${{ parameters.esrp }}
138
+ includeCodeQL: true
139
+
140
+ # ── package stage (release and nightly only) ─────────────────────────
141
+ # Creates msixbundle, appxupload, and NuGet packages from both platform artifacts.
142
+ - ${{ if parameters.includePackageStage }}:
143
+ - template: package-stage.yml
144
+ parameters:
145
+ isRelease: ${{ parameters.isRelease }}
146
+ pool: ${{ parameters.pool }}
147
+ esrp: ${{ parameters.esrp }}
148
+ nugetPackages: ${{ parameters.nugetPackages }}