Baeldung Pro – Ops – NPI EA (cat = Baeldung on Ops)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

Partner – Orkes – NPI EA (cat=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Introduction

Jenkins is a popular automation server that helps us build, test, and deploy applications more efficiently. One of its powerful features is the Jenkins Pipeline, which defines a script-based approach for creating pipelines. Sometimes, our pipeline needs to verify the presence of a file before proceeding to the next step. For instance, we might only publish artifacts if a particular file exists, or we might want to skip certain tasks if a file is missing.

In this tutorial, we’ll explore different ways to check if a file exists in a Pipeline. We’ll discuss examples of both Declarative and Scripted Pipelines and show how to integrate these checks into real-world projects. By the end, we’ll see how Jenkins pipeline scripts can handle file checks, allowing us to control the flow of our build and deployment stages.

2. Jenkins Pipeline Basics

Before we discuss file checks, let’s briefly recap the two main pipeline styles: Declarative and Scripted.

Let’s start with the Declarative Pipeline:

  • it uses a specific syntax with a pipeline block
  • it emphasizes readability and simpler configuration
  • it’s great for most straightforward pipelines

Then, the Scripted Pipeline:

  • it uses a Groovy-based approach
  • it offers more flexibility and programmatic structures like loops or conditionals
  • it is helpful when we need lower-level control or advanced scripting

Regardless of our approach, a Pipeline runs on top of Groovy. This means we can tap into Groovy methods, Jenkins pipeline steps, or system commands to check for files.

3. Approaches to Checking if a File Exists

Now, let’s see how we can implement various approaches to check if a file exists in Jenkins.

3.1. Using Jenkins Pipeline Steps

The simplest path in many pipelines is to rely on built-in steps, such as the fileExists step in Jenkins. This step takes a file path as input and returns a boolean. Let’s see how it looks in Scripted Pipeline:

node {
    stage('Check File') {
        if (fileExists('myfile.txt')) {
            echo "File found."
        } else {
            echo "File not found."
        }
    }
}

This snippet runs on a node (like an agent or worker) and checks if myfile.txt exists in the workspace. If it does, we print “File found”. If not, we print “File not found”. We can extend this to more complex logic, such as skipping stages or running additional tasks if the file is there.

3.2. Checking Files with Shell Commands

Sometimes, we may prefer or need to rely on system commands. This is also easy to do in Jenkins with the sh step (on Linux or macOS) or the bat step (on Windows).

For example, on Unix-based systems:

node {
    stage('Shell Check') {
        // Linux/macOS example
        def result = sh script: '[ -f myfile.txt ] && echo "YES" || echo "NO"', returnStdout: true
        if (result.trim() == "YES") {
            echo "myfile.txt exists."
        } else {
            echo "myfile.txt missing."
        }
    }
}

Here we:

  • run a shell script that checks if myfile.txt is a regular file using [ -f myfile.txt ]. If yes, we echo “YES”, otherwise “NO”
  • set returnStdout: true so that Jenkins captures the command’s output into the result variable
  • trim the output and compare it to either “YES” or “NO”

On Windows, we can do something similar using bat:

node {
    stage('Batch Check') {
        // Windows example
        def result = bat script: 'if exist myfile.txt (echo YES) else (echo NO)', returnStdout: true
        if (result.trim().contains("YES")) {
            echo "myfile.txt exists (Windows)."
        } else {
            echo "myfile.txt missing (Windows)."
        }
    }
}

We check if myfile.txt is present using the if exist command. Then, we capture the output and parse it.

4. Checking a File in Declarative Pipelines

Declarative Pipelines often revolve around a pipeline block with multiple stages. We can still leverage fileExists, sh, or bat.

Let’s see a short example:

pipeline {
    agent any

    stages {
        stage('Check File Declarative') {
            steps {
                script {
                    if (fileExists('myfile.txt')) {
                        echo "Found myfile.txt!"
                    } else {
                        echo "Did not find myfile.txt."
                    }
                }
            }
        }
    }
}

In this approach, the pipeline remains mostly declarative, but when we need to do something dynamic (like checking files), we add a script block. That’s often enough for many file checks.

5. Handling the Outcome

Once we know whether the file is present, we can make decisions in the pipeline. For example:

  • skip certain stages if a file is missing
  • stop the pipeline or mark it as unstable if a critical file is not found
  • copy or archive the file if it exists

5.1. Skipping a Stage

Let’s suppose we only want to run the Deploy stage if a file named deploy-package.zip is found. In Declarative syntax, we might do:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo "Building..."
                // Build steps here
            }
        }
        stage('Check for Package') {
            steps {
                script {
                    if (!fileExists('deploy-package.zip')) {
                        error "Package not found. Aborting."
                    }
                }
            }
        }
        stage('Deploy') {
            steps {
                echo "Deploying with deploy-package.zip."
                // deployment steps
            }
        }
    }
}

