Jenkinsfile 中奇怪的变量作用域行为 [英] Strange variable scoping behavior in Jenkinsfile

查看:19
本文介绍了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

如果 defsome_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 注释可以直接从同一脚本中定义的方法访问.
  • 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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