1. 简介

Jenkins 是一个广泛使用的自动化服务器,它帮助我们更高效地构建、测试和部署应用程序。其中,Jenkins Pipeline(流水线) 是其核心功能之一,它允许我们通过脚本定义构建流程。在某些场景下,我们可能需要在继续执行后续步骤之前确认某个文件是否存在。例如:

  • 仅当某个文件存在时才发布构建产物(Artifacts)
  • 如果文件缺失,跳过某些构建步骤

本文将介绍几种在 Jenkins Pipeline 中检查文件是否存在的方法,涵盖 Declarative PipelineScripted Pipeline 两种风格,并结合实际使用场景给出示例。最终我们将看到如何通过文件检查来控制流水线流程。

2. Jenkins Pipeline 基础知识

Jenkins Pipeline 主要分为两种写法:

Declarative Pipeline(声明式流水线)

  • 使用特定的语法结构,以 pipeline 块为起点
  • 更强调可读性和简洁性
  • 适合大多数简单清晰的流水线需求

Scripted Pipeline(脚本式流水线)

  • 基于 Groovy 的 DSL(领域特定语言)
  • 支持更复杂的逻辑结构,如循环、条件判断等
  • 适合需要精细控制或高级脚本的场景

无论使用哪种方式,Pipeline 的底层运行环境是 Groovy,因此我们可以借助 Groovy 方法、Jenkins 提供的 Pipeline 步骤或系统命令来实现文件检查。

3. 检查文件是否存在的方法

3.1 使用 Jenkins Pipeline 步骤

Jenkins 提供了一个内置步骤 fileExists,用于判断文件是否存在。它接收一个文件路径作为参数,并返回布尔值。

示例:Scripted Pipeline

node {
    stage('Check File') {
        if (fileExists('myfile.txt')) {
            echo "文件存在。"
        } else {
            echo "文件不存在。"
        }
    }
}

这段代码运行在 Jenkins Agent 上,检查当前工作目录下是否存在 myfile.txt 文件。如果存在则输出“文件存在”,否则输出“文件不存在”。

3.2 使用 Shell 命令检查文件

有时候我们可能更倾向于使用系统命令来检查文件是否存在。这在 Jenkins 中也可以通过 sh(Linux/macOS)或 bat(Windows)步骤实现。

示例:Linux/macOS

node {
    stage('Shell Check') {
        def result = sh script: '[ -f myfile.txt ] && echo "YES" || echo "NO"', returnStdout: true
        if (result.trim() == "YES") {
            echo "myfile.txt 存在。"
        } else {
            echo "myfile.txt 不存在。"
        }
    }
}

这里我们使用了 shell 命令 [ -f myfile.txt ] 来判断文件是否存在,并通过 returnStdout: true 获取命令输出结果。

示例:Windows

node {
    stage('Batch Check') {
        def result = bat script: 'if exist myfile.txt (echo YES) else (echo NO)', returnStdout: true
        if (result.trim().contains("YES")) {
            echo "myfile.txt 存在(Windows)。"
        } else {
            echo "myfile.txt 不存在(Windows)。"
        }
    }
}

使用 if exist 命令判断文件是否存在,逻辑类似。

4. 在 Declarative Pipeline 中检查文件

在声明式流水线中,我们依然可以使用 fileExistssh/bat 步骤。只需要在 steps 中嵌入 script 块即可。

示例:Declarative Pipeline

pipeline {
    agent any

    stages {
        stage('Check File Declarative') {
            steps {
                script {
                    if (fileExists('myfile.txt')) {
                        echo "找到 myfile.txt!"
                    } else {
                        echo "未找到 myfile.txt。"
                    }
                }
            }
        }
    }
}

通过 script 块,我们可以在 Declarative Pipeline 中嵌入 Groovy 逻辑,实现动态判断。

5. 处理检查结果

一旦我们确认文件是否存在,就可以根据结果做出不同处理。以下是几种常见做法:

5.1 跳过阶段

例如,我们只想在 deploy-package.zip 存在时才执行部署阶段:

