36

I'm trying to convert my Scripted pipeline to a Declarative Pipeline. Wondering how to do a simple if-statement inside a steps {} block.

    stage ('Deploy to Docker') {
        steps {
            parallel (
                "instance1" : {
                    environment {
                        containerId = sh(script: "docker ps --quiet --filter name=${fullDockerImageName}", returnStdout: true).trim()
                    }
                    steps {
                        if (containerId.isEmpty()) {
                            docker.image('some/image').run("--name ${fullDockerImageName}")
                        }
                    }
                }
            )
        }
   }

This causes the following Exception:

WorkflowScript: 201: Expected a step @ line 201, column 29.
                           if (containerId.isEmpty()) {

Since I'm not allowed to do a simple if(..) inside a steps {} block, any idea on how to do this?

It doesn't seem to make sense to make this a full stage with a when {}, since there are more steps that happens in a simple stage (starting a stopped container if it exists, etc).

What's the best way to do a simple if?

Jasper Roel
  • 383
  • 1
  • 4
  • 5
  • 1
    @jon-s This is extremely like my other question (https://stackoverflow.com/questions/42277936/assigning-variables-in-a-parallel-step-using-declarative-pipeline-steps-in-jenki), but I wanted to document both extremely common scenarios (the if-statement and the var-assignment), so posting it anyway. Maybe you have a different insight on this one? – Jasper Roel Feb 16 '17 at 17:49

4 Answers4

28

This should work

pipeline {
     stages {
        stage ('Main Stage') {
            steps {
                script {
                    if (true) {
                        stage ('Stage 1') {
                            sh 'echo Stage 1'
                        }
                    }
                    if (false) {
                        stage ('Stage 2') {
                            sh 'echo Stage 2'
                        }
                    }
                }
            }
        }
    }
}
Reuben Abela
  • 305
  • 3
  • 2
24

Unfortunately you have to wrap it within a script, for now. As it says here;

Declarative Pipelines may use all the available steps documented in the Pipeline Steps reference, which contains a comprehensive list of steps, with the addition of the steps listed below which are only supported in Declarative Pipeline.

And if you look at the step reference it simply lists all plugins which contributes pipeline steps. And as far as I can see, there is no step supporting if, then, else. So the answer is, no, right now it is not possible, but, it should be fairly simple to implement this as a step and add to a plugin.

Jon S
  • 15,846
  • 4
  • 44
  • 45
  • 3
    You should add a fairly simple example in order to actually answer the question. It was how to perform if clauses not if it is possible at all. – Dominik Aug 20 '19 at 09:07
  • 3
    How do you add an example of something that can't be done? With that said, this answers is over two years old, things might have changed now... – Jon S Aug 20 '19 at 11:16
  • 1
    I'm just commenting this because this is the best voted answer but it just says something like "it should be fairly simple to implement this as a step" but doesn't really provide this simple result. You can just have a look at Reuben Abelas answer for an example how to perform if statements in declarative pipeline. Additionally as you said this answer IS two years old so I would recommend using the "when" directive – Dominik Aug 20 '19 at 15:58
  • 1
    Aha I see, by saying "it should be fairly simple to implement this as a step and add to a plugin" I mean that adding this functionality to Jenkins in form a plugin would be fairly simple, however as anyone who have developed plugins, it is never a oneliner, probably ~100 lines of Java, a POM file of about the same size and then some groovy or jelly files on top of that, far outside the scope for an answer on StackOverflow. As for when, the author explicitly states that it doesn't make sense to use and can't be used (and is looking for other options). – Jon S Aug 21 '19 at 05:26
8

I think that this is the most correct/best practice way about using if/else or control logic within your Jenkins Declarative pipeline.

https://jenkins.io/doc/book/pipeline/syntax/#when

@IronSean answer, doesn't seem like you need that plugin (anymore).

DamnedNForsaken
  • 494
  • 1
  • 6
  • 14
  • 7
    Please do not just refer to the URL (it might be gone in the future) but also provide the essence of the link or an example in your answer. – Dominik Aug 20 '19 at 15:57
4

Using the Conditional BuildStep plugin you can add a when {} step to process a conditional.

The following should work, barring syntax issues with the isEmpty() check within this context.

stage ('Deploy to Docker') {
    steps {
        parallel (
            "instance1" : {
                environment {
                    containerId = sh(script: "docker ps --quiet --filter name=${fullDockerImageName}", returnStdout: true).trim()
                }
                when {
                    expression {
                        return containerId.isEmpty()
                    }
                }
                step {
                    docker.image('some/image').run("--name ${fullDockerImageName}")
                }
            }
        )
    }
}

The related blog post is here.

EDIT: Sorry, the actual snytax seems to be closer to this, which doesn't have access to your needed conditional:

stage ('Deploy to Docker') {
    when {
        expression {
            return containerId.isEmpty()
        }
    }
    steps {
        parallel (
            "instance1" : {
                environment {
                    containerId = sh(script: "docker ps --quiet --filter name=${fullDockerImageName}", returnStdout: true).trim()
                }
                step {
                    docker.image('some/image').run("--name ${fullDockerImageName}")
                }
            }
        )
    }
}
IronSean
  • 1,520
  • 17
  • 31