groovy 从同一存储库加载Jenkins Pipeline共享库

3ks5zfa0  于 2022-11-01  发布在  Jenkins
关注(0)|答案(8)|浏览(279)

TL;DR是否有办法将代码从本地 * 存储库导入到Jenkinsfile * 中(而不是load步骤)?
为什么?
我曾经经历过,对于复杂的构建,Jenkinsfile会变得有点笨重,而且不是很容易维护。
既然构建工作是代码,那么拥有与其他代码相同的方法就太好了。也就是说,我想把它分成更小的(更易维护的)单元,并对它们进行 * 单元测试 *。

我所尝试的#

  • shared libraries:允许将Jenkins Pipeline逻辑划分为单独模块中的较小文件,甚至对其进行单元测试。

但是,它们需要在不同的存储库中,并且(如果不在GitHub上)必须配置到Jenkins中。

  • load步骤:允许从存储库加载groovy * 脚本 *。

然而,文件必须是脚本,而不是“完整的”groovy类,这使得多个文件或类很难相互依赖,例如继承是不可能的。
此外,在Jenkins作业上执行重放时不会显示这些文件,这使得它们很难开发和调试。

我的问题

  • 是否有办法(或解决方法)在与Jenkinsfile相同的存储库中创建一个共享库,并将此库导入Jenkinsfile
  • 还是还有别的方法我没试过?

目录结构示例

shared libs的目录结构类似,我希望在单个存储库中拥有以下内容 *。

(root)
+- someModule
|   +- ...
+- jenkins           # Classes/Scripts used by Jenkins in a separate module
|   +- src                       # Groovy source files
|      +- org
|          +- foo
|              +- Bar.groovy     # for org.foo.Bar class
|   +- test                      # Groovy test files
|      +- org
|          +- foo
|              +- BarTest.groovy # Test for org.foo.Bar class
|   +- pom.xml or build.groovy   # Build for local library
+- Jenkinsfile     # Build "someModule", uses classes from "jenkins" module
klr1opcd

klr1opcd1#

解决方法:

library identifier: 'shared-library@version', retriever: legacySCM(scm)

目前在PR 37中采用的方法将不能与构建代理一起正常工作,而且无论如何,它只适用于使用library步骤的脚本,而不适用于@Library注解。
load步骤加载的文件 * 确实 * 出现在Replay中。但是您的脚本确实不能静态引用这些文件中定义的类型。换句话说,您可以模拟库vars/*.groovy,但不能模拟src/**/*.groovy-与当前PR 37的限制相同。

monwx1rj

monwx1rj2#

我 想 正确 方法 是 实现 一 个 自 定义 的 SCMRetriever
但是 , 您 可以 使用 以下 方法 :
假设 本地 存储 库 中 的 jenkins/vars/log.groovy 包含 :

def info(message) {
    echo "INFO: ${message}"
}

中 的 每 一 个
您 的 Jenkinsfile 可以 使用 library 步骤 从 jenkins/ 目录 加载 该 共享 库 :

node('node1') { // load library
    checkout scm
    // create new git repo inside jenkins subdirectory
    sh('cd jenkins && git init && git add --all . && git commit -m init &> /dev/null') 
    def repoPath = sh(returnStdout: true, script: 'pwd').trim() + "/jenkins"
    library identifier: 'local-lib@master', retriever: modernSCM([$class: 'GitSCMSource', remote: repoPath])
}

node('node2') {
    stage('Build') {
        log.info("called shared lib") // use the loaded library
    }
}

格式

tnkciper

tnkciper3#

你可以看看我写的插件,它允许使用repo的子目录,你的管道是作为共享库:https://github.com/karolgil/SharedLibrary
在构建和安装它之后,您可以简单地将以下内容放入您的管道中:

@SharedLibrary('dir/in/repo') _

开始使用dir/in/repo作为管道的共享库。

okxuctiv

okxuctiv4#

想做同样的事情,最终创造了这个:
https://github.com/jenkinsci/workflow-cps-global-lib-plugin/pull/37
下面是我如何使用它:
https://github.com/syndesisio/syndesis-pipeline-library/blob/master/Jenkinsfile#L3
在我的例子中,我想创建一个Jenkinsfile,它实际上是存储库包含的管道库的tests
让我知道你的想法,并随时添加您的意见公关太多。

ve7v8dk2

ve7v8dk25#

