140

I'm trying to create a declarative Jenkins pipeline script but having issues with simple variable declaration.

Here is my script:

pipeline {
   agent none
   stages {
       stage("first") {
           def foo = "foo" // fails with "WorkflowScript: 5: Expected a step @ line 5, column 13."
           sh "echo ${foo}"
       }
   }
}

However, I get this error:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: Expected a step @ line 5, column 13.
           def foo = "foo"
           ^

I'm on Jenkins 2.7.4 and Pipeline 2.4.

j08691
  • 204,283
  • 31
  • 260
  • 272
Malcolm Crum
  • 4,345
  • 4
  • 30
  • 49

7 Answers7

128

The Declarative model for Jenkins Pipelines has a restricted subset of syntax that it allows in the stage blocks - see the syntax guide for more info. You can bypass that restriction by wrapping your steps in a script { ... } block, but as a result, you'll lose validation of syntax, parameters, etc within the script block.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
abayer
  • 1,739
  • 1
  • 10
  • 4
75

I think error is not coming from the specified line but from the first 3 lines. Try this instead :

node {
   stage("first") {
     def foo = "foo"
     sh "echo ${foo}"
   }
}

I think you had some extra lines that are not valid...

From declaractive pipeline model documentation, it seems that you have to use an environment declaration block to declare your variables, e.g.:

pipeline {
   environment {
     FOO = "foo"
   }

   agent none
   stages {
       stage("first") {
           sh "echo ${FOO}"
       }
   }
}
Neuron
  • 5,141
  • 5
  • 38
  • 59
Pom12
  • 7,622
  • 5
  • 50
  • 69
57

Agree with @Pom12, @abayer. To complete the answer you need to add script block

Try something like this:

pipeline {
    agent any
    environment {
        ENV_NAME = "${env.BRANCH_NAME}"
    }

    // ----------------

    stages {
        stage('Build Container') {
            steps {
                echo 'Building Container..'

                script {
                    if (ENVIRONMENT_NAME == 'development') {
                        ENV_NAME = 'Development'
                    } else if (ENVIRONMENT_NAME == 'release') {
                        ENV_NAME = 'Production'
                    }
                }
                echo 'Building Branch: ' + env.BRANCH_NAME
                echo 'Build Number: ' + env.BUILD_NUMBER
                echo 'Building Environment: ' + ENV_NAME

                echo "Running your service with environemnt ${ENV_NAME} now"
            }
        }
    }
}
Neuron
  • 5,141
  • 5
  • 38
  • 59
Si Zi
  • 1,109
  • 10
  • 6
14

In Jenkins 2.138.3 there are two different types of pipelines.

Declarative and Scripted pipelines.

"Declarative pipelines is a new extension of the pipeline DSL (it is basically a pipeline script with only one step, a pipeline step with arguments (called directives), these directives should follow a specific syntax. The point of this new format is that it is more strict and therefore should be easier for those new to pipelines, allow for graphical editing and much more. scripted pipelines is the fallback for advanced requirements."

jenkins pipeline: agent vs node?

Here is an example of using environment and global variables in a Declarative Pipeline. From what I can tell enviroment are static after they are set.

def  browser = 'Unknown'

pipeline {
    agent any
    environment {
    //Use Pipeline Utility Steps plugin to read information from pom.xml into env variables
    IMAGE = readMavenPom().getArtifactId()
    VERSION = readMavenPom().getVersion()


    }
    stages {
        stage('Example') {
            steps {
                script {
                    browser = sh(returnStdout: true, script: 'echo Chrome')
                }
            }
        }
        stage('SNAPSHOT') {
                when {
                    expression { 
                        return !env.JOB_NAME.equals("PROD") && !env.VERSION.contains("RELEASE")
                    }
                }
                steps {
                    echo "SNAPSHOT"
                    echo "${browser}"
                }
            }
            stage('RELEASE') {
                when {
                    expression { 
                        return !env.JOB_NAME.equals("TEST") && !env.VERSION.contains("RELEASE")
                    }
                }
                steps {
                    echo "RELEASE"
                    echo "${browser}"
                }
            }
    }//end of stages 
}//end of pipeline
pitchblack408
  • 2,913
  • 4
  • 36
  • 54
  • I get the following error from above code: [Pipeline] Start of Pipeline [Pipeline] readMavenPom [Pipeline] End of Pipeline org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Required context class hudson.FilePath is missing Perhaps you forgot to surround the code with a step that provides this, such as: node – mancocapac Apr 23 '19 at 19:40
  • No, it worked as is. It is a declarative pipeline. Agent any means that it can work on any node – pitchblack408 Apr 23 '19 at 19:52
  • @pitchblack408, you are correct I had [agent none] at the top of my pipeline. Not sure what you mean by : environment are static after they are set ? They can be changed within a script, e.g. script{ IMAGE = "newVal} – mancocapac Apr 24 '19 at 16:35
  • Example, look at IMAGE. It is not variable that can or should be changed by the pipelines. It’s my understanding that it’s to be treated as a static value after definition as part of the environment. – pitchblack408 Apr 25 '19 at 00:07
3

You are using a Declarative Pipeline which requires a script-step to execute Groovy code. This is a huge difference compared to the Scripted Pipeline where this is not necessary.

The official documentation says the following:

The script step takes a block of Scripted Pipeline and executes that in the Declarative Pipeline.

pipeline {
   agent none
   stages {
       stage("first") {
           script {
               def foo = "foo" 
               sh "echo ${foo}"
           }
       }
   }
}
Michael Kemmerzell
  • 4,802
  • 4
  • 27
  • 43
3

you can define the variable global , but when using this variable must to write in script block .

def foo="foo"
pipeline {
agent none
stages {
   stage("first") {
      script{
          sh "echo ${foo}"
      }
    }
  }
}
2

Try this declarative pipeline, its working

pipeline {
   agent any
    stages {
      stage("first") {
        steps{
          script {
           def foo = "foo" 
           sh "echo ${foo}"
              }
            }
          }
        }
       }