Skip to content

Commit 3ecd831

Browse files
authored
Support resolving environment variable references in matrix config (#7682)
* Support resolving environment variable references in matrix config * Improve type and null handling * Fix reference bug * Change behavior on missing env vars to throw
1 parent 481137c commit 3ecd831

4 files changed

Lines changed: 254 additions & 108 deletions

File tree

doc/common/matrix_generator.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* [all](#all)
1818
* [sparse](#sparse)
1919
* [include/exclude](#includeexclude)
20+
* [Environment Variable References](#environment-variable-references)
2021
* [Generated display name](#generated-display-name)
2122
* [Filters](#filters)
2223
* [Replace/Modify/Append](#replacemodifyappend-values)
@@ -512,6 +513,29 @@ will be generated, but the full matrix of both include and exclude will be proce
512513
Excludes are processed first, so includes can be used to forcefully add specific combinations to the matrix,
513514
regardless of exclusions.
514515

516+
### Environment Variable References
517+
518+
The matrix config supports values that reference environment variables and resolves them at
519+
matrix generation time. This is useful especially in pipeline scenarios where we want to reference
520+
common values that are defined elsewhere in the environment and/or pipeline config.
521+
522+
Prefix a matrix value with `env:` to trigger an environment variable
523+
lookup. If the variable does not exist, then the value will resolve to empty string.
524+
525+
For example:
526+
527+
``` yaml
528+
{
529+
"net461_macOS1015": {
530+
"framework": "net461",
531+
"operatingSystem": "env:OperatingSystem"
532+
}
533+
}
534+
```
535+
536+
Matrix filters and replace parameters evaluate before environment variables are resolved. Matrix
537+
display name renames and display name filters evaluate after variables are resolved.
538+
515539
### Generated display name
516540

517541
In the matrix job output that azure pipelines consumes, the format is a map of maps. For example:

eng/common-tests/matrix-generator/tests/job-matrix-functions.modification.tests.ps1

Lines changed: 110 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Import-Module Pester
22

33

44
BeforeAll {
5-
. $PSScriptRoot/../../../common/scripts/job-matrix/job-matrix-functions.ps1
5+
. $PSScriptRoot/../../../common/scripts/job-matrix/job-matrix-functions.ps1
66

77
function CompareMatrices([Array]$matrix, [Array]$expected) {
88
$matrix.Length | Should -Be $expected.Length
@@ -33,25 +33,25 @@ Describe "Platform Matrix nonSparse" -Tag "UnitTest", "nonsparse" {
3333
}
3434

3535
It "Should process nonSparse parameters" {
36-
$parameters, $nonSparse = ProcessNonSparseParameters $config.matrixParameters "testField1","testField3"
36+
$parameters, $nonSparse = ProcessNonSparseParameters $config.matrixParameters "testField1", "testField3"
3737

3838
$parameters.Count | Should -Be 1
3939
$parameters[0].Name | Should -Be "testField2"
40-
$parameters[0].Value | Should -Be 1,2,3
40+
$parameters[0].Value | Should -Be 1, 2, 3
4141

4242
$nonSparse.Count | Should -Be 2
4343
$nonSparse[0].Name | Should -Be "testField1"
44-
$nonSparse[0].Value | Should -Be 1,2
44+
$nonSparse[0].Value | Should -Be 1, 2
4545
$nonSparse[1].Name | Should -Be "testField3"
46-
$nonSparse[1].Value | Should -Be 1,2,3,4
46+
$nonSparse[1].Value | Should -Be 1, 2, 3, 4
4747

4848
$parameters, $nonSparse = ProcessNonSparseParameters $config.matrixParameters "testField3"
4949
$parameters.Count | Should -Be 2
5050
($parameters).Name -match "testField3" | Should -Be $null
5151

5252
$nonSparse.Count | Should -Be 1
5353
$nonSparse[0].Name | Should -Be "testField3"
54-
$nonSparse[0].Value | Should -Be 1,2,3,4
54+
$nonSparse[0].Value | Should -Be 1, 2, 3, 4
5555
}
5656

5757
It "Should ignore nonSparse with all selection" {
@@ -77,10 +77,10 @@ Describe "Platform Matrix nonSparse" -Tag "UnitTest", "nonsparse" {
7777
'@
7878
$config = GetMatrixConfigFromJson $matrixJson
7979

80-
$matrix = GenerateMatrix $config "all" -nonSparseParameters "testField3","testField4"
80+
$matrix = GenerateMatrix $config "all" -nonSparseParameters "testField3", "testField4"
8181
$matrix.Length | Should -Be 16
8282

83-
$matrix = GenerateMatrix $config "sparse" -nonSparseParameters "testField3","testField4"
83+
$matrix = GenerateMatrix $config "sparse" -nonSparseParameters "testField3", "testField4"
8484
$matrix.Length | Should -Be 8
8585
}
8686

@@ -125,13 +125,13 @@ Describe "Platform Matrix nonSparse" -Tag "UnitTest", "nonsparse" {
125125
}
126126
}
127127

128-
# This test is currently disabled (it doesn't have "UnitTest" tag) as it fails
128+
# This test is currently disabled (it doesn't have "UnitTest" tag) as it fails
129129
# in test "Should generate a sparse matrix where the entire base matrix is imported" on line:
130130
#
131131
# $matrix = GenerateMatrix $importConfig "sparse"
132132
#
133133
# with message:
134-
#
134+
#
135135
# ParameterBindingArgumentTransformationException: Cannot process argument transformation on parameter 'parameters'. Cannot convert the "System.Collections.Hashtable" value of type "System.Collections.Hashtable" to type "MatrixParameter".
136136
#
137137
# See full build failure:
@@ -392,11 +392,11 @@ Describe "Platform Matrix Import" -Tag "import" {
392392

393393
Describe "Platform Matrix Replace" -Tag "UnitTest", "replace" {
394394
It "Should parse replacement syntax" -TestCases @(
395-
@{ query = 'foo=bar/baz'; key = '^foo$'; value = '^bar$'; replace = 'baz' },
396-
@{ query = 'foo=\/p:bar/\/p:baz'; key = '^foo$'; value = '^\/p:bar$'; replace = '/p:baz' },
397-
@{ query = 'f\=o\/o=\/p:b\=ar/\/p:b\=az'; key = '^f\=o\/o$'; value = '^\/p:b\=ar$'; replace = '/p:b=az' },
398-
@{ query = 'foo=bar/'; key = '^foo$'; value = '^bar$'; replace = '' },
399-
@{ query = 'foo=/baz'; key = '^foo$'; value = '^$'; replace = 'baz' }
395+
@{ query = 'foo=bar/baz'; key = '^foo$'; value = '^bar$'; replace = 'baz' },
396+
@{ query = 'foo=\/p:bar/\/p:baz'; key = '^foo$'; value = '^\/p:bar$'; replace = '/p:baz' },
397+
@{ query = 'f\=o\/o=\/p:b\=ar/\/p:b\=az'; key = '^f\=o\/o$'; value = '^\/p:b\=ar$'; replace = '/p:b=az' },
398+
@{ query = 'foo=bar/'; key = '^foo$'; value = '^bar$'; replace = '' },
399+
@{ query = 'foo=/baz'; key = '^foo$'; value = '^$'; replace = 'baz' }
400400
) {
401401
$parsed = ParseReplacement $query
402402
$parsed.key | Should -Be $key
@@ -582,5 +582,100 @@ Describe "Platform Matrix Replace" -Tag "UnitTest", "replace" {
582582
$matrix[2].parameters.Baz | Should -Be "importedBaz"
583583
$matrix[2].parameters.replaceme | Should -Be "replaceme"
584584
}
585+
}
585586

587+
Describe "Platform Matrix Environment Variables" -Tag "UnitTest", "envvar" {
588+
It "Should parse environment variable reference syntax" {
589+
$matrixJson = @'
590+
{
591+
"matrix": {
592+
"foo": "bar",
593+
"envReference": ["env:TestMatrixEnvReference", "env:TestMatrixEnvReference2", "noref"]
594+
},
595+
"include": [
596+
{
597+
"foo": "bar",
598+
"envReference": "env:TestMatrixEnvReference"
599+
}
600+
]
601+
}
602+
'@
603+
604+
[System.Environment]::SetEnvironmentVariable("TestMatrixEnvReference", "")
605+
{ GenerateMatrix (GetMatrixConfigFromJson $matrixJson) "sparse" } | Should -Throw
606+
607+
[System.Environment]::SetEnvironmentVariable("TestMatrixEnvReference", "replaced")
608+
[System.Environment]::SetEnvironmentVariable("TestMatrixEnvReference2", "replaced2")
609+
[array]$replacedMatrix = GenerateMatrix (GetMatrixConfigFromJson $matrixJson) "sparse"
610+
$replacedMatrix.Length | Should -Be 4
611+
$replacedMatrix[0].name | Should -Be "bar_replaced"
612+
$replacedMatrix[0].parameters.envReference | Should -Be "replaced"
613+
$replacedMatrix[1].name | Should -Be "bar_replaced2"
614+
$replacedMatrix[1].parameters.envReference | Should -Be "replaced2"
615+
$replacedMatrix[2].name | Should -Be "bar_noref"
616+
$replacedMatrix[2].parameters.envReference | Should -Be "noref"
617+
$replacedMatrix[3].name | Should -Be "bar_replaced"
618+
$replacedMatrix[3].parameters.envReference | Should -Be "replaced"
619+
}
620+
621+
It "Should support filter/replace with variable reference syntax" {
622+
$matrixJson = @'
623+
{
624+
"displayNames": {
625+
"env:replaceme": "env:TestMatrixEnvReference"
626+
},
627+
"matrix": {
628+
"foo": "bar",
629+
"envReference": "env:replaceme"
630+
}
631+
}
632+
'@
633+
634+
[System.Environment]::SetEnvironmentVariable("TestMatrixEnvReference", "replaced")
635+
636+
[array]$replacedMatrix = GenerateMatrix `
637+
-config (GetMatrixConfigFromJson $matrixJson) `
638+
-selectFromMatrixType "sparse" `
639+
-replace @("envReference=env:replaceme/env:TestMatrixEnvReference")
640+
$replacedMatrix.Length | Should -Be 1
641+
$replacedMatrix[0].name | Should -Be "bar_replaced"
642+
$replacedMatrix[0].parameters.envReference | Should -Be "replaced"
643+
644+
# Don't filter out by replaced values, but by original references
645+
[System.Environment]::SetEnvironmentVariable("replaceme", "filter_replaced")
646+
[array]$replacedMatrix = GenerateMatrix `
647+
-config (GetMatrixConfigFromJson $matrixJson) `
648+
-selectFromMatrixType "sparse" `
649+
-filter @("envReference=env:replaceme")
650+
$replacedMatrix.Length | Should -Be 1
651+
$replacedMatrix[0].name | Should -Be "bar_filter_replaced"
652+
$replacedMatrix[0].parameters.envReference | Should -Be "filter_replaced"
653+
}
654+
655+
It "Should support display name and display name filter with variable reference syntax" {
656+
$matrixJson = @'
657+
{
658+
"displayNames": {
659+
"replaced": "display"
660+
},
661+
"matrix": {
662+
"foo": "bar",
663+
"envReference": "env:TestMatrixEnvReference"
664+
}
665+
}
666+
'@
667+
668+
[System.Environment]::SetEnvironmentVariable("TestMatrixEnvReference", "replaced")
669+
[array]$replacedMatrix = GenerateMatrix (GetMatrixConfigFromJson $matrixJson) "sparse"
670+
$replacedMatrix.Length | Should -Be 1
671+
$replacedMatrix[0].name | Should -Be "bar_display"
672+
$replacedMatrix[0].parameters.envReference | Should -Be "replaced"
673+
674+
[System.Environment]::SetEnvironmentVariable("TestMatrixEnvReference", "replaced")
675+
[array]$replacedMatrix = GenerateMatrix `
676+
-config (GetMatrixConfigFromJson $matrixJson) `
677+
-selectFromMatrixType "sparse" `
678+
-displayNameFilter "doesnotexist"
679+
$replacedMatrix | Should -BeNullOrEmpty
680+
}
586681
}

eng/common-tests/matrix-generator/tests/job-matrix-functions.tests.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,17 +228,17 @@ Describe "Matrix-Reverse-Lookup" -Tag "UnitTest", "lookup" {
228228
@{ index = 1; expected = @(0,0,0,1) }
229229
@{ index = 2; expected = @(0,0,0,2) }
230230
@{ index = 3; expected = @(0,0,0,3) }
231-
231+
232232
@{ index = 4; expected = @(0,0,1,0) }
233233
@{ index = 5; expected = @(0,0,1,1) }
234234
@{ index = 6; expected = @(0,0,1,2) }
235235
@{ index = 7; expected = @(0,0,1,3) }
236-
236+
237237
@{ index = 8; expected = @(0,1,0,0) }
238238
@{ index = 9; expected = @(0,1,0,1) }
239239
@{ index = 10; expected = @(0,1,0,2) }
240240
@{ index = 11; expected = @(0,1,0,3) }
241-
241+
242242
@{ index = 12; expected = @(0,1,1,0) }
243243
@{ index = 13; expected = @(0,1,1,1) }
244244
@{ index = 14; expected = @(0,1,1,2) }

0 commit comments

Comments
 (0)