当前位置: 首页 > 面试题库 >

Jenkinsfile中的奇怪变量作用域行为

郜振国
2023-03-14
问题内容

当我运行以下Jenkins管道脚本时:

def some_var = "some value"

def pr() {
    def another_var = "another " + some_var
    echo "${another_var}"
}

pipeline {
    agent any

    stages {
        stage ("Run") {
            steps {
                pr()
            }
        }
    }
}

我收到此错误:

groovy.lang.MissingPropertyException: No such property: some_var for class: groovy.lang.Binding

如果def从中删除some_var,则可以正常工作。有人可以解释导致此行为的作用域规则吗?


问题答案:

TL; DR

  • 定义的变量 def主脚本主体不能从其他方法来访问。
  • 定义的变量 ,而不 def能够直接通过任何方法甚至从不同的脚本访问。这是一个坏习惯。
  • 使用 def @Field 注释定义的变量可以直接从同一脚本中定义的方法访问。

说明

当groovy编译该脚本时,它实际上将所有内容移动到一个 大致 类似于以下内容的类

class Script1 {
    def pr() {
        def another_var = "another " + some_var
        echo "${another_var}"
    }
    def run() {
        def some_var = "some value"
        pipeline {
            agent any
            stages {
                stage ("Run") {
                    steps {
                        pr()
                    }
                }
            }
        }
    }
}

您可以看到这some_var显然超出了范围,因为pr()它是另一种方法中的局部变量。

在没有定义变量的 情况下 def,实际上 没有 将该变量放入脚本的绑定中(所谓的 绑定变量 )。因此,当groovy
pr()首先执行方法时,它将尝试查找具有名称的局部变量,some_var如果该变量不存在,则尝试在Binding中找到该变量(因为您没有定义便存在该变量def)。

绑定变量被认为是不好的做法,因为如果您加载多个脚本(load步骤),则在所有这些脚本中都可以访问绑定变量,因为Jenkins对所有脚本共享相同的绑定。更好的选择是使用@Field

注释。这样,您可以使一个脚本中的所有方法都可以访问变量,而无需将其暴露给其他脚本。

import groovy.transform.Field

@Field 
def some_var = "some value"

def pr() {
    def another_var = "another " + some_var
    echo "${another_var}"
}
//your pipeline

当groovy将这个脚本编译成一个类时,它将看起来像这样

class Script1 {
    def some_var = "some value"

    def pr() {
        def another_var = "another " + some_var
        echo "${another_var}"
    }
    def run() {
        //your pipeline
    }
}


 类似资料:
  • 我正在使用Spring Boot2,通过阅读这里关于外部化属性的文档,我希望可以通过声明一个同名的os环境变量来覆盖application.properties中变量的值。 所以我做了如下的尝试。 首先,在中声明以下2个变量 > Spring可以看到环境变量,而不管是否有have点(.)是否在变量名中,如和所示 Spring只能在中使用同名os环境变量的值重写该变量的值,前提是该变量的名称不包含点

  • 问题内容: 以下是来自java.lang.System类的代码(JDK版本1.6) 当我们在代码中编写代码时,为什么即使将“ out”设置为“ null”也不会得到NullPointerException 无论如何,将通过System类中的以下方法进行设置 那么为什么JLS需要方法? 问题答案: 看看-这个方法被称为启动事情,它调用的是一个方法。这将它与应该存在的位置联系在一起。 因此,即使该字段

  • 变量作用域 变量的作用域值的是变量的生命周期和作用范围(全局与局部作用域的区别)。 作用域介绍 静态作用域 静态作用域有称为词法作用域,即指其在编译的阶段就可以决定变量的引用。静态作用域只更变量定义的位置有关与代码执行的顺序无关。 var x = 0; function foo() { alert(x); } function bar() { var x = 20; foo(); }

  • 任何编程中的范围都是程序的一个区域,其中定义的变量可以存在,并且超出该变量无法访问。 有三个地方,其中变量可以用Pascal编程语言声明 - 在子程序或块中,称为局部变量 在所有子程序之外,称为全局变量 在子程序参数的定义中称为形式参数 让我们解释什么是local和global变量和形式参数。 局部变量 (Local Variables) 在子程序或块内声明的变量称为局部变量。 它们只能由子程序或

  • 如果你之前用过像Python或者Ruby之类的动态语言,现在你可能已经熟悉了Vim脚本的变量。你会发现Vim变量的大部分内容跟你想的一样,不过有一个东西可能会不同,那就是变量的作用域。 在两个分隔的窗口中分别打开两个不同的文件,然后在其中一个窗口中执行下面的命令: :::vim :let b:hello = "world" :echo b:hello 如你所愿,Vim会显示world。现在切换到

  • 我刚刚开始使用活动框架。我给我的Spring启动应用程序添加了依赖项,并想测试非常简单的sequnce流,但我被奇怪的行为卡住了。 所以,我有2个简单的服务,没有任何业务逻辑。 和带有进程定义的xml文件: 我放了一些控制器: 问题是:对于service1,它打印id,但是对于service2,它丢失id。在service2的调试器模式下,由于某种原因,参数id是空字符串。我不明白为什么...