In Check for Package, we see if deploy-package.zip is there. If not, we call error to abort the deployment. The entire pipeline stops, preventing a deployment with missing files.

5.2. Setting Build Status

Another scenario is to mark the build as unstable if a file is missing but still allow the pipeline to continue:

script {
    if (!fileExists('optional-report.txt')) {
        currentBuild.result = 'UNSTABLE'
        echo "optional-report.txt is missing, marking build unstable."
    }
}

Now, the pipeline finishes, but Jenkins logs the result as UNSTABLE, signaling that something is not entirely correct.

6. Working With Shared Libraries

We often rely on Shared Libraries in larger Jenkins setups to keep pipeline code organized. Suppose we want a standard function, checkFileExists, that can be reused across pipelines:

// vars/checkFileExists.groovy in our shared library
def call(String filePath) {
    if (fileExists(filePath)) {
        return true
    } else {
        return false
    }
}

Now, in our pipeline:

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

This approach streamlines repeated tasks, letting us maintain the check logic in a single place. As needed, we can add logging, error handling, or custom logic to that function.

7. Handling Remote Files

In some situations, the file we want to check might reside on a different agent or remote server. Jenkins typically runs each stage on the agent defined in the pipeline, so if the file is not in the workspace for that agent, fileExists won’t find it. We have two main strategies:

  • copy the file into the workspace first: we can do an scp or a build step that fetches the file, then use fileExists
  • check directly on the remote system: use an ssh step or sh command that logs into the remote machine and checks for the file

For example, we can do a basic SSH approach:

node('myAgentWithSSH') {
    stage('Remote File Check') {
        // We assume we have set up credentials or SSH keys for remote login
        sh '''
          ssh user@remoteserver "[ -f /path/to/file.txt ] && echo 'YES' || echo 'NO'"
        '''
    }
}

Then, parse the output, similar to our earlier shell-based check.

8. Practical Tips

Here are a few tips to make file checks more effective in Jenkins:

  • We can confirm which directory we are in when checking for files. Jenkins might place the workspace differently or might have multiple nodes
  • A quick echo “Current workspace: ${pwd()}” can help clarify the path
  • We can try out dir(‘subfolder’) blocks in pipelines to change the working directory. Then, ensure we adjust our file checks accordingly
  • If we run tests or builds in parallel on different agents, we should keep in mind each agent has its own workspace unless we explicitly share them
  • If a missing file is critical, we can call error to stop the pipeline. If it is optional, we might continue but log a warning

9. Example: Conditional Archive and Deployment

Let’s combine multiple steps in a single pipeline snippet to see how everything fits together:

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh "touch build-output.jar"  // a mock build
                echo "Build complete."
            }
        }

        stage('Archive Output') {
            steps {
                script {
                    if (fileExists('build-output.jar')) {
                        echo "Archiving build-output.jar..."
                        archiveArtifacts artifacts: 'build-output.jar', fingerprint: true
                    } else {
                        echo "No artifact to archive."
                    }
                }
            }
        }

        stage('Deployment Decision') {
            steps {
                script {
                    if (fileExists('build-output.jar')) {
                        echo "Proceeding with deployment..."
                        // deployment steps here
                    } else {
                        echo "Skipping deployment because build-output.jar is missing."
                    }
                }
            }
        }
    }
}

This pipeline demonstrates how a typical Jenkins flow might rely on the existence of certain files to decide which steps to run:

  • Build: we create a file named build-output.jar just as an example
  • Archive Output: we check if it exists, and if so, we archive it
  • Deployment Decision: we only deploy if the artifact is present

10. Conclusion

In this article, we discussed why checking if a file exists is a common requirement in Jenkins Pipelines, whether to confirm the presence of build artifacts, configuration files, or output logs.

We explored implementing it in Declarative and Scripted Pipelines using Groovy-based scripts and the sample scripts are available over on GitHub.