2

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
  • 1
    You want this: jenkins.io/doc/book/pipeline/shared-libraries Commented May 22, 2019 at 12:39
  • @MattSchuchard yeah, I'm aware of shared libraries too, but haven't actually found a working example of extracting a stage to a shared library yet, only sequences of steps and entire pipelines. :( Commented May 24, 2019 at 3:44

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.