@@ -77,14 +77,23 @@ data class Pipeline(
7777        } else  if  (useMultibranchWorkspace) {
7878            writer.writeln(" // Calculate custom workspace for multibranch pipelines" 
7979            writer.writeln(" // This prevents workspace path truncation and branch conflicts" 
80-             writer.writeln(" // by using a relative path that includes the sanitized job name " 
80+             writer.writeln(" // by using a relative path that includes the sanitized job path " 
8181            writer.writeln(" def customWorkspacePath = null" 
8282            writer.writeln(" if (env.BRANCH_NAME) {" 
8383            val  innerWriter =  writer.inner()
84-             innerWriter.writeln(" // Decode URL-encoded characters (e.g., %2F -> /) from job name and sanitize for safe filesystem paths" 
85-             innerWriter.writeln(" def decodedJobName = java.net.URLDecoder.decode(env.JOB_NAME, 'UTF-8')" 
86-             innerWriter.writeln(" def safeJobName = decodedJobName.replaceAll(/[^A-Za-z0-9._-]/, '_')" 
87-             innerWriter.writeln(" customWorkspacePath = \" ./workspace//\$ {safeJobName}\" " 
84+             innerWriter.writeln(" // Preserve folder hierarchy from JOB_NAME and sanitize only the final segment" 
85+             innerWriter.writeln(" def rawParts = env.JOB_NAME.tokenize('/')" 
86+             innerWriter.writeln(" def folderParts = rawParts.size() > 1 ? rawParts[0..-2] : []" 
87+             innerWriter.writeln(" def rawLeaf = rawParts ? rawParts[-1] : env.JOB_NAME" 
88+             innerWriter.writeln(" " 
89+             innerWriter.writeln(" // Decode last segment (handles %2F etc); then replace '/' and non-safe chars with '_'" 
90+             innerWriter.writeln(" def decodedLeaf = java.net.URLDecoder.decode(rawLeaf, 'UTF-8')" 
91+             innerWriter.writeln(" def safeLeaf = decodedLeaf.replaceAll('/', '_').replaceAll(/[^A-Za-z0-9._-]/, '_')" 
92+             innerWriter.writeln(" " 
93+             innerWriter.writeln(" // Sanitize folder parts but keep '/' between them" 
94+             innerWriter.writeln(" def safeFolderPath = folderParts.collect { it.replaceAll(/[^A-Za-z0-9._-]/, '_') }.join('/')" 
95+             innerWriter.writeln(" " 
96+             innerWriter.writeln(" customWorkspacePath = safeFolderPath ? \" ./workspace//\$ {safeFolderPath}/\$ {safeLeaf}\"  : \" ./workspace//\$ {safeLeaf}\" " 
8897            writer.writeln(" }" 
8998            writer.writeln(" " 
9099        }
0 commit comments