我的团队正在迁移到Jenkins 2,并且我正在使用管道插件,以便我们的构建可以存在于我们的存储库中。因为分配存储库在我们公司中有很多开销,所以我们只有一个存储库,其中包含许多子项目和子模块。

我想要的是每个子模块的单独构建和Junit/checkstyle/etc报告的报告,以及每个子项目的最终“构建和部署”步骤,将它们放在一起。

我当前的计划是为每个子模块创建单独的作业,以便它们获得自己的junit/checkstyle/etc报告页面。然后有一个多任务项目来编排子项目的子模块构建。由于所有子项目都是简单的jar构建,因此我想将大部分逻辑放在一个公共(public)文件中,让我们在子项目的根目录下将其称为JenkinsfileForJars。所以 repo 结构是

  • 子项目
  • JenkinsfileForJars.groovy
  • 子模块A
  • Jenkinsfile
  • 子模块B
  • Jenkinsfile

  • 我的Jenkinsfile包含
    def submoduleName = "submoduleA"
    def pipeline
    node {
    
        pipeline = load("${env.WORKSPACE}/subproject/JenkinsfileForJars.groovy")
    
    }
    pipeline.build()
    pipeline.results()
    

    我的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;
    

    当我运行上面的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
    

    据我所知,我正在遵循loading manual scriptsexample given文档中显示的已加载脚本的内容。我不明白为什么在加载命令后我的脚本为空。

    如何获取我的Jenkinsfile来加载JenkinsfileForJars.groovy?

    最佳答案

    该问题与Blake Mitchell在上面的评论中提到的SCM结帐有关。
    由于要从子模块加载groovy函数,因此,如果您只想在主模块上保留裸仓库,则需要首先 check out 子模块,最好是在build agent/slave上。

    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()
    }
    

    请注意,在结帐示例中,Jenkins中的管理员也需要将对scm。*属性的访问列入白名单(进程内脚本批准)。

    关于jenkins - 在多个作业中重用 Jenkins 管道的各个阶段,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40045568/

    10-10 08:57