Malcolm Crum
Malcolm Crum

Reputation: 4879

Cannot define variable in pipeline stage

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.

Upvotes: 145

Views: 312706

Answers (9)

Nor.Z
Nor.Z

Reputation: 1419

To use var in Jenkins --
Some more/summarized examples regarding:

- local var vs env var;
- var scope;
- string interpolation;

def var_D = "Demo"

pipeline {
  agent any

  environment {
    var_E = "Egg"
  }

  stages {
    stage("R1") {
      steps {
        script {
          def var_A = "Apple" 
          sh "echo ${var_A}" // Apple            // this is string interpolation -- injected by groovy                                  
          sh "echo $var_A"   // Apple            // same^ groovy syntax https://stackoverflow.com/questions/33880220/when-do-you-need-curly-braces-for-variable-substitution-in-gradle                                  
          sh 'echo ${var_A}' //                  // no such env var in bash (its an local var in groovy) -- so its empty                  
          sh 'echo $var_A'   //                  // same^               
          echo "${var_A}"    // Apple                               
          echo "$var_A"      // Apple                             
          echo '${var_A}'    // ${var_A}         // single quote disables string interpolation
          echo '$var_A'      // $var_A                             
        }
      }
    }
    stage("R2") {
      environment {
        var_C = "Cammel"
      }
      steps {
        sh "echo ${var_C}" // Cammel          // ~~~//repeat: this is string interpolation -- injected by groovy                   
        sh "echo $var_C"   // Cammel          // ~~~//repeat: same^ groovy syntax https://stackoverflow.com/questions/33880220/when-do-you-need-curly-braces-for-variable-substitution-in-gradle                   
        sh 'echo ${var_C}' // Cammel          // https://stackoverflow.com/questions/8748831/when-do-we-need-curly-braces-around-shell-variables                   
        sh 'echo $var_C'   // Cammel          // bash is accessing the env var -- its bash not groovy because >"single quote disables string interpolation"
        echo "${var_C}"    // Cammel          // same^               
        echo "$var_C"      // Cammel          // same^             
        echo '${var_C}'    // ${var_C}                
        echo '$var_C'      // $var_C              
      }
    }
    // ;wrong; stage("R3") {
    // ;wrong;   steps {
    // ;wrong;     script {
    // ;wrong;       def var_B = "Banana" 
    // ;wrong;     }
    // ;wrong;     sh "echo ${var_B}" // out of scope -- groovy.lang.MissingPropertyException: No such property: var_B for class: groovy.lang.Binding
    // ;wrong;   }
    // ;wrong; }
    // ;wrong; stage("R3.2") {
    // ;wrong;   steps {
    // ;wrong;     script {
    // ;wrong;       def var_B = "Banana" 
    // ;wrong;     }
    // ;wrong;     sh "echo zzz"
    // ;wrong;     script {
    // ;wrong;       sh "echo ${var_B}" // out of scope -- groovy.lang.MissingPropertyException: No such property: var_B for class: groovy.lang.Binding
    // ;wrong;     }
    // ;wrong;   }
    // ;wrong; }
    stage("R4") {
      steps {
        sh "echo ${var_D}" // Demo           // global scope
        sh "echo ${var_E}" // Egg            // global scope
        sh 'echo ${var_D}' //                // >"no such env var in bash (its an local var in groovy)"
        sh 'echo ${var_E}' // Egg            // global scope
        // ;wrong; sh "echo ${var_A}" // out of scope -- groovy.lang.MissingPropertyException: No such property: var_A for class: groovy.lang.Binding
        script {
          sh "echo ${var_D}" // Demo         // same^ (script scope wont make diff)
          sh "echo ${var_E}" // Egg          // same^
          sh 'echo ${var_D}' //              // same^ 
          sh 'echo ${var_E}' // Egg          // same^
          // ;wrong; sh "echo ${var_A}" // out of scope -- groovy.lang.MissingPropertyException: No such property: var_A for class: groovy.lang.Binding
        }
      }
    }
  }
}

// [Output]
//
// Started by user nor
// [Pipeline] Start of Pipeline
// [Pipeline] node
// Running on Jenkins in C:\Users\Amplify\AppData\Local\Jenkins\.jenkins\workspace\Test1
// [Pipeline] {
// [Pipeline] withEnv
// [Pipeline] {
// [Pipeline] stage
// [Pipeline] { (R1)
// [Pipeline] script
// [Pipeline] {
// [Pipeline] sh
// + echo Apple
// Apple
// [Pipeline] sh
// + echo Apple
// Apple
// [Pipeline] sh
// + echo
// 
// [Pipeline] sh
// + echo
// 
// [Pipeline] echo
// Apple
// [Pipeline] echo
// Apple
// [Pipeline] echo
// ${var_A}
// [Pipeline] echo
// $var_A
// [Pipeline] }
// [Pipeline] // script
// [Pipeline] }
// [Pipeline] // stage
// [Pipeline] stage
// [Pipeline] { (R2)
// [Pipeline] withEnv
// [Pipeline] {
// [Pipeline] sh
// + echo Cammel
// Cammel
// [Pipeline] sh
// + echo Cammel
// Cammel
// [Pipeline] sh
// + echo Cammel
// Cammel
// [Pipeline] sh
// + echo Cammel
// Cammel
// [Pipeline] echo
// Cammel
// [Pipeline] echo
// Cammel
// [Pipeline] echo
// ${var_C}
// [Pipeline] echo
// $var_C
// [Pipeline] }
// [Pipeline] // withEnv
// [Pipeline] }
// [Pipeline] // stage
// [Pipeline] stage
// [Pipeline] { (R4)
// [Pipeline] sh
// + echo Demo
// Demo
// [Pipeline] sh
// + echo Egg
// Egg
// [Pipeline] sh
// + echo
// 
// [Pipeline] sh
// + echo Egg
// Egg
// [Pipeline] script
// [Pipeline] {
// [Pipeline] sh
// + echo Demo
// Demo
// [Pipeline] sh
// + echo Egg
// Egg
// [Pipeline] sh
// + echo
// 
// [Pipeline] sh
// + echo Egg
// Egg
// [Pipeline] }
// [Pipeline] // script
// [Pipeline] }
// [Pipeline] // stage
// [Pipeline] }
// [Pipeline] // withEnv
// [Pipeline] }
// [Pipeline] // node
// [Pipeline] End of Pipeline
// Finished: SUCCESS

Upvotes: 0

Thomas Decaux
Thomas Decaux

Reputation: 22701

Use function !

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

def foo() {
  return "hello this is logic code ${env.param1}"
}

Upvotes: 0

Muzaffar khan
Muzaffar khan

Reputation: 47

Try this declarative pipeline, its working

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

Upvotes: 2

hamid valizadeh
hamid valizadeh

Reputation: 63

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}"
      }
    }
  }
}

Upvotes: 3

Pom12
Pom12

Reputation: 7880

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}"
       }
   }
}

Upvotes: 77

Si Zi
Si Zi

Reputation: 1139

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"
            }
        }
    }
}

Upvotes: 56

Michael Kemmerzell
Michael Kemmerzell

Reputation: 5276

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}"
           }
       }
   }
}

Upvotes: 4

pitchblack408
pitchblack408

Reputation: 2983

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

Upvotes: 15

abayer
abayer

Reputation: 1759

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.

Upvotes: 130

Related Questions