Jenkins 管道作业-dsl

Jenkins pipeline job-dsl

我正在尝试从管道步骤中 运行 一个 job-dsl 脚本。一般来说,这应该是可能的,如 here 所述,在管道步骤中添加了以下代码片段:

stage('Add new jobs') {
  steps {
    echo 'Scanning...'
    jobDsl(additionalClasspath: 'src/breuer/jenkins/utils', removedJobAction: 'DELETE', removedViewAction: 'DELETE',
       targets: 'src/breuer/jenkins/utils/DotNetJob.groovy', unstableOnDeprecation: true)
  }
}

当运行连接这个管道时,Jenkins 会抱怨

ERROR: no Job DSL script(s) found at src/breuer/jenkins/utils/DotNetJob.groovy
Finished: FAILURE

为了测试目的,DotNetJob.groovy 的内容如下所示:

#!/usr/bin/env groovy
package breuer.jenkins.utils

import javaposse.jobdsl.dsl.Job

def solutions = findFiles glob: '**/*.sln'
echo "Solution count: ${solutions.size()}"

job("TestDotNet") {
  steps {
    shell 'echo Hello from new DotNet job'
  }
}

我认为,问题在于管道作业和包含作业 dsl 的脚本位于不同的工作空间中。设置如下:

共享库回购已作为全局管道库添加到管理詹金斯->配置系统中,并为每个管道隐式加载(例如 Jenkinsfile)

现在实际代码库中的管道非常小。它只是转发到共享库中的管道定义:

#!/usr/bin/env groovy

dotNetStandardPipeline {
  message = "Hello World!"
}

这很有魅力,因为全局管道库是隐式导入的。此 dotNetStandardPipeline 现在包含上述步骤,尝试调用 jobDsl 管道步骤并将目标设置为 DotNetJob.groovy 脚本,位于与 dotNetStandardPipeline 本身相同的 repo 中。
现在的问题似乎是,管道是在 'Code-Repository' 的工作区中执行的,因此路径 'src/breuer/jenkins/utils' 不存在。

我如何才能知道脚本的真实位置以及如何将 jobDsl 指定为目标,它本身位于不同的存储库中?还是我走错了路?

编辑

经过进一步调查,共享库存储库被检出到 "real" 工作区旁边的目录,似乎是事实 @libs后缀。所以我认为使用以下方法是个好主意:

script {
    def wsName = "${WORKSPACE}".split("\\")[ -1 ]
    echo "wsName: ${wsName}"
    echo "RelDir: ../${wsName}@libs/breuer-jenkins-lib/src/breuer/jenkins/utils/DotNetJob.groovy"
    jobDsl(removedJobAction: 'DELETE', removedViewAction: 'DELETE',
                    targets: "../${wsName}@libs/breuer-jenkins-lib/src/breuer/jenkins/utils/DotNetJob.groovy", unstableOnDeprecation: true)
}

不幸的是,这似乎完全破坏了某些东西,因为现在 jenkins 会在构建的输出中抱怨以下消息:

java.nio.file.AccessDeniedException: D:\Road to Git\Jenkins\JenkinsGit\workspace\t_TestCIIntegration_develop-RKLAJXSET2S232SE6RNISESVW75KUNU4E3CPSAAP42MHZAGO6Z2A\.git
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(Unknown Source)
at java.nio.file.Files.newByteChannel(Unknown Source)
at java.nio.file.Files.newByteChannel(Unknown Source)
at java.nio.file.spi.FileSystemProvider.newInputStream(Unknown Source)
at java.nio.file.Files.newInputStream(Unknown Source)
at hudson.FilePath.read(FilePath.java:1771)
at hudson.FilePath$read.call(Unknown Source)
at javaposse.jobdsl.plugin.ScriptRequestGenerator.readFile(ScriptRequestGenerator.groovy:103)

这么看来,即使我能够确定 groovy 文件的位置,仍然无法调用它?!

注意:当直接将src目录复制到工作空间中,然后将target参数设置为src/breuer/jenkins...等等,就可以了

这是否意味着 groovy 脚本 必须 与 jenkinsfile 在同一个 repo 中??

编辑 2

由于很难用文字解释我的计划背后的结构和想法,我在 GitHub 上创建了一个带有两个演示存储库的小型演示组织。 here 您可以找到包含两个 C# 解决方案和 jenkinsfile 的源代码存储库。自述文件描述了 CI 集成的计划。
包含 groovy 脚本的 CI 库位于 here

编辑 3 和结论

