Skip to content

Commit 4169f9a

Browse files
Combine official-build artifact uploads for perf (#12931)
Scans injected by policy have dramatically increased our official build time. I consulted with some folks internally, the highest-impact approach we identified was to reduce the number of invocations of the artifact-upload tasks, since each one in the normal flow of the job incurs a scan cost. To do this we had to: 1. Convert all of the `1ES.PublishBuildArtifacts` task calls to declarative template `outputs:` 2. define an `outputParentDirectory` that can be scanned exactly once (for all uploaded artifacts) instead of per-upload 3. Restrict that `outputParentDirectory` to contain only things that will be uploaded (`artifacts/` was too broad and caused the scan to find some false positives). Example successful official build: https://dev.azure.com/devdiv/DevDiv/_build/results?buildId=12895565 <img width="503" height="346" alt="image" src="https://github.com/user-attachments/assets/b79838d2-bba1-43e0-bd15-00584c4ca858" /> (compare that 1h 21m to 2h 34m from a recent `main` branch official build) Example exp build showing log upload on (artificially injected) failure: https://dev.azure.com/devdiv/DevDiv/_build/results?buildId=12941708
1 parent 5ef39be commit 4169f9a

File tree

1 file changed

+105
-58
lines changed

1 file changed

+105
-58
lines changed

azure-pipelines/.vsts-dotnet-build-jobs.yml

Lines changed: 105 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,51 @@ jobs:
2222

2323
timeoutInMinutes: 180
2424

25+
templateContext:
26+
outputParentDirectory: '$(Build.SourcesDirectory)\artifacts\official'
27+
outputs:
28+
# Publish OptProf configuration files
29+
- output: artifactsDrop
30+
sourcePath: '$(Build.SourcesDirectory)\artifacts\official\OptProf\$(BuildConfiguration)\Data'
31+
dropServiceURI: 'https://devdiv.artifacts.visualstudio.com'
32+
dropMetadataContainerName: 'ProfilingInputs/DevDiv/$(Build.Repository.Name)/$(Build.SourceBranchName)/$(Build.BuildNumber)'
33+
condition: and(succeeded(), ${{ parameters.enableOptProf }})
34+
35+
# Publish bootstrapper info for OptProf data collection run to consume
36+
- output: buildArtifacts
37+
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\official\MicroBuild\Output'
38+
ArtifactName: MicroBuildOutputs
39+
40+
# RAINES TODO: switch to pipeline?
41+
- output: buildArtifacts
42+
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\official\log\$(BuildConfiguration)'
43+
ArtifactName: logs
44+
condition: always()
45+
46+
# Publish test configuration for OptProf data collection
47+
- output: buildArtifacts
48+
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\official\VSSetup\$(BuildConfiguration)'
49+
ArtifactName: VSSetup
50+
condition: and(succeeded(), ${{ parameters.enableOptProf }})
51+
52+
# Archive NuGet packages to DevOps.
53+
# Publish our NuPkgs as an artifact. The name of this artifact must be PackageArtifacts as the
54+
# arcade templates depend on the name.
55+
- output: buildArtifacts
56+
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\official\packages\$(BuildConfiguration)'
57+
ArtifactName: PackageArtifacts
58+
59+
# Publish "IntelliSense" XSD files to their own artifact
60+
# so it can be consumed by the insertion-to-VS job
61+
- output: pipelineArtifact
62+
targetPath: '$(Build.SourcesDirectory)\artifacts\official\xsd'
63+
artifactName: xsd
64+
65+
# Publish Asset Manifests for Build Asset Registry job
66+
- output: buildArtifacts
67+
PathtoPublish: '$(Build.SourcesDirectory)\artifacts\official\log\$(BuildConfiguration)\AssetManifest'
68+
ArtifactName: AssetManifests
69+
2570
variables:
2671
- group: Publish-Build-Assets
2772
- name: TeamName
@@ -106,17 +151,6 @@ jobs:
106151
# Required by Microsoft policy
107152
- template: /eng/common/templates-official/steps/generate-sbom.yml@self
108153

109-
# Publish OptProf configuration files
110-
- task: 1ES.PublishArtifactsDrop@1
111-
inputs:
112-
dropServiceURI: 'https://devdiv.artifacts.visualstudio.com'
113-
buildNumber: 'ProfilingInputs/DevDiv/$(Build.Repository.Name)/$(Build.SourceBranchName)/$(Build.BuildNumber)'
114-
sourcePath: '$(Build.SourcesDirectory)\artifacts\OptProf\$(BuildConfiguration)\Data'
115-
toLowerCase: false
116-
usePat: true
117-
displayName: 'OptProf - Publish to Artifact Services - ProfilingInputs'
118-
condition: and(succeeded(), ${{ parameters.enableOptProf }})
119-
120154
# Build VS bootstrapper
121155
# Generates $(Build.StagingDirectory)\MicroBuild\Output\BootstrapperInfo.json
122156
- task: MicroBuildBuildVSBootstrapper@3
@@ -140,22 +174,6 @@ jobs:
140174
displayName: 'OptProf - Build IBC training settings'
141175
condition: and(succeeded(), ${{ parameters.enableOptProf }})
142176

143-
# Publish bootstrapper info
144-
- task: 1ES.PublishBuildArtifacts@1
145-
inputs:
146-
PathtoPublish: $(Build.StagingDirectory)\MicroBuild\Output
147-
ArtifactName: MicroBuildOutputs
148-
ArtifactType: Container
149-
displayName: 'OptProf - Publish Artifact: MicroBuildOutputs'
150-
condition: succeeded()
151-
152-
- task: 1ES.PublishBuildArtifacts@1
153-
displayName: 'Publish Artifact: logs'
154-
inputs:
155-
PathtoPublish: 'artifacts\log\$(BuildConfiguration)'
156-
ArtifactName: logs
157-
condition: succeededOrFailed()
158-
159177
# Publishes setup VSIXes to a drop.
160178
# Note: The insertion tool looks for the display name of this task in the logs.
161179
- task: 1ES.MicroBuildVstsDrop@1
@@ -169,40 +187,69 @@ jobs:
169187
vsDropServiceUri: 'https://vsdrop.corp.microsoft.com/file/v1'
170188
condition: succeeded()
171189

172-
# Publish an artifact that the RoslynInsertionTool is able to find by its name.
173-
- task: 1ES.PublishBuildArtifacts@1
174-
displayName: 'Publish Artifact: VSSetup'
175-
inputs:
176-
PathtoPublish: 'artifacts\VSSetup\$(BuildConfiguration)'
177-
ArtifactName: VSSetup
178-
condition: succeeded()
190+
- pwsh: |
191+
$ErrorActionPreference = 'Stop'
179192
180-
# Archive NuGet packages to DevOps.
181-
# Publish our NuPkgs as an artifact. The name of this artifact must be PackageArtifacts as the
182-
# arcade templates depend on the name.
183-
- task: 1ES.PublishBuildArtifacts@1
184-
displayName: 'Publish Artifact: packages'
185-
inputs:
186-
PathtoPublish: 'artifacts\packages\$(BuildConfiguration)'
187-
ArtifactName: PackageArtifacts
188-
condition: succeeded()
193+
$sourceRoot = Join-Path '$(Build.SourcesDirectory)' 'artifacts'
194+
$targetRoot = Join-Path $sourceRoot 'official'
189195
190-
# Publish "IntelliSense" XSD files to their own artifact
191-
# so it can be consumed by the insertion-to-VS job
192-
- task: 1ES.PublishPipelineArtifact@1
193-
displayName: 'Publish Artifact: xsd'
194-
inputs:
195-
path: 'artifacts\xsd'
196-
artifactName: xsd
197-
condition: succeeded()
196+
if (-not (Test-Path $targetRoot)) {
197+
New-Item -Path $targetRoot -ItemType Directory | Out-Null
198+
}
198199
199-
# Publish Asset Manifests for Build Asset Registry job
200-
- task: 1ES.PublishBuildArtifacts@1
201-
displayName: Publish Asset Manifests
202-
inputs:
203-
PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(BuildConfiguration)/AssetManifest'
204-
ArtifactName: AssetManifests
205-
condition: succeeded()
200+
$paths = @(
201+
"log/$(BuildConfiguration)",
202+
"$(Build.StagingDirectory)/MicroBuild/Output",
203+
"packages/$(BuildConfiguration)",
204+
"xsd"
205+
)
206+
207+
if ("${{ parameters.enableOptProf }}" -eq "true") {
208+
$paths += "OptProf/$(BuildConfiguration)/Data"
209+
$paths += "VSSetup/$(BuildConfiguration)"
210+
}
211+
212+
$allpresent = $true
213+
214+
foreach ($path in $paths) {
215+
$from = [System.IO.Path]::Combine($sourceRoot, $path)
216+
217+
$destinationSubPath = if ($path -eq "$(Build.StagingDirectory)/MicroBuild/Output") {
218+
"MicroBuild/Output"
219+
} else {
220+
$path
221+
}
222+
223+
$to = Join-Path $targetRoot $destinationSubPath
224+
225+
Write-Host "Moving '$from' -> '$to'"
226+
227+
$parent = Split-Path $to -Parent
228+
if (-not (Test-Path $parent)) {
229+
New-Item -Path $parent -ItemType Directory -Force | Out-Null
230+
}
231+
232+
if (-not (Test-Path $from)) {
233+
Write-Host "##vso[task.logissue type=error]Source '$from' does not exist; skipping move for '$path'."
234+
$allpresent = $false
235+
continue
236+
}
237+
238+
$robocopyResult = & robocopy $from $to /E /MOVE /NFL /NDL /NJH /NJS /NP /MT:8
239+
$exitCode = $LASTEXITCODE
240+
if ($exitCode -ge 8) {
241+
$robocopyResult | Out-String | Write-Host
242+
throw "Robocopy failed with exit code $exitCode while moving '$path' to '$destinationSubPath'."
243+
}
244+
}
245+
246+
if (-not $allpresent) {
247+
throw "An expected output was not present."
248+
}
249+
250+
$global:LASTEXITCODE = 0
251+
displayName: 'Move build artifacts into official folder'
252+
condition: always()
206253
207254
# Tag the build at the very end when we know it's been successful.
208255
- task: colinsalmcorner.colinsalmcorner-buildtasks.tag-build-task.tagBuildOrRelease@0

0 commit comments

Comments
 (0)