diff --git a/src/main/java/bio/terra/cli/app/CommandRunner.java b/src/main/java/bio/terra/cli/app/CommandRunner.java index 15ee00fe1..76864d25d 100644 --- a/src/main/java/bio/terra/cli/app/CommandRunner.java +++ b/src/main/java/bio/terra/cli/app/CommandRunner.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +32,13 @@ protected static String buildFullCommand(List command) { String fullCommand = ""; if (command != null && command.size() > 0) { final String argSeparator = " "; - fullCommand += argSeparator + String.join(argSeparator, command); + fullCommand += + argSeparator + + String.join( + argSeparator, + command.stream() + .map(i -> "\"" + i.replace("\"", "\\\"") + "\"") + .collect(Collectors.toList())); } return fullCommand; } diff --git a/src/test/java/unit/PassthroughApps.java b/src/test/java/unit/PassthroughApps.java index b08655141..a4cbaee55 100644 --- a/src/test/java/unit/PassthroughApps.java +++ b/src/test/java/unit/PassthroughApps.java @@ -86,6 +86,23 @@ void appList() throws IOException { assertTrue(appList.containsAll(Arrays.asList("gcloud", "gsutil", "bq", "nextflow", "git"))); } + @Test + @DisplayName("app execute respects arguments with spaces") + void appExecuteSpace() throws IOException { + workspaceCreator.login(/*writeGcloudAuthFiles=*/ true); + + // `terra workspace set --id=$id` + TestCommand.runAndParseCommandExpectSuccess( + UFWorkspace.class, "workspace", "set", "--id=" + getUserFacingId()); + + // `terra app execute sh -c "echo Hello World"` + TestCommand.Result cmd = + TestCommand.runCommand("app", "execute", "sh", "-c", "\"echo Hello World\""); + + // Check that the output was printed + assertThat("Output is correct", cmd.stdOut, CoreMatchers.containsString("Hello World")); + } + @Test @DisplayName("env vars include terra user and workspace cloud project") void workspaceEnvVars() throws IOException {