Jenkins管道作业DSL

3
我想在流水线步骤中运行一个 job-dsl 脚本。一般来说,这应该是可能的,如 此处 所述。以下代码片段已添加到流水线步骤中:
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 的脚本位于不同的工作区。设置如下:
  • 1个 GitHub 组织
  • 该组织内有2个存储库
  • 1个存储库包含用 Groovy 代码编写的共享库/作业构建器
  • 1个存储库包含多个 .Net 解决方案,并在根目录中具有 Jenkinsfile
共享库存储库已添加为“管理 Jenkins->配置系统”中的全局流水线库,并对每个流水线(例如 Jenkinsfile)进行了隐式加载。
现在,实际代码存储库中的管道非常小。它只转发到共享库中的管道定义。
#!/usr/bin/env groovy

dotNetStandardPipeline {
  message = "Hello World!"
}

这个功能非常好用,因为全局管道库被隐式导入。这个dotNetStandardPipeline 包含了上面提到的步骤,尝试使用一个目标设置为与dotNetStandardPipeline本身在同一仓库中的DotNetJob.groovy脚本调用jobDsl管道步骤。
现在问题似乎是,在“代码仓库”的工作区执行管道,因此路径“src/breuer/jenkins/utils”不存在。
我如何知道脚本的真实位置,并指定一个作为目标的jobDsl,它本身存在于另一个仓库?或者我完全走错了吗?
编辑
经过进一步的调查,事实似乎是共享库存储库被检出到与“真实”工作区相邻的目录中,具有@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$8.call(Unknown Source)
at javaposse.jobdsl.plugin.ScriptRequestGenerator.readFile(ScriptRequestGenerator.groovy:103)

看起来,即使我能确定groovy文件的位置,调用它仍然是不可能的?!
注意:当将src目录直接复制到工作区并设置目标参数为src/breuer/jenkins...等时,它可以工作。
这是否意味着,groovy脚本必须与jenkinsfile在同一个代码库中?
编辑2:
由于很难用言语解释我的计划结构和思想,我创建了一个小演示组织,在GitHub上有两个演示存储库。here你可以找到包含两个C#解决方案和jenkinsfile的源代码存储库。自述文件描述了CI集成的计划。
包含groovy脚本的CI库位于here 编辑3和结论
对于大多数来到这里的人,请查看mkobit提供的被接受的答案(感谢您的努力!)。特别是解决实际问题的方法非常有帮助。将job-dsl脚本放入资源中绝对是一个选项。
与此同时,我采取了另一种方法,并想通报一下。
我已经在jenkins上使用了“GitHub组织”作业。目标是使这个成为唯一手动创建的工作,通过代码(即通过Jenkinsfile)创建所有其他所需的工作。
我要关心的真正存储库之一是一个规模巨大的repo,从svn移动到git,其中包含约300个.Net解决方案。每个这些解决方案都应该由jenkins上的单独的作业构建。我们可以在管道内部执行此操作,但这意味着要在管道中拥有很多阶段,或者一开始就没有有关单独失败解决方案的信息。 因此,我必须为每个解决方案动态构建单独的工作。
代码仓库本身不应该被大量的Jenkins相关内容污染,因此我想严格分离这两个东西。
现在,我决定手动创建一个自由风格任务作为种子任务,并添加一些参数(工作区、项目、分支等)。
然后,流水线将触发种子任务的构建,种子任务将使用所需信息运行job-dsl。
在流水线中完成这个阶段后,流水线将触发所需任务的构建。
这可能不是最优雅的解决方案,但通过这种方法,我可以实现一个完全自动化、在代码中定义的Jenkins环境,只需要手动创建两个任务。

你说你在GUI中添加了共享库并隐式加载它。为什么你要使用jobDsl的相对路径来定位它,而不是直接使用jenkins-pipeline DSL呢? - Matt Schuchard
据我所了解,Job-DSL和Pipeline有些不同,不能混合使用。例如,在Pipeline中,我无法执行def myJob = job('jobName)这样的操作。您只能执行步骤jobDsl,该步骤可以获取脚本文本或要执行的目标... - Tobias Breuer
你关于它们是不同的“DSL”是正确的 - 它们在完全不同的上下文中运行,Job DSL插件提供了一个入口点来通过管道运行它。我很难弄清楚你想在哪里运行Job DSL(jobDsl步骤),以及使用什么内容。此外,你是说你的jobDsl脚本与全局管道库位于同一源代码中吗? - mkobit
@mkobit,请查看我的第二次编辑。我已经链接了一个在Github上的演示组织,希望能够澄清我的计划...我真的很怀疑我是否在正确的轨道上... - Tobias Breuer
1个回答

2
GitHub Branch Source插件实现了以下几个功能:
  • 扫描一个或多个GitHub组织
  • 为每个存储库生成文件夹作业
  • 每个文件夹扫描有Jenkinsfile(使用默认配置)的重要事项(拉取请求、分支等)
  • 为每个重要事项生成管道作业
  • 每个管道作业可以自动通知GitHub构建状态(例如在拉取请求上)
  • 我确定我错过了其他重要功能
它可以通过轮询或监听事件(例如拉取请求创建、拉取请求更新、分支和其他SCM事件)进行操作。
我认为为每个仓库生成带有jobDsl步骤的作业的Jenkinsfile的想法可能会过于复杂(当然这取决于您的最终目标)。 Jenkins管道的好处之一是能够将构建定义指定为代码。在此示例中,您正在定义构建项目的其他作业。为什么不让Jenkinsfile自己构建存储库,并借助全局库来定义常用路径?您已经使用GitHub分支源插件提供了作业生成和扫描,因此让Jenkinsfile完成构建过程的艰苦工作吧。
如果这还没有说服您或者我没有完全理解您的用例,请让我们尝试解决您遇到的问题。

在你的方法中,有几个不同的考虑和限制需要考虑。

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

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

附加类路径 选项要求文件也在工作区中。它还有一个额外的要求,即文件必须是类文件/JAR/适用于 JVM 类路径的东西。这意味着在使用 Job DSL 之前,您必须组装这些工件,这将很难进入消耗您库的作业。

共享库从源代码加载,然后 Jenkins 管道使用其特殊编译器为执行准备。

我可以想到一些不同的选项和细节:

  1. 不要在您的全局库中使用additionalClasspath——因为它需要构建类(本质上),您将不得不编译您的辅助类。
  2. 使用jobDsl(scriptText: '<JOB_DSL_TEXT_DIRECTLY>')——您会失去一些测试Job DSL代码的能力,但仍然可以进行集成式测试以查看创建了哪些作业。(即将到来的插件)我构建了一个Gradle插件,允许您测试共享库,这可能有助于测试方面。
  3. 如果您想要保持您的Job DSL Groovy脚本分离,您可能需要将其放在共享库的resources目录中,仍然使用scriptText选项。例如,如果脚本位于resources/breuer/jenkins/utils/DotNetJob.groovy,并且已加载您的共享库,您可以执行类似于jobDsl(scriptText: libraryResource('resources/breuer/jenkins/utils/DotNetJob.groovy'))的操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接