188 lines
9.4 KiB
YAML
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'], ''))
|