Jenkins - 在一个作业中多次加载 groovy 脚本,但有不同的阶段
Jenkins - load groovy script multiple times in a single job but with different stages
我有一个 Jenkins 管道,它在脚本管道中执行构建和部署任务。管道在中央存储库中维护。对于每个部署阶段,它都会等待用户输入,等待时间可能长达数天。在等待期间,如果管道脚本发生变化,我希望在部署批准(用户输入)后加载最新的脚本。
脚本的第一步 load
工作正常,当我尝试再次加载时,出现以下错误。似乎是 GroovyClassLoader 抛出了这个错误。
我试图通过 currentBuild.rawBuild.getExecution().loadedScripts
删除 loadedScripts
但这没有帮助。有没有办法实现我在每个阶段重新加载脚本的用例?任何指针都会有所帮助。
java.lang.LinkageError: loader org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$CleanGroovyClassLoader @8d141543 attempted duplicate class definition for Script1. (Script1 is in unnamed module of loader org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$CleanGroovyClassLoader
// pipeline.groovy
def config
node('agent') {
stage('build') {
config = loadScripts()
echo 'perform some tasks'
}
stage('deploy-dev') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
stage('deploy-sit') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
// somepath/external.groovy
class JobConfig {
def someDataVar1
def someDataVar2
}
def sayHello() {
println 'hello'
}
return this
也许我没有完全理解你的问题(在这种情况下,我深表歉意),但我不明白为什么你的 'somepath/external.groovy' 不是一个简单的 groovy 库,
(像这样:http://rtyler.github.io/jenkins.io/doc/book/pipeline/shared-libraries/),
在管道的开头声明为已使用,然后您的 JobConfig 和 sayHello 可以根据需要多次调用,并根据某些参数(例如阶段名称)具有不同的行为。
简短的回答是共享库旨在解决此类问题。如果这不是一个选项,那么对脚本文件进行一些重组可能会解决这个问题。
您收到的错误表明您正在重新定义 class 同名,这是不允许的。由于您第二次加载相同的脚本,这与加载同名的 class 两次基本相同。
选项 1 是将您的 管道 拆分为多个管道,这些管道都摄取相同的配置。我个人从来没有在 long-running 等待用户输入继续的管道方面获得好运。相反,您可以将您的管道拆分为一个“构建”管道,该管道基本上加载您的配置和 运行 构建步骤,然后稍后当您准备好部署时,您 运行 一个“deploy-dev" 加载配置的管道,然后 运行 是 deploy-dev 步骤。然后是另一个对“deploy-sit”执行相同操作的管道。
// pipeline-build.groovy
def config
node('agent') {
stage('build') {
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
// pipeline-deploy-dev.groovy
def config
node('agent') {
stage('deploy-dev') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
// pipeline-deploy-sit.groovy
def config
node('agent') {
stage('deploy-sit') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
选项 2 是将 脚本 拆分为多个脚本。一个脚本将包含 class 定义,并且只会在管道顶部加载一次。然后其他脚本将包含每个管道步骤将使用的每个其他方法。这看起来像这样:
// pipeline.groovy
def config
node('agent') {
loadScript("somepath/JobConfig.groovy")
stage('build') {
config = loadScript("somepath/Build.groovy")
echo 'perform some tasks'
}
stage('deploy-dev') {
input message: 'approve'
config = loadScript("somepath/DeployDev.groovy")
echo 'perform some tasks'
}
stage('deploy-sit') {
input message: 'approve'
config = loadScript("somepath/DeploySit.groovy")
echo 'perform some tasks'
}
}
def loadScript(def script) {
checkout scm
config = load script
return config
}
然后当您加载后面的脚本时,它们可以更新并加载,而无需重新定义初始 class 定义或重新定义各个方法(我想这也是一个问题)。
我有一个 Jenkins 管道,它在脚本管道中执行构建和部署任务。管道在中央存储库中维护。对于每个部署阶段,它都会等待用户输入,等待时间可能长达数天。在等待期间,如果管道脚本发生变化,我希望在部署批准(用户输入)后加载最新的脚本。
脚本的第一步 load
工作正常,当我尝试再次加载时,出现以下错误。似乎是 GroovyClassLoader 抛出了这个错误。
我试图通过 currentBuild.rawBuild.getExecution().loadedScripts
删除 loadedScripts
但这没有帮助。有没有办法实现我在每个阶段重新加载脚本的用例?任何指针都会有所帮助。
java.lang.LinkageError: loader org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$CleanGroovyClassLoader @8d141543 attempted duplicate class definition for Script1. (Script1 is in unnamed module of loader org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$CleanGroovyClassLoader
// pipeline.groovy
def config
node('agent') {
stage('build') {
config = loadScripts()
echo 'perform some tasks'
}
stage('deploy-dev') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
stage('deploy-sit') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
// somepath/external.groovy
class JobConfig {
def someDataVar1
def someDataVar2
}
def sayHello() {
println 'hello'
}
return this
也许我没有完全理解你的问题(在这种情况下,我深表歉意),但我不明白为什么你的 'somepath/external.groovy' 不是一个简单的 groovy 库, (像这样:http://rtyler.github.io/jenkins.io/doc/book/pipeline/shared-libraries/), 在管道的开头声明为已使用,然后您的 JobConfig 和 sayHello 可以根据需要多次调用,并根据某些参数(例如阶段名称)具有不同的行为。
简短的回答是共享库旨在解决此类问题。如果这不是一个选项,那么对脚本文件进行一些重组可能会解决这个问题。
您收到的错误表明您正在重新定义 class 同名,这是不允许的。由于您第二次加载相同的脚本,这与加载同名的 class 两次基本相同。
选项 1 是将您的 管道 拆分为多个管道,这些管道都摄取相同的配置。我个人从来没有在 long-running 等待用户输入继续的管道方面获得好运。相反,您可以将您的管道拆分为一个“构建”管道,该管道基本上加载您的配置和 运行 构建步骤,然后稍后当您准备好部署时,您 运行 一个“deploy-dev" 加载配置的管道,然后 运行 是 deploy-dev 步骤。然后是另一个对“deploy-sit”执行相同操作的管道。
// pipeline-build.groovy
def config
node('agent') {
stage('build') {
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
// pipeline-deploy-dev.groovy
def config
node('agent') {
stage('deploy-dev') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
// pipeline-deploy-sit.groovy
def config
node('agent') {
stage('deploy-sit') {
input message: 'approve'
config = loadScripts()
echo 'perform some tasks'
}
}
def loadScripts() {
checkout scm
config = load 'somepath/external.groovy'
return config
}
选项 2 是将 脚本 拆分为多个脚本。一个脚本将包含 class 定义,并且只会在管道顶部加载一次。然后其他脚本将包含每个管道步骤将使用的每个其他方法。这看起来像这样:
// pipeline.groovy
def config
node('agent') {
loadScript("somepath/JobConfig.groovy")
stage('build') {
config = loadScript("somepath/Build.groovy")
echo 'perform some tasks'
}
stage('deploy-dev') {
input message: 'approve'
config = loadScript("somepath/DeployDev.groovy")
echo 'perform some tasks'
}
stage('deploy-sit') {
input message: 'approve'
config = loadScript("somepath/DeploySit.groovy")
echo 'perform some tasks'
}
}
def loadScript(def script) {
checkout scm
config = load script
return config
}
然后当您加载后面的脚本时,它们可以更新并加载,而无需重新定义初始 class 定义或重新定义各个方法(我想这也是一个问题)。