【问题标题】:How to declare a constructor or extends a class of a groovy script?如何声明构造函数或扩展 groovy 脚本的类?
【发布时间】:2020-09-19 01:00:37
【问题描述】:

我正在为 Jenkins 开发一个 shared library,我想访问一些类之间的一些实用程序方法,但不是全部,因此我建立了一些声明:

  • 我想避免使用静态方法,因为它不直接访问管道步骤,并且每次调用都传递管道实例会很痛苦;
  • 我也想避免使用单例,或者在每个方法调用前加上 util 类的实例;
  • 由于它不应该在所有类之间共享,我希望避免将每个方法作为文件放在 vars/ 特殊目录中,但我希望有类似的行为;
  • 尽管扩展类是一种反模式,但它是可以接受的,但我想避免使用冗长的 Java 语法来声明与文件同名的类,一旦它隐含在 groovy 中;

这个question 确实部分解决了我的问题,尽管序列化存在问题,但我注意到当我使用检查点并且从某个阶段恢复某些构建时,实例会丢失所有额外的方法。

这个other question 可以帮助我解决序列化问题,但是作者似乎已经解决了他的问题的根本原因,使用的方式不是最初的问题标题。

有没有办法在不使用class NameOfFile extends SomeOtherClass { put every thing inside this block } 语法的情况下扩展groovy 中的隐式脚本类?并且不使用内部类?

否则,有没有办法像上一个问题一样使用脚本 groovy 语法类似物来声明构造函数?

甚至,有没有办法改变序列化行为以在反序列化后再次安装额外的方法?

附录

脚本语法或多或少像这样工作:

考虑文件src/cicd/pipeline/SomePipeline.groovy的内容:

package cicd.pipeline

// there is no need to wrap everything inside class SomePipeline,
// since it is implicit

def method() {
  // instance method, here I can access pipeline steps freely
}

def static otherMethod() {
  // static method, here it is unable to access pipeline steps
  // without a instance
}

@groovy.transform.Field
def field

def call() {
  // if the class is used as method it will run
  this.method()
  SomePipeline.otherMethod() // or simply otherMethod() should work
  this.field = 'foo'
  println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"
}

// any code other than methods or variables with @Field
// annotation will be inside a implicit run method that is
// triggered likewise main method but isn't a static one
def localVar = 'foo'
println "It will not execute on constructor since it is on run: $localVar"
println "Method: ${org.codehaus.groovy.runtime.StackTraceUtils.sanitize(new Throwable()).stackTrace[0].methodName}"
println "this instance ${this.getClass().canonicalName} should be cicd.pipeline.SomePipeline"

如果我要使用 Java 详细语法,我将不得不将几乎所有内容都包装在 class SomePipeline 中,这在 groovy 中是隐含的,这是我想要保留的脚本语法。

【问题讨论】:

  • 你能分享一下预期的语法吗?
  • @daggett 很难说它会是什么,因为这就是我所要求的,我链接的问题表达了我所期望的感受,但我会尝试更好地描述它。

标签: groovy jenkins-pipeline shared-libraries jenkins-groovy


【解决方案1】:

我意识到 this.getClass().superclass.canonicalName 当 Jenkins 管道外部是 groovy.lang.Script 并且当内部管道是 org.jenkinsci.plugins.workflow.cps.CpsScript 并且基于 this resource 时,我能够详细说明以下解决方案:

abstract class CustomScript extends org.jenkinsci.plugins.workflow.cps.CpsScript {
  public CustomScript() {
    // do something here, it will always execute regardless
    // serialization, and before everything
  }
}

@groovy.transform.BaseScript CustomScript baseScript

就是这样,按预期工作!当然,您可以更好地阐述此解决方案,以减少重复并避免内部类,但我会留给您想象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 2011-03-11
    • 2018-09-26
    • 2013-05-29
    相关资源
    最近更新 更多