From 61035314b93e578f061d8f53d7a0b5b8fe0fc276 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 17 Nov 2025 14:38:31 +0000 Subject: [PATCH] Fix WithContainerStep when hasWorkdir is false for Windows Containers The existing logic in the Decorator class sets hasWorkDir if the docker version is newer than 17.12. In the case where hasWorkDir is false, the fallback logic in the decorate() method updates the starter cmds() but always uses a UNIX-like "sh" command, which causes Jenkins to hang and timeout when using Windows Containers. Update the logic in the decorate() method to provide an implementation for Windows Containers that prepends the appropriate "cd" command followed by && to the generated command. --- .../docker/workflow/WithContainerStep.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java index b3428f7c5..2bf8f044f 100644 --- a/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java +++ b/src/main/java/org/jenkinsci/plugins/docker/workflow/WithContainerStep.java @@ -285,7 +285,11 @@ private static class Decorator extends LauncherDecorator implements Serializable masksPrefixList.add(false); } else { String safePath = path.replace("'", "'\"'\"'"); - starter.cmds().addAll(0, Arrays.asList("sh", "-c", "cd '" + safePath + "'; exec \"$@\"", "--")); + if (super.isUnix()) { + starter.cmds().addAll(0, Arrays.asList("sh", "-c", "cd '" + safePath + "'; exec \"$@\"", "--")); + } else { + starter.cmds().addAll(0, Arrays.asList("cmd", "/c", "cd \"" + safePath + "\"", "&&")); + } } } } @@ -344,9 +348,17 @@ private static class Decorator extends LauncherDecorator implements Serializable // JENKINS-75102 Docker exec on Windows processes character escaping differently. // Modify launch to work with special characters in a way that docker exec can handle. cmds.addAll(starter.cmds().subList(0, 2)); - cmds.add("call"); - cmds.addAll(starter.cmds().subList(2, starter.cmds().size()).stream() - .map(cmd -> cmd.replaceAll("\"\"(.*)\"\"", "\"$1\"")).collect(Collectors.toList())); + if (hasWorkdir) { + cmds.add("call"); + cmds.addAll(starter.cmds().subList(2, starter.cmds().size()).stream() + .map(cmd -> cmd.replaceAll("\"\"(.*)\"\"", "\"$1\"")).collect(Collectors.toList())); + } else { + cmds.addAll(starter.cmds().subList(2, 4)); + cmds.add("call"); + // Skip the duplicate "cmd /c" as we concatenate using && instead + cmds.addAll(starter.cmds().subList(6, starter.cmds().size()).stream() + .map(cmd -> cmd.replaceAll("\"\"(.*)\"\"", "\"$1\"")).collect(Collectors.toList())); + } } else { cmds.addAll(starter.cmds()); }