Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
136 changes: 86 additions & 50 deletions eng/common/pipelines/templates/jobs/generate-job-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ parameters:
- name: PreGenerationSteps
type: stepList
default: []
- name: EnablePRGeneration
type: boolean
default: false
- name: PRMatrixSetting
type: string
default: 'ArtifactPackageNames'
# Mappings to OS name required at template compile time by 1es pipeline templates
- name: Pools
type: object
Expand Down Expand Up @@ -84,57 +90,87 @@ jobs:

- ${{ parameters.PreGenerationSteps }}

- ${{ each config in parameters.MatrixConfigs }}:
- ${{ if eq(parameters.EnablePRGeneration, false) }}:
- ${{ each config in parameters.MatrixConfigs }}:
- ${{ each pool in parameters.Pools }}:
- ${{ if eq(config.GenerateVMJobs, 'true') }}:
- task: Powershell@2
inputs:
pwsh: true
filePath: eng/common/scripts/job-matrix/Create-JobMatrix.ps1
arguments: >
-ConfigPath ${{ config.Path }}
-Selection ${{ config.Selection }}
-DisplayNameFilter '$(displayNameFilter)'
-Filters '${{ join(''',''', parameters.MatrixFilters) }}', 'container=^$', 'SupportedClouds=^$|${{ parameters.CloudConfig.Cloud }}', 'Pool=${{ pool.filter }}'
-Replace '${{ join(''',''', parameters.MatrixReplace) }}'
-NonSparseParameters '${{ join(''',''', config.NonSparseParameters) }}'
displayName: Create ${{ pool.name }} Matrix ${{ config.Name }}
name: vm_job_matrix_${{ config.Name }}_${{ pool.name }}
- ${{ if eq(config.GenerateContainerJobs, 'true') }}:
- task: Powershell@2
inputs:
pwsh: true
filePath: eng/common/scripts/job-matrix/Create-JobMatrix.ps1
arguments: >
-ConfigPath ${{ config.Path }}
-Selection ${{ config.Selection }}
-DisplayNameFilter '$(displayNameFilter)'
-Filters '${{ join(''',''', parameters.MatrixFilters) }}', 'container=^$', 'SupportedClouds=^$|${{ parameters.CloudConfig.Cloud }}', 'Pool=${{ pool.filter }}'
-NonSparseParameters '${{ join(''',''', config.NonSparseParameters) }}'
displayName: Create ${{ pool.name }} Container Matrix ${{ config.Name }}
name: container_job_matrix_${{ config.Name }}_${{ pool.name }}

# This else being set also currently assumes that the $(Build.ArtifactStagingDirectory)/PackageInfo folder is populated by PreGenerationSteps.
# Not currently not hardcoded, so not doing the needful and populating this folder before we hit this step will result in generation errors.
- ${{ else }}:
- ${{ each pool in parameters.Pools }}:
- ${{ if eq(config.GenerateVMJobs, 'true') }}:
- task: Powershell@2
inputs:
pwsh: true
filePath: eng/common/scripts/job-matrix/Create-JobMatrix.ps1
arguments: >
-ConfigPath ${{ config.Path }}
-Selection ${{ config.Selection }}
-DisplayNameFilter '$(displayNameFilter)'
-Filters '${{ join(''',''', parameters.MatrixFilters) }}', 'container=^$', 'SupportedClouds=^$|${{ parameters.CloudConfig.Cloud }}', 'Pool=${{ pool.filter }}'
-Replace '${{ join(''',''', parameters.MatrixReplace) }}'
-NonSparseParameters '${{ join(''',''', config.NonSparseParameters) }}'
displayName: Create ${{ pool.name }} Matrix ${{ config.Name }}
name: vm_job_matrix_${{ config.Name }}_${{ pool.name }}
- pwsh: |
# dump the conglomerated CI matrix
'${{ convertToJson(parameters.MatrixConfigs) }}' | Set-Content matrix.json

- ${{ if eq(config.GenerateContainerJobs, 'true') }}:
- task: Powershell@2
inputs:
pwsh: true
filePath: eng/common/scripts/job-matrix/Create-JobMatrix.ps1
arguments: >
-ConfigPath ${{ config.Path }}
-Selection ${{ config.Selection }}
-DisplayNameFilter '$(displayNameFilter)'
-Filters '${{ join(''',''', parameters.MatrixFilters) }}', 'container=^$', 'SupportedClouds=^$|${{ parameters.CloudConfig.Cloud }}', 'Pool=${{ pool.filter }}'
-NonSparseParameters '${{ join(''',''', config.NonSparseParameters) }}'
displayName: Create ${{ pool.name }} Container Matrix ${{ config.Name }}
name: container_job_matrix_${{ config.Name }}_${{ pool.name }}
./eng/common/scripts/job-matrix/Create-PrJobMatrix.ps1 `
-PackagePropertiesFolder $(Build.ArtifactStagingDirectory)/PackageInfo `
-PRMatrixFile matrix.json `
-PRMatrixSetting ${{ parameters.PRMatrixSetting }} `
-DisplayNameFilter '$(displayNameFilter)' `
-Filters '${{ join(''',''', parameters.MatrixFilters) }}', 'container=^$', 'SupportedClouds=^$|${{ parameters.CloudConfig.Cloud }}', 'Pool=${{ pool.filter }}' `
-Replace '${{ join(''',''', parameters.MatrixReplace) }}'
displayName: Create ${{ pool.name }} PR Matrix
name: vm_job_matrix_pr_${{ pool.name }}

- ${{ each config in parameters.MatrixConfigs }}:
- ${{ each pool in parameters.Pools }}:
- ${{ if eq(config.GenerateVMJobs, 'true') }}:
- template: ${{ parameters.JobTemplatePath }}
parameters:
UsePlatformContainer: false
OSName: ${{ pool.os }}
Matrix: dependencies.${{ parameters.GenerateJobName }}.outputs['vm_job_matrix_${{ config.Name }}_${{ pool.name }}.matrix']
DependsOn: ${{ parameters.GenerateJobName }}
CloudConfig: ${{ parameters.CloudConfig }}
${{ each param in parameters.AdditionalParameters }}:
${{ param.key }}: ${{ param.value }}
- ${{ if eq(parameters.EnablePRGeneration, false) }}:
- ${{ each config in parameters.MatrixConfigs }}:
- ${{ each pool in parameters.Pools }}:
- ${{ if eq(config.GenerateVMJobs, 'true') }}:
- template: ${{ parameters.JobTemplatePath }}
parameters:
UsePlatformContainer: false
OSName: ${{ pool.os }}
Matrix: dependencies.${{ parameters.GenerateJobName }}.outputs['vm_job_matrix_${{ config.Name }}_${{ pool.name }}.matrix']
DependsOn: ${{ parameters.GenerateJobName }}
CloudConfig: ${{ parameters.CloudConfig }}
${{ each param in parameters.AdditionalParameters }}:
${{ param.key }}: ${{ param.value }}

- ${{ if eq(config.GenerateContainerJobs, 'true') }}:
- template: ${{ parameters.JobTemplatePath }}
parameters:
UsePlatformContainer: true
OSName: ${{ pool.os }}
Matrix: dependencies.${{ parameters.GenerateJobName }}.outputs['vm_job_matrix_${{ config.Name }}_${{ pool.name }}.matrix']
DependsOn: ${{ parameters.GenerateJobName }}
CloudConfig: ${{ parameters.CloudConfig }}
${{ each param in parameters.AdditionalParameters }}:
${{ param.key }}: ${{ param.value }}
- ${{ if eq(config.GenerateContainerJobs, 'true') }}:
- template: ${{ parameters.JobTemplatePath }}
parameters:
UsePlatformContainer: true
OSName: ${{ pool.os }}
Matrix: dependencies.${{ parameters.GenerateJobName }}.outputs['vm_job_matrix_${{ config.Name }}_${{ pool.name }}.matrix']
DependsOn: ${{ parameters.GenerateJobName }}
CloudConfig: ${{ parameters.CloudConfig }}
${{ each param in parameters.AdditionalParameters }}:
${{ param.key }}: ${{ param.value }}
- ${{ else }}:
- ${{ each pool in parameters.Pools }}:
- template: ${{ parameters.JobTemplatePath }}
parameters:
UsePlatformContainer: false
OSName: ${{ pool.os }}
Matrix: dependencies.${{ parameters.GenerateJobName }}.outputs['vm_job_matrix_pr_${{ pool.name }}.matrix']
DependsOn: ${{ parameters.GenerateJobName }}
CloudConfig: ${{ parameters.CloudConfig }}
${{ each param in parameters.AdditionalParameters }}:
${{ param.key }}: ${{ param.value }}
80 changes: 78 additions & 2 deletions eng/common/scripts/Helpers/Package-Helpers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,86 @@ function GetValueSafelyFrom-Yaml {
$current = $current[$key]
}
else {
Write-Host "The '$key' part of the path $($Keys -join "/") doesn't exist or is null."
Copy link
Member Author

@scbedd scbedd Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JimSuplizio FYI I know you did like this output.

This is very spammy when invoking for MatrixConfigs, as it is mostly null. I think that if the caller wants there to be a message about $null, they can log it.

return $null
}
}

return [object]$current
}
}

function Get-ObjectKey {
param (
[Parameter(Mandatory = $true)]
[object]$Object
)

if (-not $Object) {
return "unset"
}

if ($Object -is [hashtable] -or $Object -is [System.Collections.Specialized.OrderedDictionary]) {
$sortedEntries = $Object.GetEnumerator() | Sort-Object Name
$hashString = ($sortedEntries | ForEach-Object { "$($_.Key)=$($_.Value)" }) -join ";"
return $hashString.GetHashCode()
}

elseif ($Object -is [PSCustomObject]) {
$sortedProperties = $Object.PSObject.Properties | Sort-Object Name
$propertyString = ($sortedProperties | ForEach-Object { "$($_.Name)=$($_.Value)" }) -join ";"
return $propertyString.GetHashCode()
}

elseif ($Object -is [array]) {
$arrayString = ($Object | ForEach-Object { Get-ObjectKey $_ }) -join ";"
return $arrayString.GetHashCode()
}

else {
return $Object.GetHashCode()
}
}

function Group-ByObjectKey {
param (
[Parameter(Mandatory)]
[array]$Items,

[Parameter(Mandatory)]
[string]$GroupByProperty
)

$groupedDictionary = @{}

foreach ($item in $Items) {
$key = Get-ObjectKey $item."$GroupByProperty"

if (-not $groupedDictionary.ContainsKey($key)) {
$groupedDictionary[$key] = @()
}

# Add the current item to the array for this key
$groupedDictionary[$key] += $item
}

return $groupedDictionary
}

function Split-ArrayIntoBatches {
param (
[Parameter(Mandatory = $true)]
[Object[]]$InputArray,

[Parameter(Mandatory = $true)]
[int]$BatchSize
)

$batches = @()

for ($i = 0; $i -lt $InputArray.Count; $i += $BatchSize) {
$batch = $InputArray[$i..[math]::Min($i + $BatchSize - 1, $InputArray.Count - 1)]

$batches += , $batch
}

return , $batches
}
24 changes: 20 additions & 4 deletions eng/common/scripts/Package-Properties.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class PackageProps
# additional packages required for validation of this one
[string[]]$AdditionalValidationPackages
[HashTable]$ArtifactDetails
[HashTable[]]$CIMatrixConfigs

PackageProps([string]$name, [string]$version, [string]$directoryPath, [string]$serviceDirectory)
{
Expand Down Expand Up @@ -84,8 +85,7 @@ class PackageProps
$this.Group = $group
}

hidden [HashTable]ParseYmlForArtifact([string]$ymlPath) {

hidden [PSCustomObject]ParseYmlForArtifact([string]$ymlPath) {
$content = LoadFrom-Yaml $ymlPath
if ($content) {
$artifacts = GetValueSafelyFrom-Yaml $content @("extends", "parameters", "Artifacts")
Expand All @@ -95,8 +95,21 @@ class PackageProps
$artifactForCurrentPackage = $artifacts | Where-Object { $_["name"] -eq $this.ArtifactName -or $_["name"] -eq $this.Name }
}

# if we found an artifact for the current package, we should count this ci file as the source of the matrix for this package
if ($artifactForCurrentPackage) {
return [HashTable]$artifactForCurrentPackage
$result = [PSCustomObject]@{
ArtifactConfig = [HashTable]$artifactForCurrentPackage
MatrixConfigs = @()
}

# if we know this is the matrix for our file, we should now see if there is a custom matrix config for the package
$matrixConfigList = GetValueSafelyFrom-Yaml $content @("extends", "parameters", "MatrixConfigs")

if ($matrixConfigList) {
$result.MatrixConfigs = matrixConfigList
}

return $result
}
}
return $null
Expand All @@ -112,7 +125,10 @@ class PackageProps
foreach($ciFile in $ciFiles) {
$ciArtifactResult = $this.ParseYmlForArtifact($ciFile.FullName)
if ($ciArtifactResult) {
$this.ArtifactDetails = [Hashtable]$ciArtifactResult
$this.ArtifactDetails = [Hashtable]$ciArtifactResult.ArtifactConfig
$this.CIMatrixConfigs = $ciArtifactResult.MatrixConfigs
# if this package appeared in this ci file, then we should
# treat this CI file as the source of the Matrix for this package
break
}
}
Expand Down
Loading