Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
329 changes: 329 additions & 0 deletions .azure/pipelines/perf-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
#
# perf-build.yml
#
# Azure DevOps pipeline that builds every commit on `main` (and any other
# branches listed in the trigger) and uploads per-RID ASP.NET Core runtime
# packs to the Build Cache Service (BCS) so that dotnet/crank can resolve
# Microsoft.AspNetCore.App runtime binaries by commit SHA for
# performance-regression bisection.
#
# Modeled on dotnet/runtime's `eng/pipelines/performance/perf-build.yml`,
# including its three-stage shape:
#
# * RegisterBuild — runs in parallel with build; writes a tiny per-config
# buildInfo.json marker to BCS at
# builds/aspnetcore/buildArtifacts/{sha}/{configKey}/buildInfo.json.
# * build — produces per-RID Microsoft.AspNetCore.App.Runtime
# pipeline artifacts.
# * UploadArtifacts — depends on both; downloads each pipeline artifact
# and uploads it to
# builds/aspnetcore/buildArtifacts/{sha}/{configKey}/{archive}.
#
# The RegisterBuild and UploadArtifacts stages delegate to the shared
# dotnet/performance templates (`register-build-jobs.yml@performance` and
# `upload-build-artifacts-jobs.yml@performance`) — the same templates the
# runtime perf-build calls. Those templates were generalized in
# dotnet/performance to take an explicit `repoName` so non-runtime tenants
# (us) land under `builds/aspnetcore/...` instead of `builds/runtime/...`.
#
# This pipeline does NOT extend `1ES.Official.PipelineTemplate.yml`.
# Per-commit perf-build artifacts go to a private BCS cache (not redistributed
# / signed), so SDL/PoliCheck/TSA scans add no security value here. Matches
# runtime's perf-build which also runs as a plain (non-1ES) pipeline against
# the same `.NET Performance` Azure service connection.
#
# Atomicity contract: the MissingBuildsTrigger Azure Function only indexes
# Azure DevOps builds with overall Status == Succeeded. All stages run with
# the default `continueOnError: false`; any failure sinks the overall build
# to Failed and the Function skips indexing for that SHA. Operator retries
# the whole build green. The atomic unit for indexing is the AzDO build,
# not the per-config job.
#
# Output layout in BCS:
#
# builds/aspnetcore/buildArtifacts/{sha}/{configKey}/buildInfo.json
# builds/aspnetcore/buildArtifacts/{sha}/{configKey}/{archiveFile}
#
# Archive contents (lowercase directory names are a load-bearing contract
# — the future aspnetcore-overlay crank PR will FindDirectory on exactly
# `microsoft.aspnetcore.app.runtime.{rid}`):
#
# microsoft.aspnetcore.app.runtime.{rid}/
# Release/
# runtimes/{rid}/
# lib/net{X}.0/Microsoft.AspNetCore.*.dll
# native/aspnetcorev2*.dll (Windows only — ANCM/IIS bits)
#

# Build every individual commit (no batching). The MissingBuildsTrigger
# Azure Function then indexes succeeded builds into
# builds/aspnetcore/latest/{branch}/latestBuilds.json on its 8h tick.
trigger:
batch: false
branches:
include:
- main

# No PR validation in v1. This pipeline only produces meaningful output
# under internal+IndividualCI (real commits to mirrored branches). PR
# triggering is left for a follow-up once the security model around the
# `.NET Performance` service connection is settled.
pr: none

variables:
- name: _TeamName
value: AspNetCore

# Build-script arguments mirrored from ci.yml. We deliberately omit
# anything related to signing, installers, helix, or maestro publishing
# because none of those contribute to the per-RID runtime pack we ship to
# BCS.
- name: _BuildArgs
value: /p:TeamName=$(_TeamName)
/p:OfficialBuildId=$(Build.BuildNumber)
/p:SkipTestBuild=true
- name: _InternalRuntimeDownloadArgs
value: -RuntimeSourceFeed https://ci.dot.net/internal
-RuntimeSourceFeedKey $(dotnetbuilds-internal-container-read-token-base64)
/p:DotNetAssetRootAccessTokenSuffix='$(dotnetbuilds-internal-container-read-token-base64)'

- template: /eng/common/templates-official/variables/pool-providers.yml@self

resources:
repositories:
# dotnet/performance hosts the shared BCS upload templates that runtime's
# perf-build.yml also consumes. We reference its dnceng AzDO mirror
# (internal/dotnet-performance) so the templates resolve at pipeline
# compile time.
- repository: performance
type: git
name: internal/dotnet-performance

