Rupaleee
Rupaleee

Reputation: 75

Unable to recognize WORKSPACE as directory using Jenkinsfile/pipline plugin

I am trying to search a file recursively inside a directory hence cannot use findFiles. I have seen the directories via manually login in to the slave but it cannot be recognized in the code below. When I use isDirectory() it says false hence later while using dir.listFiles() it return null.

Below is the code:

def recursiveFileSearch(File dir, filename, filesPath) {

  File[] files = dir.listFiles() // It returns null here as it cannot recognize it as directory
  echo "$files" 
  for (int i=0; i < files.size(); i++) {
    if (files[i].isDirectory()) {
      recursiveFileSearch(files[i], filename, filesPath)
    } else {
      if (files[i].getAbsolutePath().contains(filename)) {
        filesPath.add(files[i].getAbsolutePath())
        return filesPath
      }
    }
  }
  return filesPath
}

node('maven') {
      git 'https://github.com/rupalibehera/t3d.git'
      sh 'mvn clean install'
      File currentDir = new File(pwd())

      def isdir = currentDir.isDirectory()
      println "isdir:${isdir}" // The output here is False
      def isexist = currentDir.exists()
      println "isexist:${isexist}" // The output here is False
      def canread = currentDir.canRead()
      println "canread:${canread}" // The output here is False
      def filesPath = []
      def openshiftYaml = recursiveFileSearch(currentDir, "openshift.yml", filesPath)
} 

I am not sure what is going wrong here.

But below are some observations:

Any pointers/help is appreciated

Upvotes: 0

Views: 2240

Answers (3)

Peter Kahn
Peter Kahn

Reputation: 13036

you are running into the Using File in Pipeline Description problem. I know it all too well. File objects and NIO work fine for breaking up paths, but their isDirectory, exists and other methods run on master as a part of the Jenkinsfile and not on the node. So, all use on master looks great, because the files are in the workspace. All use on a node, fails.

In short, don't do that. Use fileExists(), pwd(), findFiles etc

If you created a shareLibrary and want to use unit tests on the code outside of Jenkins, then you can create a fascade which relies on the script object ('this' from a pipeline)

Class for shared lib

class PipelineUtils implements Serializable {
    static def pipelineScript = null;

    /**
     * Setup this fascade with access to pipeline script methods
     * @param jenkinsPipelineScript
     * @return
     */
    static initialize(def jenkinsPipelineScript) {
        pipelineScript = jenkinsPipelineScript
    }

    /**
     * Use pipelineScript object ('this' from pipeline) to access fileExists
     * We cannot use Java File objects for detection as the pipeline script runs on master and uses delegation/serialization to
     * get to the node.  So, File.exists() will be false if the file was generated on the node and that node isn't master.
     * https://support.cloudbees.com/hc/en-us/articles/230922128-Pipeline-Using-java-io-File-in-a-Pipeline-description
     * @param target
     * @return true if path exists
     */
    static boolean exists(Path target) {
        if (!pipelineScript) {
            throw new Exception("PipelineUtils.initialize with pipeline script not called - access to pipeline 'this' required for access to file detection routines")
        }

        if (! target.parent) {
            throw new Exception('Please use absolutePaths with ${env.WORKSPACE}/path-to-file')
        }
        return pipelineScript.fileExists(target.toAbsolutePath().toString())
    }

    /**
     * Convert workspace relative path to absolute path
     * @param path relative path
     * @return node specific absolute path
     */
    static def relativeWorkspaceToAbsolutePath(String path) {
        Path pwd = Paths.get(pipelineScript.pwd())
        return pwd.resolve(path).toAbsolutePath().toString()
    }

    static void echo(def message) {
        pipelineScript.echo(message)
    }
}

class for tests

class JenkinsStep { static boolean fileExists(def path) { return new File(path).exists() }

static def pwd() {
    return System.getProperty("user.dir")
}

static def echo(def message) {
    println "${message}"
}

}

usage in jenkins

PipelineUtils.initialize(this)
println PipelineUtils.exists(".")
// calls jenkins fileExists()

usage in unit tests

PipelineUtils.initialize(new JenkinsStep())
println PipelineUtils.exists(".")
// calls File.exists

Upvotes: 1

Jesse Glick
Jesse Glick

Reputation: 25481

Generally, run a sh step to do whatever work you need. You may not use java.io.File or the like from Pipeline script. It does not run on the agent, and is also insecure, which is why any such attempt will be rejected when the sandbox mode is left on (the default).

Upvotes: 1

Rupaleee
Rupaleee

Reputation: 75

I found the answer, for searching any file in your workspace from Jenkinsfile you can use findFiles step, I did try this but I was passing the incorrect glob for the same. Now I just do def files = findFiles(glob: '**/openshift.yml') \\ it returns the path of file

Upvotes: 0

Related Questions