Jenkinsfile使用Groovy遍历文件系统时循环仅执行一次如何解决
问题原因
- 核心问题是你在Pipeline中直接使用了Groovy原生的
new File()和traverse方法:这类Java/Groovy原生的文件系统API,只会在Jenkins 主节点(master)的JVM进程中执行,而你克隆Git仓库、执行sh ls命令都是在agent节点的工作目录下操作的,主节点上不存在对应路径的文件,读取逻辑异常就会出现只遍历到第一个文件就终止的情况。 - 次要问题:Groovy 2.4.x版本的
traverse方法存在已知的闭包返回值判定bug,如果闭包内最后一行表达式的返回值为false,遍历会提前终止,你的代码逻辑也可能触发该问题。
修复方案
方案1:使用Jenkins官方推荐的findFiles步骤(首选)
该步骤属于Pipeline Utility Steps插件,绝大多数Jenkins环境默认预装,是专门用于在agent节点遍历工作区文件的官方API,不存在跨节点读取的问题,替换后的代码如下:
dir("${reposDir}/${projectTitle}/${projectName}") { sh "pwd" sh "ls -alF" echo "[INFO] Iterate project" // 递归遍历当前目录下所有类型的文件 def allFiles = findFiles(glob: '**/*') allFiles.each { f -> println f.name println f.absolutePath if(f.name.endsWith('.sh')) { println "..." // 你的业务逻辑 } } }
方案2:通过sh命令输出遍历结果(无需额外插件)
如果你的Jenkins环境没有安装Pipeline Utility Steps插件,可以通过shell命令把遍历结果导出到Groovy变量中再处理:
dir("${reposDir}/${projectTitle}/${projectName}") { sh "pwd" sh "ls -alF" echo "[INFO] Iterate project" // 递归获取当前目录下所有文件的绝对路径,每行一个结果 def allFilePaths = sh( script: "find \$(pwd) -type f", returnStdout: true ).trim().split('\n') allFilePaths.each { filePath -> def fileName = filePath.split('/')[-1] println fileName println filePath if(fileName.endsWith('.sh')) { println "..." // 你的业务逻辑 } } }
额外优化提示
你的并行stage代码存在逻辑错误:parallel branchedStages不应放在projects.each循环内部,否则每次循环只会执行单个项目的stage,无法实现多项目并行构建,需要把该语句移到循环外部。
内容的提问来源于stack exchange,提问作者Sebastian Sommerfeld
相关产品推荐
相关产品推荐

