-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathdynamicMatrix.groovy
More file actions
148 lines (123 loc) · 4.84 KB
/
Copy pathdynamicMatrix.groovy
File metadata and controls
148 lines (123 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env groovy
/*
dynamicMatrix
A custom step mimics Jenkins declarative matrix but with better visualization and extra customization options.
It's mainly an implementation of https://www.jenkins.io/blog/2019/12/02/matrix-building-with-scripted-pipeline
as a workaround for declarative matrix limitations https://issues.jenkins.io/browse/JENKINS-61280.
Parameters:
@param Map axes - DEFAULT: None, MANDATORY: Yes
@param Closure actions - DEFAULT: None, MANDATORY: Yes
@param boolean failFast - DEFAULT: false
If a stage failed in the matrix, mark the build as failed and don't continue the rest of stages.
@param String stageNameSeparator - DEFAULT: "_"
Default stage name separator which used in "MATRIX_STAGE_NAME" exported var. e.g. if the matrix has
"PLATFORM" and "BROWSER" as axes and "stageNameSeparator" is "_", MATRIX_STAGE_NAME var will be
"${PLATFORM}_${BROWSER}".
@param Map extraVars - DEFAULT: [:]
A map has key value for any vars needed to be passed to the matrix stages.
@param boolean returnStages - DEFAULT: false
Instead run matrix stages in parallel, return the stages if extra operations will be applied.
It's mainly helpful to run matrix with heterogeneous groups (e.g. used in dynamicMatrixMultiGroups step).
Exported vars:
- MATRIX_STAGE_NAME: An env var concatenates all matrix stage axes with underscore.
e.g. if the matrix has "PLATFORM" and "BROWSER" as axes, this var will be "${PLATFORM}_${BROWSER}".
It's useful to be used as identifier for stages within the matrix.
- MATRIX_STAGE_VARS: The same as MATRIX_STAGE_NAME but comma separated and includes keys.
e.g. if the matrix has "PLATFORM" and "BROWSER" as axes, this var will be
"PLATFORM=${PLATFORM}, BROWSER=${BROWSER}".
Example:
Here is an example for a pipeline that runs a single parallel matrix group:
```
stage('single_matrix') {
steps {
dynamicMatrix([
failFast: false,
axes: [
PLATFORM: ['linux', 'mac', 'windows'],
BROWSER: ['chrome', 'firefox']
],
actions: {
stage("${PLATFORM}_${BROWSER}") {
sh 'echo ${PLATFORM}, ${BROWSER}'
sh 'echo ${MATRIX_STAGE_NAME}'
}
}
])
}
}
```
For examples with multi axes and multi groups, please check "dynamicMatrixMultiCombinations"
and "dynamicMatrixMultiGroups".
*/
import groovy.transform.Field
@Field String stepName = this.class.name
@NonCPS
List getMatrixAxes(Map axes) {
List axesFlatten = []
axes.each { axisName, axisValues ->
List axisCombination = []
axisValues.each { axisValue ->
axisCombination << [(axisName): axisValue]
}
axesFlatten << axisCombination
}
axesFlatten.combinations()*.sum()
}
List<String> mapToKeyValueList(Map source) {
return source.collect { key, value -> "${key}=${value}" }
}
void call(Map givenParameters = [:]) {
// Mandatory parameters.
mandatoryParameters = [
'axes': [],
'actions': {}
]
mandatoryParameters.keySet().each { mandatoryParameter ->
if (!givenParameters[mandatoryParameter]) {
error "[${stepName}] The following parameter is required and must be specified: '${mandatoryParameter}'"
}
}
// Optional parameters.
defaultParameters = [
failFast: true,
stageNameSeparator: '_',
extraVars: [:],
returnStages: false,
// TODO: Add 'exclude' parameter.
]
// Validate given parameters.
List availableParameters = (mandatoryParameters.keySet() + defaultParameters.keySet()) as List
givenParameters.keySet().each { parameter ->
assert parameter in availableParameters,
"[${stepName}] Invalid parameter '${parameter}'. Available parameter are: ${availableParameters}"
}
// The parameters var must be copied as a local var (with def) to allow the method to work within loops.
def parameters = defaultParameters + givenParameters
Map matrixStages = [
failFast: parameters.failFast
]
List matrixAxes = getMatrixAxes(parameters.axes)
for(int index = 0; index < matrixAxes.size(); index++) {
Map axis = matrixAxes[index]
List groupVars = mapToKeyValueList(axis)
String groupID = groupVars.join(', ')
// Add Matrix common vars.
groupVars.addAll(
["MATRIX_STAGE_VARS=${groupID}", "MATRIX_STAGE_NAME=${axis.values().join(parameters.stageNameSeparator)}"] +
mapToKeyValueList(parameters.extraVars)
)
echo "[${stepName}] Matrix group vars are:\n ${groupVars}"
matrixStages[groupID] = { ->
stage(groupID) {
withEnv(groupVars) {
parameters.actions()
}
}
}
}
if (parameters.returnStages) {
return matrixStages
} else {
parallel matrixStages
}
}