You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用多Git仓库时Jenkins出现NoSuchFileException问题求助

问题描述

我在使用Jenkins从仓库加载文件时,持续遇到java.nio.file.NoSuchFileException错误。当前使用两个Git仓库:

  • repo1.git:包含test.jenkinsfile、initialemail.groovy、statusemail.groovy文件
  • repo2.git:包含构建/部署阶段的所有文件

Jenkins流水线配置为:从SCM加载流水线脚本,SCM选择Git,仓库地址git@gitlab.com:test/repo1.git,分支testbranch,脚本路径jenkins/test.jenkinsfile。

test.jenkinsfile内容如下:

//create an empty map to capture the stage status
def stageStatusMap = [:]

pipeline {
    agent any

    environment {
        AWS_CREDENTIALS = credentials('Test')
    }

    stages {
        stage('Send Initial Email') {
            steps {
                script {
                    def initialemailsender = load 'jenkins/initialemail.groovy'
                    initialemailsender.sendemail()
                }
            }
        }

        stage('Checkout') {
            steps {
                git branch: 'master',
                    credentialsId: 'test',
                    url: 'git@gitlab.com:test/repo2.git'
            }
        }

        stage('Build') {
            steps {
                //some build steps here from the Docker files in repo2.git
            }
            post {
                success {
                    script {
                        stageStatusMap['Build'] = 'Success'
                    }
                }
                failure {
                    script {
                        stageStatusMap['Build'] = 'Failed'
                    }
                }
            }
        }

    }

    post {
        always {
            script {
                    //Load the statusemail from repo1.git 
                    statusemail = load 'jenkins/statusemail.groovy'
                    statusemail.sendemail(stageStatusMap)
                    echo "test"
            }
            cleanWs()
            echo 'Cleaned up the workspace and finished executing pipeline!'
        }
    }
}

执行流水线时触发错误:

java.nio.file.NoSuchFileException: /data/jenkins/workspace/Test/jenkins/statusemail.groovy

原因:检出repo2后,工作区被替换为repo2的内容,找不到来自repo1的statusemail.groovy文件。重新检出repo1可以解决,但希望找到无需重复拉取的方案。

已尝试的无效方法:

  1. 在流水线开头定义加载statusemail.groovy,因load必须在阶段内执行而失败;
  2. 在发送初始邮件阶段加载,该变量无法在post块中访问。

求无需重新检出repo1即可在post块中加载statusemail.groovy的解决方案。

解决方案

方法1:提前加载脚本并存储为全局变量

在检出repo2之前,提前加载repo1中的脚本并赋值给全局变量(不要加def限制作用域),后续即使工作区被替换,已加载的脚本对象仍可直接调用。

修改后的Jenkinsfile示例:

// 全局变量,存储加载的邮件脚本对象
def initialemailsender
def statusemailsender
def stageStatusMap = [:]

pipeline {
    agent any

    environment {
        AWS_CREDENTIALS = credentials('Test')
    }

    stages {
        stage('Load Repo1 Scripts') {
            steps {
                script {
                    // 此时工作区仍为repo1内容,加载两个邮件脚本
                    initialemailsender = load 'jenkins/initialemail.groovy'
                    statusemailsender = load 'jenkins/statusemail.groovy'
                }
            }
        }

        stage('Send Initial Email') {
            steps {
                script {
                    initialemailsender.sendemail()
                }
            }
        }

        stage('Checkout Repo2') {
            steps {
                git branch: 'master',
                    credentialsId: 'test',
                    url: 'git@gitlab.com:test/repo2.git'
            }
        }

        stage('Build') {
            steps {
                //some build steps here from the Docker files in repo2.git
            }
            post {
                success {
                    script {
                        stageStatusMap['Build'] = 'Success'
                    }
                }
                failure {
                    script {
                        stageStatusMap['Build'] = 'Failed'
                    }
                }
            }
        }

    }

    post {
        always {
            script {
                // 直接调用已加载的全局变量
                statusemailsender.sendemail(stageStatusMap)
                echo "test"
            }
            cleanWs()
            echo 'Cleaned up the workspace and finished executing pipeline!'
        }
    }
}

方法2:将repo2检出到独立子目录

使用dir步骤限定repo2的检出目录,避免覆盖repo1的文件,确保repo1的脚本始终存在于工作区根目录。

修改后的Checkout阶段及构建阶段:

stage('Checkout Repo2') {
    steps {
        dir('repo2-workspace') { // 指定repo2检出到子目录
            git branch: 'master',
                credentialsId: 'test',
                url: 'git@gitlab.com:test/repo2.git'
        }
    }
}

stage('Build') {
    steps {
        dir('repo2-workspace') { // 在repo2子目录下执行构建操作
            //some build steps here from the Docker files in repo2.git
        }
    }
    post {
        success {
            script {
                stageStatusMap['Build'] = 'Success'
            }
        }
        failure {
            script {
                stageStatusMap['Build'] = 'Failed'
            }
        }
    }
}

此时post块中可以直接加载jenkins/statusemail.groovy,因为根目录的repo1文件未被覆盖。

方法3:迁移脚本到Jenkins共享库

将邮件脚本封装为Jenkins共享库,彻底摆脱工作区文件依赖,这是长期维护流水线脚本的最优方案。

  1. 构建共享库目录结构:
email-shared-lib/
├── vars/
│   ├── sendInitialEmail.groovy
│   └── sendStatusEmail.groovy
└── src/
    // 可选:封装更复杂的逻辑到类中
  1. 在Jenkins全局配置中添加该共享库(路径或Git仓库地址)。
  2. 修改Jenkinsfile引入共享库并调用方法:
@Library('email-shared-lib') _ // 引入共享库
def stageStatusMap = [:]

pipeline {
    agent any

    environment {
        AWS_CREDENTIALS = credentials('Test')
    }

    stages {
        stage('Send Initial Email') {
            steps {
                script {
                    sendInitialEmail() // 调用共享库方法
                }
            }
        }

        stage('Checkout Repo2') {
            steps {
                git branch: 'master',
                    credentialsId: 'test',
                    url: 'git@gitlab.com:test/repo2.git'
            }
        }

        stage('Build') {
            steps {
                //some build steps here from the Docker files in repo2.git
            }
            post {
                success {
                    script {
                        stageStatusMap['Build'] = 'Success'
                    }
                }
                failure {
                    script {
                        stageStatusMap['Build'] = 'Failed'
                    }
                }
            }
        }

    }

    post {
        always {
            script {
                sendStatusEmail(stageStatusMap) // 调用共享库方法
                echo "test"
            }
            cleanWs()
            echo 'Cleaned up the workspace and finished executing pipeline!'
        }
    }
}

内容的提问来源于stack exchange,提问作者tt1997

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:27:06