我发现Pawel的版本有问题,如果你从SCM(不是嵌入在Jenkins作业UI配置)检查管道。这是我的版本为这些情况:

node {
    def scriptFolder = sh(script: "echo \$(pwd | sed 's,\\(.*\\)\\(@[0-9]*\$\\),\\1,')@script/\$(sed -n '2,\$p' ../config.xml | xmllint --xpath '(//scriptPath/text())' - | xargs dirname)", returnStdout: true).trim()
    sh("cd ${scriptFolder} && ls -l vars/ && if [ -d .git ]; then rm -rf .git; fi; git init && git add --all . && git commit -m init &> /dev/null")
    library identifier: 'local-lib@master', retriever: modernSCM([$class: 'GitSCMSource', remote: scriptFolder])

    stage('Build') {
        log.info("called shared lib") // use the loaded library
    }
}

在这些情况下,管缐本身会在与管缐本身定义的工作区不同的工作区(相同的目录名称,但名称中有@script)中出库。

9fkzdhlc

9fkzdhlc6#

我已经成功地测试了一个简单的解决方案,用于同时使用HTTPS和SSH两种协议的GIT存储库(我使用BitBucket),只需如下配置Jenkins作业(指向相同的存储库,但强制使用不同的获取方法):

  • 在“分支源”中,添加“通过SSH checkout ”选项
  • 在管道库-〉源代码管理-〉项目库中使用HTTPS协议-例如类似https://...
flseospp

flseospp7#

是否有方法将代码从本地存储库导入到Jenkinsfile中(而不是加载步骤)?
是否有方法(或解决方法)在Jenkinsfile所在的存储库中创建一个共享库,并将此库导入Jenkinsfile?
是的。如果***“共享库资料档案库的目录结构”***符合规范,则它绝对可行,不需要任何解决方法即可使其正常工作。基本上,您的目录结构需要沿着以下方式进行调整:

+- src                     # Groovy source files
|   +- org
|       +- foo
|           +- Bar.groovy  # for org.foo.Bar class
+- vars
|   +- foo.groovy          # for global 'foo' variable
|   +- foo.txt             # help for 'foo' variable
+- resources               # resource files (external libraries only)
|   +- org
|       +- foo
|           +- bar.json    # static helper data for org.foo.Bar
+- someModule
|   +- ...
|
|
+- Jenkinsfile

这个答案并不是基于猜测。虽然没有文档记录,但我已经在多个项目和培训中应用了这个模式,而且它很有效。你不需要像往常那样修改你的工作配置。

yvfmudvl

yvfmudvl8#

我的共享库管道可以自我测试。它有点笨重,但它的工作。
我所要做的就是将库本身导入到库的repo中的Jenkinsfile中。实际的管道在/vars中定义为myPipeline.groovy--它采用声明式语法,使用Jenkins提供的Delegate模式来接收参数,并且尽一切努力将所有实际代码放入库步骤中,使DSL管道尽可能干净。

// repo's Jenkinsfile
library 'my-shared-library'

myPipeline {
  myParam1 = 'value1'
  myParam2 = 'value2'
}

在测试新的东西时,一定要记住拉下正在处理的分支:

// repo's Jenkinsfile
library 'my-shared-library@my-new-branch`
...

您可以将实际的单元测试写入/test/com/myOrg/目录;我使用the plain JenkinsPipelineUnit framework,它可以完成工作,但是很笨重。我最终使用Gradle来执行构建和测试。它很慢,但是可以完成工作。
或者,你可以在一个特别的管道中在实际的Jenkinsfile中测试你的/vars步骤。这有时比在单元中模拟所有的东西要容易,特别是如果你最终模拟了你想测试的东西,这就违背了目的。
load()绝对应该提供载入的指令码,以便在Replay中进行编辑。如果没有,则可能发生其他状况。
最后,我强烈建议在您的开发机器上设置一个Jenkins示例,这样您就可以测试更改而无需推送它们。特别是如果您创建了一个ad-hoc管道来测试您的步骤,那么您可以在Replay中编辑管道,为您自己创建最短的反馈循环。要想更快地进行测试,请熟悉在脚本控制台中测试groovy。或者使用Gradle run从命令行实际运行更复杂的代码。任何避免等待代码推送和管道运行的方法都将使您的开发进行得更快。
注意脚本控制台上的警告,readJson/readYaml不能正常工作,我相信其他的也是如此。当我需要测试类似的东西时,我倾向于使用ad-hoc管道来快速迭代代码。

相关问题