Skip to content

Commit c38656f

Browse files
committed
Use sh
1 parent 5699272 commit c38656f

File tree

5 files changed

+89
-34
lines changed

5 files changed

+89
-34
lines changed

impl/core/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,10 @@
2424
<groupId>de.huxhorn.sulky</groupId>
2525
<artifactId>de.huxhorn.sulky.ulid</artifactId>
2626
</dependency>
27+
<dependency>
28+
<groupId>org.apache.commons</groupId>
29+
<artifactId>commons-exec</artifactId>
30+
<version>1.4.0</version>
31+
</dependency>
2732
</dependencies>
2833
</project>

impl/core/src/main/java/io/serverlessworkflow/impl/executors/DefaultTaskExecutorFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public TaskExecutorBuilder<? extends TaskBase> getTaskExecutor(
7777
} else if (task.getEmitTask() != null) {
7878
return new EmitExecutorBuilder(position, task.getEmitTask(), definition);
7979
} else if (task.getRunTask() != null) {
80-
return new RunExecutor.RunTaskExecutorBuilder(position, task.getRunTask(), definition);
80+
return new RunTaskExecutor.RunTaskExecutorBuilder(position, task.getRunTask(), definition);
8181
}
8282
throw new UnsupportedOperationException(task.get().getClass().getName() + " not supported yet");
8383
}

impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunExecutor.java renamed to impl/core/src/main/java/io/serverlessworkflow/impl/executors/RunTaskExecutor.java

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,13 @@
2828
import io.serverlessworkflow.impl.expressions.ExpressionUtils;
2929
import java.io.IOException;
3030
import java.io.OutputStream;
31+
import java.util.Map;
3132
import java.util.Objects;
3233
import java.util.concurrent.CompletableFuture;
3334

