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
如果从some_var
中删除了def
,它将正常工作.有人可以解释导致此行为的作用域规则吗?
If the def
is removed from some_var
, it works fine. Could someone explain the scoping rules that cause this behavior?
推荐答案
TL; DR
-
在主脚本主体中用
- 变量不能通过其他方法访问. 定义为无
- 变量可以通过任何方法直接访问,甚至可以从不同的脚本访问.这是一个坏习惯.
- 使用,,
def
,和定义的变量TL;DR
- 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.
当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 forpr()
becuse it's a local variable in a different method.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 executespr()
method firstly it tries to find a local variable with a namesome_var
and if it doesn't exist it then tries to find that variable in a Binding (which exists because you defined it withoutdef
).绑定变量被认为是不好的做法,因为如果您加载多个脚本(
load
步骤),则在所有这些脚本中都可以访问绑定变量,因为Jenkins共享所有脚本的相同绑定.更好的选择是使用@Field
注释.这样,您可以使一个脚本中的所有方法都可以访问变量,而无需将其暴露给其他脚本.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屋!
- variables defined with
def
定义的def
的