Hakanai
Hakanai

Reputation: 12670

How do I run the same stages on multiple nodes in Jenkins declarative pipeline?

We have a pipeline like this:

pipeline {
    agent none

    stages {
        stage('Build') {
            // ...
        }

        stage('Test') {
            parallel {
                stage('Test on Debian') {
                    agent {
                        label 'debian'
                    }
                    steps {
                        unstash 'compile-artifacts'
                        unstash 'dot-gradle'

                        sh './gradlew check --stacktrace'
                    }
                    post {
                        always {
                            junit '*/build/test-results/**/*.xml'
                        }
                    }
                }

                stage('Test on CentOS') {
                    agent {
                        label 'centos'
                    }
                    steps {
                        unstash 'compile-artifacts'
                        unstash 'dot-gradle'

                        sh './gradlew check --stacktrace'
                    }
                    post {
                        always {
                            junit '*/build/test-results/**/*.xml'
                        }
                    }
                }

                stage('Test on Windows') {
                    agent {
                        label 'windows'
                    }
                    steps {
                        unstash 'compile-artifacts'
                        unstash 'dot-gradle'

                        bat "gradlew.bat check --stacktrace"
                    }
                    post {
                        always {
                            junit '*/build/test-results/**/*.xml'
                        }
                    }
                }

                stage('Test on macOS') {
                    agent {
                        label 'macos'
                    }
                    steps {
                        unstash 'compile-artifacts'
                        unstash 'dot-gradle'


                        sh './gradlew check --stacktrace'
                    }
                    post {
                        always {
                            junit '*/build/test-results/**/*.xml'
                        }
                    }
                }
            }
        }
    }
}

Every stage is essentially identical, save for one line in the Windows block which I already know how to deal with, so is there a way to template out the common parts of these stages to remove the duplication?

I already tried putting a loop inline, but it's not something that declarative pipelines let you do. :(

Upvotes: 2

Views: 4726

Answers (2)

Michael Kemmerzell
Michael Kemmerzell

Reputation: 5256

You can refactor your step{}-blocks with groovy-methods:

def stageX(boolean linux) {
    unstash 'compile-artifacts'
    unstash 'dot-gradle'
    if (linux) {
        sh './gradlew check --stacktrace' }
    else {
        bat "gradlew.bat check --stacktrace" }
}

which you have to call like the following in your step{}:

steps {
   script { stageX( true) } // or with false for your windows agent
}

Of course you can do the same for your junit-plugin-call:

def junitCall() {
   junit '*/build/test-results/**/*.xml'
}

and call it like:

post {
   always {
       script { junitCall() 
       }   
   }
}

You won't win a lot of lines but it will improve the handling of the code a lot. If you want to cleanup your Jenkinsfile even more you could put the methods into a shared-library which you import so they aren't even declared in your Jenkinsfile.

Upvotes: 4

Frank Lichtenheld
Frank Lichtenheld

Reputation: 51

Essentially what you want to do is currently not possible. As https://jenkins.io/doc/book/pipeline/shared-libraries/#defining-declarative-pipelines states:

Only entire pipelines can be defined in shared libraries as of this time. This can only be done in vars/*.groovy, and only in a call method. Only one Declarative Pipeline can be executed in a single build, and if you attempt to execute a second one, your build will fail as a result.

So you can define methods to bundle several steps or you can bundle a whole pipeline in a shared library but nothing in between. Which is a shame, really.

Upvotes: 0

Related Questions