When working with Jenkins pipelines, downloading files might seem like a simple task, but it can be tricky when you need to handle both master and agent nodes correctly. In this post, we’ll explore how to create a solution for downloading files in Jenkins using Groovy.

The Challenge Link to heading

Downloading files in Jenkins pipelines presents several challenges:

  1. Node Awareness: Files need to be downloaded to the correct node (master or agent)
  2. Workspace Management: Files should be saved in the correct workspace
  3. File Path Management: Handling relative and absolute paths correctly

The Solution Link to heading

Here’s a comprehensive solution that handles all these challenges:

// vars/downloadFile.groovy
import hudson.FilePath
import jenkins.model.Jenkins

/**
* Download a file from a remote URL and save it to a local file.
* @param url (required) remote URL to download from
* @param localFilename (optional) relative local file name in current workspace to save the downloaded file. 
*        Defaults to the file name (last token) of the remote URL
* @return void
*/
void call(String url, String localFilename = null) {
    if (!localFilename) {
        localFilename = localFilename ?: url.tokenize('/')[-1]
    }

    String filePath = "${env.WORKSPACE}/${localFilename}"

    // Reference: https://stackoverflow.com/questions/14474973/how-to-download-a-file-groovy
    FilePath file
    String nodeName = env.NODE_NAME
    
    // Handle both master and agent nodes
    if (nodeName == 'master') {
        file = new FilePath(filePath)
    } else {
        file = new FilePath(Jenkins.getInstance().getComputer(nodeName).getChannel(), filePath)
    }

    BufferedOutputStream out = new BufferedOutputStream(file.write())
    out << new URL(url).openStream()
    out.close()

    echo("Downloaded file and saved to ${localFilename}")
}

Usage Example Link to heading

Here’s how to use this step in your Jenkins pipeline:

pipeline {
    agent any
    
    stages {
        stage('Download File') {
            steps {
                script {
                    // Download with default filename
                    downloadFile('https://example.com/file.zip')
                    
                    // Download with custom filename
                    downloadFile('https://example.com/file.zip', 'custom-name.zip')
                }
            }
        }
    }
}