在Jenkins Pipeline的Shell脚本部分中定义变量

jxr*_*mos 1 jenkins jenkins-pipeline

我试图动态定义一个变量,稍后在我的Jenkins管道的一些shell命令中使用它,并抛出异常。我什至尝试将变量从环境部分预定义为无济于事。这是被禁止的操作吗?我的其他变量myVar似乎工作正常,但是在管道中是一个常量。

pipeline {
    agent any

   environment {
     py2Ana=""
     myVar="ABCDE"
   }
    stages {
        stage('Stage1') {
            steps {
                sh """
                    echo myVar=$myVar
                    echo Find Anaconda2 Python installation...
                    py2Ana=`which -a python | grep --max-count=1 anaconda2`
                    if [[ -z "$py2Ana" ]]; then
                        echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
                        exit 1 # terminate and indicate error
                    fi
                """
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

例外

groovy.lang.MissingPropertyException: No such property: py2Ana for class: groovy.lang.Binding
    at groovy.lang.Binding.getVariable(Binding.java:63)
    at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:242)
    at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:288)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:292)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
    at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
    at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
    at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
    at WorkflowScript.run(WorkflowScript:21)
Run Code Online (Sandbox Code Playgroud)

Joe*_*eAC 13

正如@jxramos 所说,Jenkins 正在尝试解析脚本中的变量。它将任何 $string 解释为需要替换的变量。解决方案是转义脚本内变量的 $ ,如下所示:

pipeline { 
  agent any 
  stages {
    stage('test stage'){
      steps {
        sh """#!/bin/bash
            myvar=somevalue
            echo "The value is \$myvar"
        """
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


jxr*_*mos 5

如果您愿意的话,Jenkins在预处理步骤中似乎强制执行一个变量替换优先级。换句话说,没有延迟扩展,就像Windows批处理文件中的行为一样setlocal ENABLEDELAYEDEXPANSION。这说明了正在发生的事情,这是我用来确定这一点的测试管道:

pipeline {
    agent any

   environment {
     py2Ana="DEFAULT"
   }
   stages {
       stage('Stage1') {
           steps {
                sh """
                    echo py2Ana=$py2Ana
                    py2Ana=Initialized
                    echo py2Ana Initialized=$py2Ana
                """
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将产生以下控制台输出...

Started by user unknown or anonymous
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] node
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Stage1)
[Pipeline] sh
[TestPipeline] Running shell script
+ echo py2Ana=DEFAULT
py2Ana=DEFAULT
+ py2Ana=Initialized
+ echo py2Ana Initialized=DEFAULT
py2Ana Initialized=DEFAULT
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Run Code Online (Sandbox Code Playgroud)

这样做的另一个限制是,您真的不能sh在Jenkins声明性管道脚本的部分中使用动态变量,因为Jenkins将在执行之前首先尝试解析所有变量。因此,以下内容始终会产生错误

sh """
   for filename in /tmp/**; do
      echo filename=$filename
   done
"""
Run Code Online (Sandbox Code Playgroud)

错误是...

groovy.lang.MissingPropertyException: No such property: filename for class: groovy.lang.Binding
Run Code Online (Sandbox Code Playgroud)

一个人需要动态定义一个脚本(在找到一种方法来逃避$写入文件之后),或者已经在源代码中执行了该脚本。


Joe*_*g S 5

该错误本身似乎确实是由空字符串的赋值引起的。

但是:您真的需要在 Jenkinsfile 中定义该环境变量吗?对我来说,您似乎只想从 shell 脚本中设置和读取变量。但它的编码方式if [[ -z "$py2Ana" ]]; then永远不会获取 shell 脚本设置的值 - 它总是想要使用 Jenkinsfile 中的属性 - 这是行不通的。

您可以使用if [[ -z "${env.py2Ana}" ]]; thenif 条件来修复该错误,但它仍然不会获取上一行设置的值,但始终读取 Jenkinsfile 中设置的空字符串。

要解决这个问题,您可以将整个字符串用单引号引起来,例如(也许您甚至想去掉 then myVar)...:

pipeline {
    agent any

    stages {
        stage('Stage1') {
            steps {
                sh '''
                    echo Find Anaconda2 Python installation...
                    py2Ana=`which -a python | grep --max-count=1 anaconda2`
                    if [[ -z "$py2Ana" ]]; then
                        echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
                        exit 1 # terminate and indicate error
                    fi
                '''
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

...或者在前面添加一个反斜杠,$py2Ana例如:

pipeline {
    agent any

    stages {
        stage('Stage1') {
            steps {
                sh """
                    echo Find Anaconda2 Python installation...
                    py2Ana=`which -a python | grep --max-count=1 anaconda2`
                    if [[ -z "\$py2Ana" ]]; then
                        echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
                        exit 1 # terminate and indicate error
                    fi
                """
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

env.py2Ana无论哪种方式,如果没有在代码中引用,我怀疑environmentJenkinsfile 中的块仍然有意义 - 这就是我从示例中删除它的原因。