对于大多数来到这里的人,请查看mkobit给出的已接受答案(感谢您的努力!)。特别是解决实际问题的方法真的很有帮助。将 job-dsl 脚本放入资源绝对是一种选择。

同时我采用了另一种方法,我想告知一下这个方法。
我已经在 jenkins 上使用了 "GitHub Organization" 作业。目的是让它成为 唯一 手动创建的作业,并通过代码(即通过 Jenkinsfile)创建所有其他必需的作业。
我必须关心的一个真正的存储库是一个大量增长的存储库,从 svn 移动到 git,其中包含大约 300 个 .Net 解决方案。这些解决方案中的每一个都应由 jenkins 上的单独作业构建。我们 可以 在管道本身内执行此操作,但这将意味着以太在管道中有很多阶段,或者乍一看没有关于个别失败解决方案的信息。 因此,我必须为每个解决方案动态构建单独的作业。

代码库本身不应该被很多与 jenkins 相关的东西污染,所以我想严格区分这两件事。
现在,我决定不再让管道调用 job-dsl 脚本,而是在 jenkins 中手动创建一个 Freestyle-Job。这用作 Seed-Job 并具有一些参数(工作区、项目、分支等)。
现在管道将触发种子作业的构建,然后 运行 使用所需信息发送作业 dsl。
管道中的这个阶段完成后,管道将随后触发所需作业的构建。

这可能不是最优雅的解决方案,但通过这种方法,我实现了一个完全自动化的、在代码中定义的 jenkins 环境,只有两个手动创建的作业。

GitHub Branch Source 插件完成了一些事情:

  • 扫描一个或多个 GitHub 个组织
  • 为每个存储库生成一个文件夹作业
  • 每个文件夹都会扫描具有 Jenkinsfile(默认配置)
  • 的重要内容(拉取请求、分支等)
  • 每个值得注意的事物都有一个为其生成的管道作业
  • 每个管道作业可以自动通知 GitHub 构建状态(比如在拉取请求中)
  • 我确定我还缺少其他值得注意的功能

它可以通过轮询或监听事件来操作,例如拉取请求创建、拉取请求更新、分支和其他 SCM 事件。

我认为让每个存储库使用 jobDsl 步骤生成作业的 Jenkinsfile 的想法可能过于复杂(当然取决于您期望的最终目标)。 Jenkins Pipelines 的好处之一是能够将构建定义指定为代码。在此示例中,您将定义其他作业来构建项目。为什么不让 Jenkinsfile 自己构建存储库,在全局库的帮助下定义公共路径?您已经有了 GitHub Branch Source 插件提供的作业生成和扫描,所以让 Jenkinsfile 完成构建过程的艰苦工作。

好的,如果这不能令人信服或者我不完全理解您的用例,让我们尝试解决您 运行 遇到的问题。


您在方法中必须考虑一些不同的注意事项和限制

jobDsl 步骤可以通过几种不同的方式提供作业脚本:

  1. jobDsl(targets: 'ant/pattern/for/job/files/*.groovy') - 文件从工作区提供,目标可以是 Ant pattern
  2. jobDsl(scriptText: "folder('myFolder')") - 直接提供脚本文本

附加类路径 选项要求文件也位于工作区中。它还有一个额外的要求,即文件是在 JVM 类路径上工作的 classfiles/JARs/things。这意味着您必须先 assemble 工件,然后才能将它们与作业 DSL 一起使用,这对于进入消耗您的库的作业来说会很痛苦。

共享库从源代码加载,然后 Jenkins Pipelines 使用它的特殊编译器准备执行。

我可以从这些选项中想到几个不同的选项和细节:

  1. 不要在你的全局库中使用 additionalClasspath - 因为它需要构建 类 (本质上)你将不得不编译你的助手 类
  2. 使用 jobDsl(scriptText: '<JOB_DSL_TEXT_DIRECTLY>') - 您失去了一些仅测试作业 DSL 代码的能力,但您仍然可以进行集成样式测试以查看创建了哪些作业。 (插件传入)我建了一个Gradle plugin that allows you to test shared libraries,这样可能对测试方面有帮助。
  3. 如果你想将你的 Job DSL Groovy 脚本分开,你可能必须将它放在共享库的 resources 目录中,并且仍然使用 scriptText 选项。例如,如果脚本位于 resources/breuer/jenkins/utils/DotNetJob.groovy 并且您的共享库已加载,您可以执行类似 jobDsl(scriptText: libraryResource('resources/breuer/jenkins/utils/DotNetJob.groovy'))
  4. 的操作