From c52284d72805f4c6be0bdd0f74e669273a568997 Mon Sep 17 00:00:00 2001 From: Bilgetz Date: Tue, 18 Jul 2023 14:31:57 +0200 Subject: [PATCH] Add basic matrix section of Jenkinsfile --- .../unit/declarative/StageDeclaration.groovy | 13 +++++ .../declarative/matrix/AxesDeclaration.groovy | 16 ++++++ .../declarative/matrix/AxisDeclaration.groovy | 21 ++++++++ .../matrix/MatrixDeclaration.groovy | 51 +++++++++++++++++++ .../TestDeclarativePipeline.groovy | 11 ++++ .../jenkins/jenkinsfiles/Matrix_Jenkinsfile | 26 ++++++++++ 6 files changed, 138 insertions(+) create mode 100644 src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxesDeclaration.groovy create mode 100644 src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxisDeclaration.groovy create mode 100644 src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/MatrixDeclaration.groovy create mode 100644 src/test/jenkins/jenkinsfiles/Matrix_Jenkinsfile diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/declarative/StageDeclaration.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/StageDeclaration.groovy index 8ad5def5..67518f77 100644 --- a/src/main/groovy/com/lesfurets/jenkins/unit/declarative/StageDeclaration.groovy +++ b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/StageDeclaration.groovy @@ -1,5 +1,6 @@ package com.lesfurets.jenkins.unit.declarative +import com.lesfurets.jenkins.unit.declarative.matrix.MatrixDeclaration import static groovy.lang.Closure.* @@ -10,6 +11,7 @@ class StageDeclaration extends GenericPipelineDeclaration { WhenDeclaration when ParallelDeclaration parallel boolean failFast = false + MatrixDeclaration matrix List options = [] StageDeclaration(String name) { @@ -32,6 +34,10 @@ class StageDeclaration extends GenericPipelineDeclaration { this.parallel = createComponent(ParallelDeclaration, closure).with { it.failFast = failFast; it } } + def matrix(@DelegatesTo(strategy = DELEGATE_FIRST, value = MatrixDeclaration) Closure closure) { + this.matrix = createComponent(MatrixDeclaration, closure) + } + def when(@DelegatesTo(strategy = DELEGATE_FIRST, value = WhenDeclaration) Closure closure) { this.when = createComponent(WhenDeclaration, closure) } @@ -46,6 +52,9 @@ class StageDeclaration extends GenericPipelineDeclaration { if(parallel) { actions++ } + if(matrix) { + actions++ + } if(stages.size()>0) { actions++ } @@ -64,6 +73,10 @@ class StageDeclaration extends GenericPipelineDeclaration { parallel.execute(delegate) } + if(matrix) { + matrix.execute(delegate) + } + if(delegate.binding.variables.currentBuild.result == "FAILURE"){ executeWith(delegate, { echo "Stage \"$name\" skipped due to earlier failure(s)" }) return diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxesDeclaration.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxesDeclaration.groovy new file mode 100644 index 00000000..5ab21c9f --- /dev/null +++ b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxesDeclaration.groovy @@ -0,0 +1,16 @@ +package com.lesfurets.jenkins.unit.declarative.matrix + +import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration +import groovy.transform.ToString + +import static groovy.lang.Closure.DELEGATE_FIRST + +@ToString(includePackage = false, includeNames = true, ignoreNulls = true) +class AxesDeclaration extends GenericPipelineDeclaration { + List axis = [] + + def axis(@DelegatesTo(strategy = DELEGATE_FIRST, value = AxisDeclaration) Closure closure) { + this.axis.add( createComponent(AxisDeclaration, closure)) + } + +} diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxisDeclaration.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxisDeclaration.groovy new file mode 100644 index 00000000..c0d8ede3 --- /dev/null +++ b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/AxisDeclaration.groovy @@ -0,0 +1,21 @@ +package com.lesfurets.jenkins.unit.declarative.matrix + + +import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration +import groovy.transform.ToString + +@ToString(includePackage = false, includeNames = true, ignoreNulls = true) +class AxisDeclaration extends GenericPipelineDeclaration { + + String name + List values = [] + + def name(String name) { + this.name = name + } + + def values(String... values) { + this.values = Arrays.asList(values) + } +} + diff --git a/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/MatrixDeclaration.groovy b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/MatrixDeclaration.groovy new file mode 100644 index 00000000..a6359d92 --- /dev/null +++ b/src/main/groovy/com/lesfurets/jenkins/unit/declarative/matrix/MatrixDeclaration.groovy @@ -0,0 +1,51 @@ +package com.lesfurets.jenkins.unit.declarative.matrix + +import com.lesfurets.jenkins.unit.declarative.GenericPipelineDeclaration + +import static groovy.lang.Closure.DELEGATE_FIRST + +class MatrixDeclaration extends GenericPipelineDeclaration { + + AxesDeclaration axes + + def axes(@DelegatesTo(strategy = DELEGATE_FIRST, value = AxesDeclaration) Closure closure) { + this.axes = createComponent(AxesDeclaration, closure) + } + + def execute(Object delegate) { + super.execute(delegate) + + axes.axis.each { + it.name + it.values + } + + + axes.axis.combinations() + def matrixAxes = getMatrixAxes() + matrixAxes.each { + this.stages.entrySet().forEach { e -> + def savedEnv = [:] + def env = e.value.binding.getVariable('env') as Map + savedEnv.putAll(env) + env.putAll(it) + e.value.execute(delegate) + e.value.binding.setVariable('env', savedEnv) + } + } + } + + private List getMatrixAxes() { + List calculatedAxes = [] + axes.axis.each { axis -> + List axisList = [] + axis.values.each { value -> + axisList << [(axis.name): value] + } + calculatedAxes << axisList + } + // calculate cartesian product + calculatedAxes.combinations()*.sum() + } + +} diff --git a/src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestDeclarativePipeline.groovy b/src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestDeclarativePipeline.groovy index a1d95777..15b17f58 100644 --- a/src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestDeclarativePipeline.groovy +++ b/src/test/groovy/com/lesfurets/jenkins/unit/declarative/TestDeclarativePipeline.groovy @@ -796,5 +796,16 @@ class TestDeclarativePipeline extends DeclarativePipelineTest { void test_stage_and_steps() { runScript("StageAndSteps_Jenkinsfile") } + + @Test void should_matrix() throws Exception { + runScript('Matrix_Jenkinsfile') + printCallStack() + assertCallStack().contains('echo(axe_1_value_1 axe_2_value_1)') + assertCallStack().contains('echo(axe_1_value_1 axe_2_value_2)') + assertCallStack().contains('echo(axe_1_value_2 axe_2_value_1)') + assertCallStack().contains('echo(axe_1_value_2 axe_2_value_2)') + assertJobStatusSuccess() +} + } diff --git a/src/test/jenkins/jenkinsfiles/Matrix_Jenkinsfile b/src/test/jenkins/jenkinsfiles/Matrix_Jenkinsfile new file mode 100644 index 00000000..8feafbef --- /dev/null +++ b/src/test/jenkins/jenkinsfiles/Matrix_Jenkinsfile @@ -0,0 +1,26 @@ +pipeline { + agent none + stages { + stage("stage") { + matrix { + axes { + axis { + name 'AXE_1' + values "axe_1_value_1", "axe_1_value_2" + } + axis { + name 'AXE_2' + values "axe_2_value_1", "axe_2_value_2" + } + } + stages { + stage("matrix stage") { + steps { + echo "${AXE_1} ${AXE_2}" + } + } + } + } + } + } +} \ No newline at end of file