如何在沙盒管道脚本中将 Jenkins 配置为从 Artifactory @Grab 依赖项

use*_*557 5 jenkins-groovy jenkins-pipeline

我可以在沙盒和非沙盒模式下在 Jenkins 管道脚本中使用 @Grab 注释。我的问题是,默认情况下,依赖项是针对 Maven 中央存储库解决的,但我需要针对我们公司的 Artifactory 解决它们。为了演示这个问题,这里有一个简单的管道脚本:

//@Grab(group = 'my.compay', module='my-module-name', version='1.0.0-SNAPSHOT')
//import my.company.MyFancyClass
@Grab('com.google.guava:guava:23.0')
import com.google.common.base.Joiner

pipeline {
    agent any
    stages {
        stage('Grape Test') {
            steps {
                echo "Joiner: ${Joiner.class}"
                // echo "MyFancyClass: ${MyFancyClass.class}"
            }
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

当我按原样运行脚本时,我将在输出中看到类的完全限定名称。但是,当我取消注释与公司工件脚本中公开的依赖项一起使用的注释行时,会失败并显示以下内容:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 2: unable to resolve class my.company.MyFancyClass
 @ line 1, column 1.
   @Grab(group = 'my.company', module='my-module-name', version='1.0.0-SNAPSHOT')

1 error
Run Code Online (Sandbox Code Playgroud)

经过调查,我发现 @Grab 使用 Groovy 特定的东西,称为 Grape,如下所述。提到的文档描述了如何使用文件 ~/.groovy/grapeConfig.xml 中的 ivy 设置将 Grape 配置为使用您自己的存储库。我找到了解决方案,并使其适用于常规 Groovy 代码,内容如下:

<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<credentials host="localhost" realm="Artifactory Realm" username="USERNAME" passwd="PASSWORD"/>
<resolvers>
  <chain name="downloadGrapes" returnFirst="true">
    <filesystem name="cachedGrapes">
      <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/>
      <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision](-[classifier]).[ext]"/>
    </filesystem>
    <ibiblio name="localm2" root="file:${user.home}/.m2/repository/" checkmodified="true" changingPattern=".*" changingMatcher="regexp" m2compatible="true"/>

    <ibiblio name="maven-release" m2compatible="true" root="http://artifactory:8081/artifactory/maven-release"/>
    <ibiblio name="maven-snapshot" m2compatible="true" root="http://artifactory:8081/artifactory/maven-snapshot"/>
    <!-- todo add 'endorsed groovy extensions' resolver here -->
    <ibiblio name="jcenter" root="https://jcenter.bintray.com/" m2compatible="true"/>
    <ibiblio name="ibiblio" m2compatible="true"/>
  </chain>
</resolvers>
</ivysettings>
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个ivy配置文件仅部分解决了我的问题,并且使Grapes仅从常规Groovy代码按预期工作(与从CLI调用grape命令相同)。

我不知道 Jenkins 如何使用 Groovy/Grapes,但它显然忽略了该文件的默认位置。我阅读了一些 Ivy 文档,发现可以自定义一些 Ivy 设置,例如使用属性配置文件位置。这就是为什么我尝试说服 Jenkins 通过使用以下命令从 CLI 运行它来有效地使用我的配置:

java -Divy.settings.file=%USERPROFILE%\.groovy\grapeConfig.xml -jar jenkins.war --httpPort=8888
Run Code Online (Sandbox Code Playgroud)

这确实有效,但令我惊讶的是,这只是部分有效!仅当我关闭管道脚本的沙箱模式时,它才有效。如果我打开它,我再次能够仅从 Maven Central @Grab 依赖项。

任何想法都非常受欢迎...

use*_*557 4

由于我没有收到任何答案,我进一步进行了调查并得出了有趣的结论。首先让我们看一下修改后的管道脚本:

@Grab('com.google.guava:guava:23.0')
import com.google.common.base.Joiner

pipeline {
    agent any
    stages {
        stage('Grape Test') {
            steps {
                echo "Joiner: ${Joiner.class}"
                 script {
                    Joiner.class.getClassLoader().getURLs().each { url ->
                        println url.toExternalForm()
                    }
                }
           }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我在沙盒模式下运行了这个脚本,其中对 Guava 的依赖似乎从 Maven Central 得到了满足。令人惊讶的是,我发现 Joiner 是从其他地方获取的,如缩短的输出所示:

...

[Pipeline] echo
Joiner: class com.google.common.base.Joiner

...

[Pipeline] echo
file:/C:/Users/mrohac/.jenkins/war/WEB-INF/lib/guava-11.0.1.jar

...

Run Code Online (Sandbox Code Playgroud)

因此,这个测试证明 @Grab 在沙盒模式下在导入工作并从类路径加载类时被默默地忽略。这让我得出这样的结论:在管道脚本中使用用 Java 编写的专有代码的唯一方法是将相关依赖项放在类路径上。

因此,在管道脚本中启用自定义 Java 代码的结论是将相关依赖项放在类路径上。对于我来说,作为 Jenkins 新手,实现这一目标的最佳方法是什么是值得怀疑的。无论如何,我可以确认将依赖项~/.jenkins/war/WEB-INF/lib/有效地添加到管道脚本中可以使用所需的类。

当然,这可能意味着新的问题,特别是与 Jenkins 的整体稳定性相关,这些问题可能会因类路径上的冲突而受到损害。无论如何,我希望可以使用自定义 Java 代码扩展管道脚本,尽量减少对 Jenkins 稳定性的影响,例如通过引入专用管道插件来注册和加载此类依赖项。