skip to Main Content

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. 🙁

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search