34-
public abstract class RunExecutor<T extends TaskBase> extends RegularTaskExecutor<T> {
35+
public abstract class RunTaskExecutor<T extends TaskBase> extends RegularTaskExecutor<T> {
3536

36-
protected RunExecutor(RegularTaskExecutorBuilder<T> builder) {
37+
protected RunTaskExecutor(RegularTaskExecutorBuilder<T> builder) {
3738
super(builder);
3839
}
3940

@@ -48,18 +49,18 @@ protected RunTaskExecutorBuilder(
4849
@Override
4950
protected RegularTaskExecutor<RunTask> buildInstance() {
5051
if (task.getRun().getRunShell() != null) {
51-
return new RunShellExecutor(this);
52+
return new RunShellTaskExecutor(this);
5253
} else {
5354
throw new RuntimeException("Unsupported run task type");
5455
}
5556
}
5657
}
5758

58-
public static class RunShellExecutor extends RunExecutor<RunTask> {
59+
public static class RunShellTaskExecutor extends RunTaskExecutor<RunTask> {
5960

6061
private final WorkflowApplication application;
6162

62-
protected RunShellExecutor(RegularTaskExecutorBuilder<RunTask> builder) {
63+
protected RunShellTaskExecutor(RegularTaskExecutorBuilder<RunTask> builder) {
6364
super(builder);
6465
this.application = builder.application;
6566
}
@@ -68,42 +69,44 @@ protected RunShellExecutor(RegularTaskExecutorBuilder<RunTask> builder) {
6869
protected CompletableFuture<WorkflowModel> internalExecute(
6970
WorkflowContext workflow, TaskContext taskContext) {
7071

71-
if (taskContext.task() != null && taskContext.task() instanceof RunTask runTask) {
72+
if (taskContext.task() != null
73+
&& taskContext.task() instanceof RunTask runTask
74+
&& runTask.getRun().getRunShell() != null) {
7275
RunShell runShell = runTask.getRun().getRunShell();
76+
String shellCommand = runShell.getShell().getCommand();
77+
78+
Objects.requireNonNull(
79+
shellCommand, "Shell command must be provided in RunShell taskContext");
7380

7481
try {
7582
String command =
76-
ExpressionUtils.isExpr(runShell.getShell().getCommand())
83+
ExpressionUtils.isExpr(shellCommand)
7784
? WorkflowUtils.buildStringResolver(
78-
application,
79-
runShell.getShell().getCommand(),
80-
taskContext.input().asJavaObject())
85+
application, shellCommand, taskContext.input().asJavaObject())
8186
.apply(workflow, taskContext, taskContext.input())
82-
: runShell.getShell().getCommand();
83-
84-
Objects.requireNonNull(command, "Shell command must be provided in RunShell taskContext");
85-
86-
ProcessBuilder builder = new ProcessBuilder(command.split(" "));
87-
88-
Process process = builder.start();
89-
90-
// get output of process
91-
StringBuilder output = new StringBuilder();
92-
StringBuilder error = new StringBuilder();
93-
process.getInputStream().transferTo(getOutputStream(output));
94-
process.getErrorStream().transferTo(getOutputStream(error));
95-
96-
boolean isAwait = runTask.getRun().get().isAwait();
97-
if (!isAwait) {
98-
throw new UnsupportedOperationException("Non-await RunShell is not supported yet");
87+
: shellCommand;
88+
89+
ProcessBuilder processBuilder = new ProcessBuilder("sh", "-c", command);
90+
91+
if (runShell.getShell().getEnvironment() != null
92+
&& !runShell.getShell().getEnvironment().getAdditionalProperties().isEmpty()) {
93+
for (Map.Entry<String, Object> entry :
94+
runShell.getShell().getEnvironment().getAdditionalProperties().entrySet()) {
95+
String value =
96+
ExpressionUtils.isExpr(entry.getValue())
97+
? WorkflowUtils.buildStringResolver(
98+
application,
99+
entry.getValue().toString(),
100+
taskContext.input().asJavaObject())
101+
.apply(workflow, taskContext, taskContext.input())
102+
: entry.getValue().toString();
103+
processBuilder.environment().put(entry.getKey(), value);
104+
}
99105
}
100106

101-
int exitCode = process.waitFor();
102-
103-
ProcessResult result =
104-
new ProcessResult(exitCode, output.toString().trim(), error.toString().trim());
107+
ProcessResult result = startProcessUsing(processBuilder);
105108

106-
return CompletableFuture.completedFuture(application.modelFactory().fromAny(result));
109+
return CompletableFuture.supplyAsync(() -> application.modelFactory().fromAny(result));
107110

108111
} catch (IOException | InterruptedException e) {
109112
throw new RuntimeException(e);
@@ -113,6 +116,21 @@ protected CompletableFuture<WorkflowModel> internalExecute(
113116
throw new RuntimeException("Task must be of type RunTask");
114117
}
115118

119+
private ProcessResult startProcessUsing(ProcessBuilder processBuilder)
120+
throws IOException, InterruptedException {
121+
Process process = processBuilder.start();
122+
123+
StringBuilder output = new StringBuilder();
124+
StringBuilder error = new StringBuilder();
125+
126+
process.getInputStream().transferTo(getOutputStream(output));
127+
process.getErrorStream().transferTo(getOutputStream(error));
128+
129+
int exitCode = process.waitFor();
130+
131+
return new ProcessResult(exitCode, output.toString().trim(), error.toString().trim());
132+
}
133+
116134
private static OutputStream getOutputStream(StringBuilder output) {
117135
return new OutputStream() {
118136
@Override

impl/test/src/test/java/io/serverlessworkflow/impl/test/shell/RunExecutorTest.java renamed to impl/test/src/test/java/io/serverlessworkflow/impl/test/shell/RunTaskExecutorTest.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.assertj.core.api.SoftAssertions;
2626
import org.junit.jupiter.api.Test;
2727

28-
public class RunExecutorTest {
28+
public class RunTaskExecutorTest {
2929

3030
@Test
3131
void testEcho() throws IOException {
@@ -63,6 +63,24 @@ void testEchoWithJqExpression() throws IOException {
6363
}
6464
}
6565

66+
@Test
67+
void testEchoWithEnvironment() throws IOException {
68+
Workflow workflow =
69+
WorkflowReader.readWorkflowFromClasspath(
70+
"workflows-samples/shell-process/echo-with-env.yaml");
71+
try (WorkflowApplication appl = WorkflowApplication.builder().build()) {
72+
WorkflowModel model =
73+
appl.workflowDefinition(workflow).instance(Map.of("lastName", "Doe")).start().join();
74+
SoftAssertions.assertSoftly(
75+
softly -> {
76+
ProcessResult result = model.as(ProcessResult.class).orElseThrow();
77+
softly.assertThat(result.code()).isEqualTo(0);
78+
softly.assertThat(result.stderr()).isEmpty();
79+
softly.assertThat(result.stdout()).contains("Hello John Doe from env!");
80+
});
81+
}
82+
}
83+
6684
record Input(User user) {}
6785

6886
record User(String name) {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
document:
2+
dsl: '1.0.1'
3+
namespace: test
4+
name: run-shell-example
5+
version: '0.1.0'
6+
do:
7+
- runShell:
8+
run:
9+
shell:
10+
command: echo "Hello $FIRST_NAME $LAST_NAME from env!"
11+
environment:
12+
FIRST_NAME: John
13+
LAST_NAME: ${.lastName}
14+

0 commit comments

Comments
 (0)