Skip to content

Commit 6fab0f3

Browse files
committed
add support for .robot files
1 parent fdb8783 commit 6fab0f3

4 files changed

Lines changed: 88 additions & 8 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import json
2+
import os
3+
4+
from robot.api.deco import library, keyword
5+
6+
7+
@library
8+
class API:
9+
10+
result = {}
11+
12+
@keyword
13+
def flw_input(self, name: str):
14+
variables = os.environ["FLOWABLE_INPUT_VARIABLES"]
15+
obj = json.loads(variables)
16+
return obj[name]
17+
18+
@keyword
19+
def flw_output(self, name: str, value: any):
20+
output_file_name = os.environ.get("FLOWABLE_OUTPUT_FILE")
21+
self.result[name] = value
22+
print('assign ' + name + '=' + value)
23+
if output_file_name is not None:
24+
with open(output_file_name, "w") as f:
25+
f.write(json.dumps(self.result))
26+
f.close()

robocorp/flowable/robocorp_client/__main__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
from flowable.external_worker_client import ExternalWorkerClient
66
from flowable.external_worker_client.cloud_token import FlowableCloudToken
7-
from flowable.robocorp_client.robocorp_handler import RobocorpActionHandler, RobocorpTaskHandler
7+
from flowable.robocorp_client.robocorp_handler import RobocorpActionHandler, RobocorpTaskHandler, RobocorpRobotHandler
88

99
if __name__ == "__main__":
1010
parser = argparse.ArgumentParser(description="Flowable Robocorp Client")
1111

1212
parser.add_argument('topic', help='Topic of the Robocorp Action to listen to')
13-
parser.add_argument('mode', type=str, choices=['action', 'task'], help='Type of robocorp action/task')
13+
parser.add_argument('mode', type=str, choices=['action', 'task', 'robot'], help='Type of robocorp action/task/robot')
1414
parser.add_argument('path', type=str, help='The directory or file with the actions/tasks to run.')
1515
parser.add_argument('--flowable-host', type=str, default='https://trial.flowable.com', help='URL of Flowable Work')
1616
parser.add_argument('--flowable-token', type=str, help='Bearer Token, can be used for example with the Flowable Trial')
@@ -32,6 +32,8 @@
3232

3333
if args.mode == 'action':
3434
robocorp_job_handler = RobocorpActionHandler(robocorp_action_file)
35-
else:
35+
elif args.mode == 'task':
3636
robocorp_job_handler = RobocorpTaskHandler(robocorp_action_file)
37+
else:
38+
robocorp_job_handler = RobocorpRobotHandler(robocorp_action_file)
3739
subscription = client.subscribe(topic, robocorp_job_handler.handle_task)
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
import os
12
import subprocess
23
import sys
34

45

5-
def call_robocorp(args, mod_name='robocorp.actions'):
6+
def call_robocorp(args, mod_name, env=None):
7+
if env is None:
8+
env = os.environ.copy()
69
call_args = [sys.executable, "-m", mod_name]
710
call_args.extend(args)
811
try:
9-
return subprocess.run(call_args, capture_output=True, text=True)
12+
return subprocess.run(call_args, capture_output=True, text=True, env=env)
1013
except subprocess.CalledProcessError as exc:
1114
print("ERROR: failed to call robocorp", exc.returncode, exc.output)
1215

robocorp/flowable/robocorp_client/robocorp_handler.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import ast
22
import json
3+
import os
34
import shlex
5+
import tempfile
46

57
from flowable.external_worker_client import ExternalWorkerAcquireJobResponse, WorkerResultBuilder
68
from flowable.robocorp_client.call_robocorp import call_robocorp
@@ -18,6 +20,18 @@ def extract_action_and_parameters(job):
1820
return action, params
1921

2022

23+
def extract_action_and_parameters_map(job):
24+
action = None
25+
params = {}
26+
for variable in job.variables:
27+
if variable.name == '__robocorpTaskName':
28+
action = variable.value
29+
else:
30+
if variable.value is not None:
31+
params[variable.name] = variable.value
32+
return action, params
33+
34+
2135
def extract_result(results):
2236
result_item = None
2337
lines = results.strip().splitlines()
@@ -35,8 +49,7 @@ def create_output_dir(job):
3549
return 'output/' + job.id + '-' + (job.scope_id or job.process_instance_id) + '-' + job.element_id
3650

3751

38-
def add_variables_to_result(work_result, result):
39-
json_result = ast.literal_eval(result)
52+
def add_variables_to_result(work_result, json_result):
4053

4154
if isinstance(json_result, dict):
4255
for key in json_result:
@@ -78,7 +91,8 @@ def handle_task(self, job: ExternalWorkerAcquireJobResponse, worker_result_build
7891
result = extract_result(results.stdout)
7992
print('---> Job execution done for "' + job.id + '" with result ' + result + '". Output saved to ' + output_dir, robocorp_args)
8093
work_result = worker_result_builder.success()
81-
return add_variables_to_result(work_result, result)
94+
json_result = ast.literal_eval(result)
95+
return add_variables_to_result(work_result, json_result)
8296

8397

8498
class RobocorpTaskHandler:
@@ -100,3 +114,38 @@ def handle_task(self, job: ExternalWorkerAcquireJobResponse, worker_result_build
100114
return worker_result_builder.failure().error_message('failed with status code ' + str(results.returncode)).error_details(results.stderr + results.stdout)
101115
print('---> Job execution done for "' + job.id + '". Output saved to ' + output_dir, robocorp_args)
102116
return worker_result_builder.success()
117+
118+
119+
class RobocorpRobotHandler:
120+
def __init__(self, robocorp_action_file: str):
121+
self.robocorp_action_file = robocorp_action_file
122+
123+
def handle_task(self, job: ExternalWorkerAcquireJobResponse, worker_result_builder: WorkerResultBuilder):
124+
action, params = extract_action_and_parameters_map(job)
125+
if action is None:
126+
return worker_result_builder.failure().error_message('failed to find robocorp action name')
127+
128+
output_dir = create_output_dir(job)
129+
robocorp_args = ['--rpa', '--name', action.__str__(), '--report', 'NONE', '--outputdir', output_dir, self.robocorp_action_file]
130+
print('---> Execute job "' + job.id + '"', robocorp_args)
131+
tmp = tempfile.NamedTemporaryFile(delete=False)
132+
tmp.close()
133+
new_env = os.environ.copy()
134+
new_env["FLOWABLE_INPUT_VARIABLES"] = json.dumps(params)
135+
new_env["FLOWABLE_OUTPUT_FILE"] = tmp.name
136+
results = call_robocorp(robocorp_args, mod_name='robot', env=new_env)
137+
138+
if results.returncode != 0:
139+
print('---> Job execution failed for "' + job.id + '". Output saved to ' + output_dir)
140+
os.unlink(tmp.name)
141+
return worker_result_builder.failure().error_message('failed with status code ' + str(results.returncode)).error_details(results.stderr + results.stdout)
142+
print('---> Job execution done for "' + job.id + '". Output saved to ' + output_dir, robocorp_args)
143+
144+
with open(tmp.name, 'r') as content_file:
145+
content = json.loads(content_file.read())
146+
os.unlink(tmp.name)
147+
148+
if content is None:
149+
return worker_result_builder.success()
150+
else:
151+
return add_variables_to_result(worker_result_builder.success(), content)

0 commit comments

Comments
 (0)