jenkins plugin matrix - ghdrako/doc_snipets GitHub Wiki

Most Jenkins jobs are designed to run a single build. Sometimes multiple builds are daisy-chained together to create a pipeline, but even with a pipeline, each step in the chain represents a single build job being run. In this Jenkins Matrix plugin a single Jenkins build job can actually run multiple, parameterized builds simultaneously.

Jenkinsfile

pipeline {
    agent none
    stages {
        stage('BuildAndTest') {
            agent any
            stages {
                stage('Build') {
                    steps {
                        echo 'Do Build'
                    }
                }
                stage('Test') {
                    steps {
                        echo 'Do Test'
                    }
                }
            }
        }
    }
}
pipeline {
    agent none
    stages {
        stage('BuildAndTest') {
            matrix {
                agent any
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows', 'mac'
                    }
                    axis {
                        name 'BROWSER'
                        values 'firefox', 'chrome', 'safari', 'edge'
                    }
                }
                stages {
                    stage('Build') {
                        steps {
                            echo "Do Build for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                    stage('Test') {
                        steps {
                            echo "Do Test for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                }
            }
        }
    }
}

Excluding invalid combinations

Each exclude has one or more axis directives with name and values. The axis directives inside an exclude generate a set of combinations (similar to generating the matrix cells). The matrix cells that match all the values from an exclude combination are removed from the matrix. If I have more than one exclude directive, each are evaluated separately to remove cells.

When dealing with a long lists of values to exclude, I can use notValues instead of values to specify axis values we don’t want excluded. Yes, that’s a double negative, so it can get a little confusing. I try to use it only when I really need it.

pipeline {
    agent none
    stages {
        stage('BuildAndTest') {
            matrix {
                agent any
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows', 'mac'
                    }
                    axis {
                        name 'BROWSER'
                        values 'firefox', 'chrome', 'safari', 'edge'
                    }
                }
                excludes {
                    exclude {
                        axis {
                            name 'PLATFORM'
                            values 'linux'
                        }
                        axis {
                            name 'BROWSER'
                            values 'safari'
                        }
                    }
                    exclude {
                        axis {
                            name 'PLATFORM'
                            notValues 'windows'
                        }
                        axis {
                            name 'BROWSER'
                            values 'edge'
                        }
                    }
                }
                stages {
                    stage('Build') {
                        steps {
                            echo "Do Build for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                    stage('Test') {
                        steps {
                            echo "Do Test for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                }
            }
        }
    }
}

This pipeline uses two axes but there is no limit on the number of axis directives.

exclude {
    axis {
        name 'PLATFORM'
        notValues 'linux'
    }
}

Controlling cell behavior at runtime

Inside the matrix directive I can also add "per-cell" directives. These are the same directives that I would add to a stage and they let me control the behavior of each cell in the matrix. These directives can use the axis values from their cell as part of their inputs, allowing me to customize the behavior of each cell to match its axis values.

On my Jenkins server I have configured agents with labels that match the OS for each agent ("linux-agent", "windows-agent", and "mac-agent"). To run each cell in my matrix on the appropriate operating system, I configure the label for that cell using Groovy string templating.

matrix {
    axes { ... }
    excludes { ... }
    agent {
        label "${PLATFORM}-agent"
    }
    stages { ... }
    // ...
}

The "per-cell" directives, on the other hand, are evaluated at runtime. I can use the "per-cell" when directive inside matrix to control which cells in the matrix are executed. I’ll add a choice parameter with the list of platforms, and add conditions to the when directive, which will either let all platforms execute, or only execute cells that match my selected platform.

pipeline {
    parameters {
        choice(name: 'PLATFORM_FILTER', choices: ['all', 'linux', 'windows', 'mac'], description: 'Run on specific platform')
    }
    agent none
    stages {
        stage('BuildAndTest') {
            matrix {
                agent {
                    label "${PLATFORM}-agent"
                }
                when { anyOf {
                    expression { params.PLATFORM_FILTER == 'all' }
                    expression { params.PLATFORM_FILTER == env.PLATFORM }
                } }
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows', 'mac'
                    }
                    axis {
                        name 'BROWSER'
                        values 'firefox', 'chrome', 'safari', 'edge'
                    }
                }
                excludes {
                    exclude {
                        axis {
                            name 'PLATFORM'
                            values 'linux'
                        }
                        axis {
                            name 'BROWSER'
                            values 'safari'
                        }
                    }
                    exclude {
                        axis {
                            name 'PLATFORM'
                            notValues 'windows'
                        }
                        axis {
                            name 'BROWSER'
                            values 'edge'
                        }
                    }
                }
                stages {
                    stage('Build') {
                        steps {
                            echo "Do Build for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                    stage('Test') {
                        steps {
                            echo "Do Test for ${PLATFORM} - ${BROWSER}"
                        }
                    }
                }
            }
        }
    }
}

If I run this Pipeline from the Jenkins UI and set the PLATFORM_FILTER parameter to mac