stages:

# ============================================================================
# RegisterBuild stage
#
# Writes a per-configKey buildInfo.json marker to BCS at:
# $web/builds/aspnetcore/buildArtifacts/{sha}/{configKey}/buildInfo.json
#
# Runs in parallel with the build stage (dependsOn: []) — the marker only
# encodes $(Build.BuildId), it doesn't need any build output. Mirrors
# dotnet/runtime's perf-build.yml structure so dashboards / cleanup tooling
# that reads buildInfo.json work uniformly across both repos.
#
# Same gate as UploadArtifacts (internal + IndividualCI/Manual).
# ============================================================================
- ${{ if and(ne(variables['System.TeamProject'], 'public'), or(eq(variables['Build.Reason'], 'IndividualCI'), eq(variables['Build.Reason'], 'Manual'))) }}:
- stage: RegisterBuild
displayName: 'Register Build'
dependsOn: []
jobs:
- template: /eng/pipelines/register-build-jobs.yml@performance
parameters:
performanceRepoAlias: performance
repoName: aspnetcore
buildType:
- aspnetcore_x64_linux
- aspnetcore_arm64_linux
- aspnetcore_x64_windows
- aspnetcore_arm64_windows
- aspnetcore_x86_windows

- stage: Build
displayName: Build
jobs:

# =====================================================================
# Windows multi-arch build job
#
# Mirrors ci.yml's Windows_build pattern: build.cmd is invoked three
# times in a single agent — x64 first (with native), then x86 and
# arm64 with -noBuildNative because they cross-pack against the x64
# native bits. Each invocation emits its own per-RID
# Microsoft.AspNetCore.App.Runtime.win-{arch}.{ver}.nupkg into the
# shared artifacts/packages/Release/Shipping/ directory.
#
# The afterBuild step delegates to the shared
# .azure/pipelines/tools/pack-bcs-archives.ps1 script (the single,
# canonical find-and-zip recipe used by every build job here), which
# unpacks each nupkg into the lowercase directory layout the future
# aspnetcore-overlay crank PR expects. It is invoked via `pwsh` (not
# Windows PowerShell 5.1) because 5.1's Compress-Archive writes
# backslash path separators, which would corrupt the archive for crank.
# =====================================================================
- template: .azure/pipelines/jobs/default-build.yml@self
parameters:
jobName: Windows_build
jobDisplayName: 'Build: Windows x64/x86/arm64 (perf-build)'
agentOs: Windows
installNodeJs: false

steps:
- script: ./eng/build.cmd
-ci
-prepareMachine
-nativeToolsOnMachine
-arch x64
-pack
-all
-noBuildJava
/p:OnlyPackPlatformSpecificPackages=true
$(_BuildArgs)
$(_InternalRuntimeDownloadArgs)
/bl:artifacts/log/Release/Build.x64.binlog
env:
MSBUILDUSESERVER: "1"
displayName: Build x64

- script: ./eng/build.cmd
-ci
-prepareMachine
-arch x86
-pack
-all
-noBuildJava
-noBuildNative
/p:OnlyPackPlatformSpecificPackages=true
$(_BuildArgs)
$(_InternalRuntimeDownloadArgs)
-ExcludeCIBinaryLog
env:
MSBUILDUSESERVER: "1"
displayName: Build x86

- script: ./eng/build.cmd
-ci
-prepareMachine
-arch arm64
-pack
-noBuildJava
-noBuildNative
/p:OnlyPackPlatformSpecificPackages=true
$(_BuildArgs)
$(_InternalRuntimeDownloadArgs)
/bl:artifacts/log/Release/Build.arm64.binlog
env:
MSBUILDUSESERVER: "1"
displayName: Build ARM64

afterBuild:
- pwsh: |
& "$(Build.SourcesDirectory)/.azure/pipelines/tools/pack-bcs-archives.ps1" -Rids win-x64,win-x86,win-arm64 -Format zip
displayName: 'Pack BCS archives (win-x64 / win-x86 / win-arm64)'

