简体   繁体   English

在多个工作中重复使用jenkins管道的各个阶段

[英]Reusing stages of a jenkins pipeline in multiple jobs

My team is moving to Jenkins 2 and I am using the pipeline plugin so that our build can live in our repository. 我的团队正在转向Jenkins 2,我正在使用管道插件,以便我们的构建可以存在于我们的存储库中。 Because getting repositories allocated has lots of overhead in our company we have a single respository with many sub-projects & sub-modules in it. 因为在我们公司中获得分配的存储库有很多开销,所以我们有一个存储库,其中包含许多子项目和子模块。

What I want is separate builds and reporting of Junit/checkstyle/etc reports for each sub-module as well as a final "build and deploy" step for each sub-project putting it all together. 我想要的是为每个子模块单独构建和报告Junit / checkstyle / etc报告,以及每个子项目的最终“构建和部署”步骤。

My current plan is to create separate jobs for each sub-module so that they get their own junit/checkstyle/etc reports page. 我目前的计划是为每个子模块创建单独的作业,以便他们获得自己的junit / checkstyle / etc报告页面。 Then have a multi-job project to orchestrate the sub-module builds for the sub-projects. 然后有一个多作业项目来为子项目编排子模块构建。 Since all of the sub-projects are simple jar builds, I want to put bulk of the logic in a common file, lets call it JenkinsfileForJars at the root of the sub-project. 由于所有子项目都是简单的jar构建,我想将大量逻辑放在一个公共文件中,让我们在子项目的根目录中调用它为JenkinsfileForJars。 So the repo structure is 回购结构是

  • sub-project 子项目
    • JenkinsfileForJars.groovy JenkinsfileForJars.groovy
    • sub-moduleA 子moduleA
      • Jenkinsfile Jenkinsfile
    • sub-moduleB 子moduleB
      • Jenkinsfile Jenkinsfile

My Jenkinsfile contains 我的Jenkinsfile包含

def submoduleName = "submoduleA"
def pipeline
node {

    pipeline = load("${env.WORKSPACE}/subproject/JenkinsfileForJars.groovy")

}
pipeline.build()
pipeline.results()

And my JenkinsfileForJars contains 我的JenkinsfileForJars包含

def build() {

    stage('Build') {
        // Run the maven build
        dir("subproject") {
            sh "./gradlew ${submoduleName}:build"
        }

    }
}
def results() {

    stage('Results') {
        dir("subproject/${submoduleName}") {
            junit 'build/test-results/TEST-*.xml'
            archive 'build/libs/*.jar'
            publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: 'build/reports/cobertura/', reportFiles: 'frame-summary.html', reportName: 'Cobertura Report'])
            publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: 'build/reports/findbugs/', reportFiles: 'main.html', reportName: 'Fidbugs Report'])
            publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: false, reportDir: 'build/reports/pmd/', reportFiles: 'main.html', reportName: 'PMD Report'])
            step([$class: 'CheckStylePublisher', pattern: 'build/reports/checkstyle/main.xml', unstableTotalAll: '200', usePreviousBuildAsReference: true])
        }
    }

}

return this;

When I run the Jenkinsfile above I get the following error: 当我运行上面的Jenkinsfile时,我收到以下错误:

Running on master in /var/lib/jenkins/workspace/jobA
[Pipeline] {
[Pipeline] load
[Pipeline] { (/var/lib/jenkins/workspace/jobA/subproject/JenkinsfileForJars.groovy)
[Pipeline] }
[Pipeline] // load
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
java.lang.NullPointerException: Cannot invoke method build() on null object

As far as I can tell, I am following what is shown in the documents for loading manual scripts and the example given for a loaded script. 据我所知,我正在关注加载手动脚本的文档中显示的内容以及为加载的脚本提供示例 I do not understand why my script is null after the load command. 我不明白为什么我的脚本在load命令后为null。

How do I get my Jenkinsfile to load JenkinsfileForJars.groovy? 如何让我的Jenkinsfile加载JenkinsfileForJars.groovy?

The problem is related to the SCM checkout as mentioned by Blake Mitchell in the comment above. 问题与Blake Mitchell在上述评论中提到的SCM结账有关。 Since you are loading your groovy functions from a submodule, you will need to checkout the submodule first, preferably on a build agent /slave, if you would like to keep only bare repos on the master. 由于您正在从子模块加载groovy函数,因此如果您只想在主服务器上保留裸存储库,则需要首先检出子模块,最好是在构建代理/从服务器上。

def pipeline
node( 'myAgentLabel' ) {
    stage ( 'checkout SCM' ) {
        checkout([
            $class: 'GitSCM'
            ,branches: scm.branches
            ,extensions: scm.extensions 
                + [[ $class: 'SubmoduleOption', disableSubmodules: false, parentCredentials: true, recursiveSubmodules: true, reference: '', trackingSubmodules: false]]
            ,doGenerateSubmoduleConfigurations: false
            ,userRemoteConfigs: scm.userRemoteConfigs
        ])
        pipeline = load( "${env.WORKSPACE}/path/to/submodule/myGroovyFunctions.grooovy" )
    }
    pipeline.build()
}

Note that in the checkout example, access to scm.* attributes also needs to be whitelisted by an administrator in Jenkins (In-process script approval) 请注意,在结帐示例中,访问scm。*属性也需要由Jenkins中的管理员列入白名单(进程内脚本批准)

There might be two possible problems: 可能存在两个可能的问题:

  • Why do you put the load in a node structure. 为什么要将负载放在节点结构中。 This import does not need computational resources, so you do not need it there. 此导入不需要计算资源,因此您不需要它。
  • The call to build should be put inside a node structure. 对构建的调用应放在节点结构中。 And probably the call to result should also be inside (the same) node structure to make sure, that the correct results are archived (if you use more than one (slave) nodes). 并且可能对结果的调用也应该在(相同的)节点结构内,以确保归档正确的结果(如果使用多个(从属)节点)。

(This should probably be a comment below your question but I do not have enough points to add a comment there.) (这应该是你问题下方的评论,但我没有足够的积分在那里添加评论。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM