Jenkinsfile 中奇怪的变量作用域行为 [英] Strange variable scoping behavior in Jenkinsfile
问题描述
当我运行以下 Jenkins 管道脚本时:
When I run the below Jenkins pipeline script:
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
中删除,它工作正常.有人可以解释导致这种行为的范围规则吗?
If the def
is removed from some_var
, it works fine. Could someone explain the scoping rules that cause this behavior?
推荐答案
TL;DR
- 在主脚本体中用
def
定义的变量不能从其他方法访问. - 定义的变量没有
def
可以通过任何方法直接访问,甚至可以从不同的脚本访问.这是一个不好的做法. - 定义的变量使用
def
和@Field
注释可以直接从同一脚本中定义的方法访问. - variables defined with
def
in the main script body cannot be accessed from other methods. - variables defined without
def
can be accessed directly by any method even from different scripts. It's a bad practice. - variables defined with
def
and@Field
annotation can be accessed directly from methods defined in the same script.
TL;DR
当 groovy 编译该脚本时,它实际上将所有内容移动到一个大致看起来像这样的类
When groovy compiles that script it actually moves everything to a class that roughly looks something like this
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()
的范围,因为它是不同方法中的局部变量.
You can see that some_var
is clearly out of scope for pr()
becuse it's a local variable in a different method.
当你定义一个没有def
的变量时,你实际上是把那个变量放到了绑定 脚本(所谓的绑定变量).因此,当 groovy 首先执行 pr()
方法时,它会尝试查找名称为 some_var
的局部变量,如果它不存在,则尝试在绑定(存在是因为您在没有 def
的情况下定义了它).
When you define a variable without def
you actually put that variable into a Binding of the script (so-called binding variables). So when groovy executes pr()
method firstly it tries to find a local variable with a name some_var
and if it doesn't exist it then tries to find that variable in a Binding (which exists because you defined it without def
).
绑定变量被认为是不好的做法,因为如果您加载多个脚本(load
步骤),所有这些脚本中都可以访问绑定变量,因为 Jenkins 为所有脚本共享相同的绑定.更好的选择是使用 @字段
注解.通过这种方式,您可以在一个脚本内的所有方法中访问变量,而无需将其暴露给其他脚本.
Binding variables are considered bad practice because if you load multiple scripts (load
step) binding variables will be accessible in all those scripts because Jenkins shares the same Binding for all scripts. A much better alternative is to use @Field
annotation. This way you can make a variable accessible in all methods inside one script without exposing it to other scripts.
import groovy.transform.Field
@Field
def some_var = "some value"
def pr() {
def another_var = "another " + some_var
echo "${another_var}"
}
//your pipeline
当 groovy 将此脚本编译成一个类时,它看起来像这样
When groovy compiles this script into a class it will look something like this
class Script1 {
def some_var = "some value"
def pr() {
def another_var = "another " + some_var
echo "${another_var}"
}
def run() {
//your pipeline
}
}
这篇关于Jenkinsfile 中奇怪的变量作用域行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!