15
votes

I am trying to write a Jenkinsfile that executes in parallel a sequence of steps. The goal is to have two agents (aka. nodes). One should do a windows build and the other a linux build. However I do not want this to happen sequentially but in parallel. I am trying to find documentation for the parallel directive that is described in Pipeline - Parallel execution of tasks.

I found one occurence of parallel one on the Jenkins, but it seems the documentation is broken: https://jenkins.io/doc/pipeline/steps/workflow-cps/

parallel: Execute in parallel

org.kohsuke.stapler.NoStaplerConstructorException: 
    There’s no @DataBoundConstructor on any constructor of class
    org.jenkinsci.plugins.workflow.cps.steps.ParallelStep

How should I setup a Jenkinsfile that can execute a series of build steps on two different agents (one linux, one windows) in parallel?

In particular, should I rather use the declarative or script based pipeline DSL?

2

2 Answers

16
votes

You can use either declarative or script based for doing parallel work. The script based docs for parallel can be found here: https://jenkins.io/doc/book/pipeline/jenkinsfile/#advanced-scripted-pipeline

They give the following example...

stage('Build') {
    /* .. snip .. */
}

stage('Test') {
    parallel linux: {
        node('linux') {
            checkout scm
            try {
                unstash 'app'
                sh 'make check'
            }
            finally {
                junit '**/target/*.xml'
            }
        }
    },
    windows: {
        node('windows') {
            /* .. snip .. */
        }
    }
}

For declarative, I believe you'll do this:

stage('Build') {
    steps {
        parallel (
            "Windows" : {
                echo 'done'
            },
            "Linux" : {
                echo 'done'
            }
        )
     }
}

Since Declarative Pipeline 1.2, the preferred declarative syntax is:

pipeline {
    agent none
    stages {
        stage('Run Tests') {
            parallel {
                stage('Test On Windows') {
                    agent {
                        label "windows"
                    }
                    steps {
                        bat "run-tests.bat"
                    }
                    post {
                        always {
                            junit "**/TEST-*.xml"
                        }
                    }
                }
                stage('Test On Linux') {
                    agent {
                        label "linux"
                    }
                    steps {
                        sh "run-tests.sh"
                    }
                    post {
                        always {
                            junit "**/TEST-*.xml"
                        }
                    }
                }
            }
        }
    }
}
2
votes

Declarative Matrix is a great feature for running parallel tasks. It allows you to execute the defined stages (incl. post build actions) for every configuration defined in the matrix directive without code duplication.

Example:

pipeline {
    agent none
    stages {
        stage('Test') {
            matrix {
                agent {
                    label "${PLATFORM}-agent"
                }
                axes {
                    axis {
                        name 'PLATFORM'
                        values 'linux', 'windows'
                    }
                }
                stages {
                    stage('Test') {
                        steps {
                            echo "Do Test for ${PLATFORM}"
                        }
                    }
                }
                post {
                    always {
                        junit "**/TEST-*.xml"
                    }
                }
            }
        }
    }
}

Quote from a Jenkins blog post:

An equivalent pipeline created without matrix would easily be several times larger, and much harder to understand and maintain.