dotnet-docker/eng/common/templates/jobs/build-images.yml
2023-05-18 17:14:23 +08:00

188 lines
9.4 KiB
YAML

parameters:
name: null
pool: {}
matrix: {}
dockerClientOS: null
buildJobTimeout: 60
customInitSteps: []
noCache: false
internalProjectName: null
publicProjectName: null
internalVersionsRepoRef: null
publicVersionsRepoRef: null
jobs:
- job: ${{ parameters.name }}
condition: and(${{ parameters.matrix }}, not(canceled()), in(dependencies.PreBuildValidation.result, 'Succeeded', 'SucceededWithIssues', 'Skipped'))
dependsOn:
- PreBuildValidation
- CopyBaseImages
- GenerateBuildMatrix
pool: ${{ parameters.pool }}
strategy:
matrix: $[ ${{ parameters.matrix }} ]
timeoutInMinutes: ${{ parameters.buildJobTimeout }}
variables:
imageBuilderDockerRunExtraOptions: $(build.imageBuilderDockerRunExtraOptions)
versionsRepoPath: versions
sbomDirectory: $(Build.ArtifactStagingDirectory)/sbom
${{ if eq(parameters.noCache, false) }}:
versionsBasePath: $(versionsRepoPath)/
pipelineDisabledCache: false
${{ if eq(parameters.noCache, true) }}:
versionsBasePath: ""
pipelineDisabledCache: true
steps:
- checkout: self
- ${{ if and(eq(variables['System.TeamProject'], parameters.publicProjectName), eq(parameters.noCache, false)) }}:
- checkout: ${{ parameters.publicVersionsRepoRef }}
path: s/$(versionsRepoPath)
- ${{ if and(eq(variables['System.TeamProject'], parameters.internalProjectName), eq(parameters.noCache, false)) }}:
- checkout: ${{ parameters.internalVersionsRepoRef }}
path: s/$(versionsRepoPath)
- ${{ if eq(parameters.noCache, false) }}:
- powershell: |
$pathSeparatorIndex = "$(Build.Repository.Name)".IndexOf("/")
if ($pathSeparatorIndex -ge 0) {
$buildRepoName = "$(Build.Repository.Name)".Substring($pathSeparatorIndex + 1)
}
else {
$buildRepoName = "$(Build.Repository.Name)"
}
$engCommonPath = "$(Build.Repository.LocalPath)/$buildRepoName/$(engCommonRelativePath)"
$engPath = "$(Build.Repository.LocalPath)/$buildRepoName/eng"
$manifest = "$buildRepoName/$(manifest)"
$testResultsDirectory = "$buildRepoName/$testResultsDirectory"
if ("$(testScriptPath)") {
$testScriptPath = "$buildRepoName/$(testScriptPath)"
}
echo "##vso[task.setvariable variable=buildRepoName]$buildRepoName"
echo "##vso[task.setvariable variable=manifest]$manifest"
echo "##vso[task.setvariable variable=engCommonPath]$engCommonPath"
echo "##vso[task.setvariable variable=engPath]$engPath"
echo "##vso[task.setvariable variable=testScriptPath]$testScriptPath"
echo "##vso[task.setvariable variable=testResultsDirectory]$testResultsDirectory"
displayName: Override Common Paths
- powershell: |
if ("${{ parameters.noCache }}" -eq "false") {
$baseContainerRepoPath = "/repo/$(buildRepoName)"
}
else {
$baseContainerRepoPath = "/repo"
}
echo "##vso[task.setvariable variable=baseContainerRepoPath]$baseContainerRepoPath"
displayName: Set Base Container Repo Path
- template: ${{ format('../steps/init-docker-{0}.yml', parameters.dockerClientOS) }}
- ${{ parameters.customInitSteps }}
- template: ../steps/set-image-info-path-var.yml
parameters:
publicSourceBranch: $(publicSourceBranch)
- powershell: echo "##vso[task.setvariable variable=imageBuilderBuildArgs]"
condition: eq(variables.imageBuilderBuildArgs, '')
displayName: Initialize Image Builder Build Args
- powershell: |
# Reference the existing imageBuilderBuildArgs variable as an environment variable rather than injecting it directly
# with the $(imageBuilderBuildArgs) syntax. This is to avoid issues where the string may contain single quotes $ chars
# which really mess up assigning to a variable. It would require assigning the string with single quotes but also needing
# to escape the single quotes that are in the string which would need to be done outside the context of PowerShell. Since
# all we need is for that value to be in a PowerShell variable, we can get that by the fact that AzDO automatically creates
# the environment variable for us.
$imageBuilderBuildArgs = "$env:IMAGEBUILDERBUILDARGS $(imageBuilder.queueArgs) --image-info-output-path $(artifactsPath)/$(legName)-image-info.json"
if ($env:SYSTEM_TEAMPROJECT -eq "${{ parameters.internalProjectName }}" -and $env:BUILD_REASON -ne "PullRequest") {
$imageBuilderBuildArgs = "$imageBuilderBuildArgs --registry-override $(acr.server) --repo-prefix $(stagingRepoPrefix) --source-repo-prefix $(mirrorRepoPrefix) --push --registry-creds ""$(acr.server)=$(acr.userName);$(acr.password)"""
}
# If the pipeline isn't configured to disable the cache and a build variable hasn't been set to disable the cache
if ("$(pipelineDisabledCache)" -ne "true" -and $env:NOCACHE -ne "true") {
$imageBuilderBuildArgs = "$imageBuilderBuildArgs --image-info-source-path $(versionsBasePath)$(imageInfoVersionsPath)"
}
echo "##vso[task.setvariable variable=imageBuilderBuildArgs]$imageBuilderBuildArgs"
displayName: Set Image Builder Build Args
- powershell: >
$(runImageBuilderCmd) build
--manifest $(manifest)
$(imageBuilderPaths)
$(osVersions)
--os-type $(osType)
--architecture $(architecture)
--retry
--source-repo $(publicGitRepoUri)
--digests-out-var 'builtImages'
--acr-subscription '$(acr.subscription)'
--acr-resource-group '$(acr.resourceGroup)'
--acr-client-id '$(acr.servicePrincipalName)'
--acr-password '$(acr.servicePrincipalPassword)'
--acr-tenant '$(acr.servicePrincipalTenant)'
$(manifestVariables)
$(imageBuilderBuildArgs)
name: BuildImages
displayName: Build Images
- publish: $(Build.ArtifactStagingDirectory)/$(legName)-image-info.json
artifact: $(legName)-image-info-$(System.JobAttempt)
displayName: Publish Image Info File Artifact
- ${{ if and(eq(variables['System.TeamProject'], parameters.internalProjectName), ne(variables['Build.Reason'], 'PullRequest')) }}:
# Define the task here to load it into the agent so that we can invoke the tool manually
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
inputs:
BuildDropPath: $(Build.ArtifactStagingDirectory)
displayName: Load Manifest Generator
condition: and(succeeded(), ne(variables['BuildImages.builtImages'], ''))
- powershell: |
$images = "$(BuildImages.builtImages)"
if (-not $images) { return 0 }
# There can be leftover versions of the task left on the agent if it's not fresh. So find the latest version.
$taskDir = $(Get-ChildItem -Recurse -Directory -Filter "ManifestGeneratorTask*" -Path '$(Agent.WorkFolder)')[-1].FullName
$manifestToolDllPath = $(Get-ChildItem -Recurse -File -Filter "Microsoft.ManifestTool.dll" -Path $taskDir).FullName
# Check whether the manifest task installed its own version of .NET.
# To be more robust, we'll handle varying implementations that it's had.
# First check for a dotnet folder in the task location
$dotnetDir = $(Get-ChildItem -Recurse -Directory -Filter "dotnet-*" -Path $taskDir).FullName
if (-not $dotnetDir) {
# If it's not there, check in the agent tools location
$dotnetDir = $(Get-ChildItem -Recurse -Directory -Filter "*dotnet-*" -Path "$(Agent.ToolsDirectory)").FullName
}
# If the manifest task installed its own version of .NET use that; otherwise it's reusing an existing install of .NET
# which is executable by default.
if ($dotnetDir) {
$dotnetPath = "$dotnetDir/dotnet"
}
else {
$dotnetPath = "dotnet"
}
# Call the manifest tool for each image to produce seperate SBOMs
# Manifest tool docs: https://eng.ms/docs/cloud-ai-platform/devdiv/one-engineering-system-1es/1es-docs/secure-supply-chain/custom-sbom-generation-workflows
$images -Split ',' | ForEach-Object {
echo "Generating SBOM for $_";
$formattedImageName = $_.Replace('$(acr.server)/$(stagingRepoPrefix)', "").Replace('/', '_').Replace(':', '_');
$sbomChildDir = "$(sbomDirectory)/$formattedImageName";
New-Item -Type Directory -Path $sbomChildDir > $null;
& $dotnetPath "$manifestToolDllPath" `
Generate `
-BuildDropPath '$(Build.ArtifactStagingDirectory)' `
-BuildComponentPath '$(Agent.BuildDirectory)' `
-PackageName '.NET' `
-PackageVersion '$(Build.BuildNumber)' `
-ManifestDirPath $sbomChildDir `
-DockerImagesToScan $_ `
-Verbosity Information
}
displayName: Generate SBOMs
condition: and(succeeded(), ne(variables['BuildImages.builtImages'], ''))
- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
- template: ${{ format('../steps/test-images-{0}-client.yml', parameters.dockerClientOS) }}
parameters:
condition: ne(variables.testScriptPath, '')
- template: ${{ format('../steps/cleanup-docker-{0}.yml', parameters.dockerClientOS) }}
- ${{ if and(eq(variables['System.TeamProject'], parameters.internalProjectName), ne(variables['Build.Reason'], 'PullRequest')) }}:
- publish: $(sbomDirectory)
artifact: $(legName)-sboms
displayName: Publish SBOM
condition: and(succeeded(), ne(variables['BuildImages.builtImages'], ''))