stage('Check for Package') {
    steps {
        script {
            if (!fileExists('deploy-package.zip')) {
                error "部署包未找到,终止构建。"
            }
        }
    }
}

如果文件不存在,调用 error 会终止整个流水线。

5.2 标记构建状态为不稳定

如果我们允许流水线继续执行,但希望标记构建为不稳定状态:

script {
    if (!fileExists('optional-report.txt')) {
        currentBuild.result = 'UNSTABLE'
        echo "optional-report.txt 缺失,标记为不稳定。"
    }
}

这样流水线仍会完成,但 Jenkins 会记录为 UNSTABLE 状态。

6. 使用共享库(Shared Library)

在大型 Jenkins 项目中,我们通常会使用 Shared Library 来统一和复用代码逻辑。例如我们可以定义一个通用的 checkFileExists 方法:

定义共享库函数(vars/checkFileExists.groovy

def call(String filePath) {
    return fileExists(filePath)
}

在流水线中使用

@Library('my-shared-lib') _
pipeline {
    agent any
    stages {
        stage('Shared Library Check') {
            steps {
                script {
                    if (checkFileExists('somefile.txt')) {
                        echo "somefile.txt 存在。"
                    } else {
                        echo "somefile.txt 不存在。"
                    }
                }
            }
        }
    }
}

这样可以统一文件检查逻辑,提高可维护性。

7. 检查远程服务器上的文件

如果文件位于远程服务器上,我们需要采取额外的步骤:

方法一:先将文件复制到本地工作区

使用 scp 或其他方式将文件拉取到本地,再使用 fileExists 判断。

方法二:直接在远程执行检查

使用 sh 执行 SSH 命令检查远程文件是否存在:

node('myAgentWithSSH') {
    stage('Remote File Check') {
        sh '''
          ssh user@remoteserver "[ -f /path/to/file.txt ] && echo 'YES' || echo 'NO'"
        '''
    }
}

然后根据输出判断文件是否存在。

⚠️ 注意:远程执行需要提前配置好 SSH 密钥或凭据。

8. 实用技巧

✅ 在检查文件时,以下技巧可提高效率和准确性:

  • 使用 echo "当前工作目录: ${pwd()}" 查看当前路径,避免路径错误
  • 使用 dir('subfolder') 切换工作目录时,注意文件路径的相对变化
  • 并行构建时,不同 Agent 的工作目录相互独立,需确保文件在正确的节点上
  • 对于关键文件缺失,使用 error 终止流程;非关键文件可用 echo 输出警告

9. 综合示例:条件化归档与部署

下面是一个完整的流水线示例,结合了构建、归档和部署阶段的条件判断:

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh "touch build-output.jar"
                echo "构建完成。"
            }
        }

        stage('Archive Output') {
            steps {
                script {
                    if (fileExists('build-output.jar')) {
                        echo "归档 build-output.jar..."
                        archiveArtifacts artifacts: 'build-output.jar', fingerprint: true
                    } else {
                        echo "没有可归档的文件。"
                    }
                }
            }
        }

        stage('Deployment Decision') {
            steps {
                script {
                    if (fileExists('build-output.jar')) {
                        echo "开始部署..."
                        // 部署步骤
                    } else {
                        echo "跳过部署,build-output.jar 不存在。"
                    }
                }
            }
        }
    }
}

这个流水线演示了如何根据文件是否存在来决定是否归档和部署,是一种常见的实际应用场景。

10. 小结

在 Jenkins Pipeline 中检查文件是否存在是一个常见需求,尤其在构建、部署和归档阶段。我们可以通过以下方式实现:

  • 使用 Jenkins 内置的 fileExists 步骤
  • 调用 Shell 或 Batch 命令
  • 在 Declarative 和 Scripted Pipeline 中灵活使用 script
  • 结合 Shared Library 提高复用性
  • 远程文件可通过 SSH 或文件传输方式处理

通过这些方法,我们可以灵活控制流水线流程,提升构建和部署的健壮性与可控性。完整示例可在 GitHub 仓库 中查看。


原始标题:Check if a File Exists in a Jenkins Pipeline