artifacts:
- name: BuildArtifacts_windows_x64_Release_aspnetcore
path: $(Build.ArtifactStagingDirectory)/bcs/BuildArtifacts_windows_x64_Release_aspnetcore
- name: BuildArtifacts_windows_x86_Release_aspnetcore
path: $(Build.ArtifactStagingDirectory)/bcs/BuildArtifacts_windows_x86_Release_aspnetcore
- name: BuildArtifacts_windows_arm64_Release_aspnetcore
path: $(Build.ArtifactStagingDirectory)/bcs/BuildArtifacts_windows_arm64_Release_aspnetcore
- name: Windows_perf_build_Logs_Attempt_$(System.JobAttempt)
path: artifacts/log/
publishOnError: true
includeForks: true

# =====================================================================
# Linux x64 build job
# =====================================================================
- template: .azure/pipelines/jobs/default-build.yml@self
parameters:
jobName: Linux_x64_build
jobDisplayName: 'Build: Linux x64 (perf-build)'
agentOs: Linux
use1ESUbuntu: true
installNodeJs: false
buildArgs:
--arch x64
--pack
--all
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
$(_BuildArgs)
$(_InternalRuntimeDownloadArgs)
afterBuild:
- pwsh: |
& "$(Build.SourcesDirectory)/.azure/pipelines/tools/pack-bcs-archives.ps1" -Rids linux-x64 -Format targz
displayName: 'Pack BCS archive (linux-x64)'

artifacts:
- name: BuildArtifacts_linux_x64_Release_aspnetcore
path: $(Build.ArtifactStagingDirectory)/bcs/BuildArtifacts_linux_x64_Release_aspnetcore
- name: Linux_x64_perf_build_Logs_Attempt_$(System.JobAttempt)
path: artifacts/log/
publishOnError: true
includeForks: true

# =====================================================================
# Linux arm64 build job (cross-build from x64 host)
# =====================================================================
- template: .azure/pipelines/jobs/default-build.yml@self
parameters:
jobName: Linux_arm64_build
jobDisplayName: 'Build: Linux ARM64 (perf-build)'
agentOs: Linux
use1ESUbuntu: true
installNodeJs: false
buildArgs:
--arch arm64
--pack
--all
--no-build-java
-p:OnlyPackPlatformSpecificPackages=true
$(_BuildArgs)
$(_InternalRuntimeDownloadArgs)
afterBuild:
- pwsh: |
& "$(Build.SourcesDirectory)/.azure/pipelines/tools/pack-bcs-archives.ps1" -Rids linux-arm64 -Format targz
displayName: 'Pack BCS archive (linux-arm64)'

artifacts:
- name: BuildArtifacts_linux_arm64_Release_aspnetcore
path: $(Build.ArtifactStagingDirectory)/bcs/BuildArtifacts_linux_arm64_Release_aspnetcore
- name: Linux_arm64_perf_build_Logs_Attempt_$(System.JobAttempt)
path: artifacts/log/
publishOnError: true
includeForks: true

# ==========================================================================
# ============================================================================
# UploadArtifacts stage
#
# Delegates to dotnet/performance's `upload-build-artifacts-jobs.yml`
# dispatcher (the same template runtime's perf-build.yml calls), which
# fans out into per-configKey `templates/upload-build-artifacts-job.yml`
# invocations that each:
#
# 1. Download the matching pipeline artifact from the Build stage.
# 2. `az storage blob upload` it to:
# $web/builds/aspnetcore/buildArtifacts/{sha}/{configKey}/{file}
#
# Depends on both build and RegisterBuild so the upload only proceeds once
# both the archives and the buildInfo.json markers are in flight. `condition:
# succeeded()` means any build / RegisterBuild failure sinks the overall
# AzDO build to Failed, and the MissingBuildsTrigger Function skips
# indexing for this SHA (whole-pipeline-indexing contract).
#
# Gated to internal + (IndividualCI | Manual). IndividualCI covers the
# steady-state per-commit flow; Manual covers the runbook's "queue one
# seed run" step.
# ============================================================================
- ${{ if and(ne(variables['System.TeamProject'], 'public'), or(eq(variables['Build.Reason'], 'IndividualCI'), eq(variables['Build.Reason'], 'Manual'))) }}:
- stage: UploadArtifacts
displayName: 'Upload Artifacts to BCS'
dependsOn:
- Build
- RegisterBuild
condition: succeeded()
jobs:
- template: /eng/pipelines/upload-build-artifacts-jobs.yml@performance
parameters:
performanceRepoAlias: performance
repoName: aspnetcore
buildType:
- aspnetcore_x64_linux
- aspnetcore_arm64_linux
- aspnetcore_x64_windows
- aspnetcore_arm64_windows
- aspnetcore_x86_windows
Loading