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 依赖项。
任何想法都非常受欢迎...
由于我没有收到任何答案,我进一步进行了调查并得出了有趣的结论。首先让我们看一下修改后的管道脚本:
@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 稳定性的影响,例如通过引入专用管道插件来注册和加载此类依赖项。