无法在管道阶段中定义变量。

142

我正在尝试创建一个声明式的Jenkins管道脚本,但在简单变量声明方面遇到问题。

这是我的脚本:

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

然而,我遇到了这个错误:

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

我使用的是 Jenkins 2.7.4 和 Pipeline 2.4.

9个回答

128

Jenkins管道的声明式模型在stage块中有一组限制性语法 - 了解更多信息,请参阅语法指南。您可以通过将步骤包装在script { ... }块中来绕过该限制,但结果是您将失去script块内部的语法、参数等验证。


9
如果我想在脚本块之外使用那个变量怎么办? - Jan Steinke
3
如需在脚本块之外使用变量,请参考此链接:https://dev59.com/elcP5IYBdhLWcg3ww8qS#43881731 - Senthil A Kumar

74

我认为错误不是来自指定的那一行,而是来自前三行。请尝试使用以下代码:

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

我认为你有一些无效的额外行...

从声明式管道模型文档来看,似乎你需要使用environment声明块来声明你的变量,例如:

pipeline {
   environment {
     FOO = "foo"
   }

   agent none
   stages {
       stage("first") {
           sh "echo ${FOO}"
       }
   }
}

3
你也可以在一个阶段中添加环境块(例如,如果你的变量依赖于先前步骤中完成的某些操作)。 - Tereza Tomcova

56

同意@Pom12@abayer的观点。为了完成答案,你需要添加脚本块。

尝试这样做:

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

4
请注意,这个例子假设已经有一个名为“ENVIRONMENT_NAME”的环境变量对于Jenkins是可访问的。 - Alberto
1
脚本块能改变环境值吗? - pitchblack408
是的,您可以在脚本块内更改环境值。 - NicoPaez

15

Jenkins 2.138.3有两种不同类型的流水线。

声明式管道和脚本管道。

"声明式管道是管道DSL的一个新扩展(它基本上是一个只有一步(名为指令的管道步骤,这些指令应遵循特定语法的管道脚本)。这种新格式的重点在于更加严格,因此对于那些刚接触流水线的人来说更容易,可以进行图形化编辑等。脚本管道是高级需求的后备方案。"

jenkins pipeline: agent vs node?

以下是在声明式管道中使用环境和全局变量的示例。据我所知,一旦设置,环境变量就是静态的。

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

我从上面的代码中得到以下错误: [Pipeline] 管道开始 [Pipeline] readMavenPom [Pipeline] 管道结束 org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: 缺少所需的上下文类hudson.FilePath 也许您忘记使用提供此类上下文的步骤,例如:node - mancocapac
不,它按原样工作。这是一个声明性流水线。任何代理意味着它可以在任何节点上工作。 - pitchblack408
@pitchblack408,你是正确的,我在管道顶部有[agent none]。不确定你所说的“环境在设置后是静态的”是什么意思?它们可以在脚本内改变,例如:script { IMAGE = "newVal }。 - mancocapac
请看图片示例。它不是管道可以或应该更改的变量。我的理解是,在定义为环境的一部分后,它应被视为静态值。 - pitchblack408

4
您正在使用需要执行Groovy代码的script-stepDeclarative Pipeline,与Scripted Pipeline相比,这是一个巨大的不同之处。官方文档如下所示:official documentation

脚本步骤获取Scripted Pipeline代码块并在Declarative Pipeline中执行。

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

3
你可以定义全局变量,但是在使用该变量时必须写在脚本块中。
def foo="foo"
pipeline {
agent none
stages {
   stage("first") {
      script{
          sh "echo ${foo}"
      }
    }
  }
}

2
你如何在一个阶段中操作变量?例如,如果我想在 stage("first") 中将 foo 赋值为 "bar",该怎么做? - StoneThrow
1
script { should be inside steps { - Sasha Bond

2
尝试使用这个声明式流水线,它可以正常工作。
pipeline {
   agent any
    stages {
      stage("first") {
        steps{
          script {
           def foo = "foo" 
           sh "echo ${foo}"
              }
            }
          }
        }
       }

这与@Michael-kemmerzell的答案几乎相同,但格式不太好。 - Steven the Easily Amused

0
使用函数!
pipeline {
   agent any
    stages {
      stage("first") {
        steps{
          script {
           sh "echo ${foo()}"
              }
            }
          }
        }
       }

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

0
在Jenkins中使用var --
关于一些更多/总结的例子:
- 本地变量 vs 环境变量;
- 变量作用域;
- 字符串插值;
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://dev59.com/pFsX5IYBdhLWcg3wY-rX                                  
          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://dev59.com/pFsX5IYBdhLWcg3wY-rX                   
        sh 'echo ${var_C}' // Cammel          // https://dev59.com/zmoy5IYBdhLWcg3wJKoq                   
        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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接