Skip to content

Commit 8a3b77e

Browse files
committed
implement open report/log after run automatically or from terminal link
1 parent ac518f0 commit 8a3b77e

File tree

7 files changed

+380
-69
lines changed

7 files changed

+380
-69
lines changed

package.json

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@
174174
"enum": [
175175
"internalConsole",
176176
"integratedTerminal",
177-
"externalTerminal" ],
177+
"externalTerminal"
178+
],
178179
"default": "integratedTerminal",
179180
"enumDescriptions": [
180181
"No terminal (pipes the output to the client debug console).",
@@ -184,16 +185,33 @@
184185
"description": "Default setting for where to launch the debug target: internal console, integrated terminal, or external terminal.",
185186
"scope": "resource"
186187
},
188+
"robotcode.robocop.enabled": {
189+
"type": "boolean",
190+
"default": true,
191+
"description": "Enables 'robocop' code analysis, if installed.",
192+
"scope": "resource"
193+
},
194+
187195
"robotcode.syntax.sectionStyle": {
188196
"type": "string",
189197
"default": "*** {name}s ***",
190198
"description": "Defines the section style format.",
191199
"scope": "resource"
192200
},
193-
"robotcode.robocop.enabled": {
194-
"type": "boolean",
195-
"default": true,
196-
"description": "Enables 'robocop' code analysis, if installed.",
201+
"robotcode.run.openReportAfterRun": {
202+
"type": "string",
203+
"enum": [
204+
"disabled",
205+
"external",
206+
"internal"
207+
],
208+
"enumDescriptions": [
209+
"Do not open the result report",
210+
"Opens the report in an external browser.",
211+
"Opens the report in an internal view (experimental)."
212+
],
213+
"default": "none",
214+
"description": "Defines if the test report should be opened a run session automatically.",
197215
"scope": "resource"
198216
},
199217
"robotcode.robocop.include": {
@@ -258,13 +276,13 @@
258276
"command": "robotcode.debugTest",
259277
"category": "RobotCode",
260278
"title": "Debug Test",
261-
"icon": {
262-
"light": "resources/light/debug_test.svg",
279+
"icon": {
280+
"light": "resources/light/debug_test.svg",
263281
"dark": "resources/dark/debug_test.svg"
264282
}
265283
}
266284
],
267-
"menus": {
285+
"menus": {
268286
"editor/title/run": [
269287
{
270288
"command": "robotcode.runSuite",
@@ -276,7 +294,7 @@
276294
"command": "robotcode.debugSuite",
277295
"title": "Debug Testsuite",
278296
"group": "robot@2",
279-
"when": "resourceLangId == robotframework && resourceExtname == .robot && !isInDiffEditor"
297+
"when": "resourceLangId == robotframework && resourceExtname == .robot && !isInDiffEditor"
280298
}
281299
],
282300
"explorer/context": [
@@ -378,6 +396,21 @@
378396
"type": "number",
379397
"description": "Timeout to connect to the debuggee.",
380398
"default": 5
399+
},
400+
"outputMessages": {
401+
"type": "boolean",
402+
"description": "Output messages from robotframework in debug console.",
403+
"default": false
404+
},
405+
"outputLog": {
406+
"type": "boolean",
407+
"description": "Output log messages from robotframework in debug console.",
408+
"default": false
409+
},
410+
"groupOutput": {
411+
"type": "boolean",
412+
"description": "Group start and stop suite/test/keyword messages in debug console.",
413+
"default": false
381414
}
382415
}
383416
}
@@ -394,7 +427,7 @@
394427
"cwd": "^\"\\${workspaceFolder}\"",
395428
"target": "^\"\\${file}\"",
396429
"env": {},
397-
"args": []
430+
"args": []
398431
}
399432
}
400433
]

robotcode/debug_adapter/launcher/__main__.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ async def run_robot(
117117
debugpy: bool = False,
118118
wait_for_debugpy_client: bool = False,
119119
debugpy_port: int = 5678,
120+
output_messages: bool = False,
121+
output_log: bool = False,
122+
group_output: bool = False,
120123
) -> Any:
121124
import robot
122125

@@ -189,6 +192,10 @@ async def start_debugpy_async() -> None:
189192
*args,
190193
]
191194

195+
Debugger.instance().output_messages = output_messages
196+
Debugger.instance().output_log = output_log
197+
Debugger.instance().group_output = group_output
198+
192199
Debugger.instance().set_main_thread(threading.current_thread())
193200
Debugger.instance().start()
194201

@@ -197,6 +204,24 @@ async def start_debugpy_async() -> None:
197204
False,
198205
)
199206

207+
if server.protocol.connected:
208+
await asyncio.wrap_future(
209+
asyncio.run_coroutine_threadsafe(
210+
server.protocol.send_event_async(
211+
Event(
212+
event="robotExited",
213+
body={
214+
"reportFile": Debugger.instance().robot_report_file,
215+
"logFile": Debugger.instance().robot_log_file,
216+
"outputFile": Debugger.instance().robot_output_file,
217+
"exitCode": exit_code,
218+
},
219+
)
220+
),
221+
loop=loop,
222+
)
223+
)
224+
200225
if server.protocol.connected:
201226
await asyncio.wrap_future(asyncio.run_coroutine_threadsafe(server.protocol.exit(exit_code), loop=loop))
202227

@@ -293,6 +318,15 @@ def main() -> None:
293318
parser.add_argument(
294319
"-dw", "--debugpy-wait-for-client", action="store_true", help="waits for debugpy client to connect"
295320
)
321+
parser.add_argument(
322+
"-om", "--output-messages", action="store_true", help="Send output messages from robotframework to client."
323+
)
324+
parser.add_argument(
325+
"-ol", "--output-log", action="store_true", help="Send log messages from robotframework to client."
326+
)
327+
parser.add_argument(
328+
"-og", "--group-output", action="store_true", help="Fold messages/log from robotframework to client."
329+
)
296330

297331
sys_args = sys.argv[1:]
298332

@@ -352,7 +386,8 @@ def main() -> None:
352386
logging.getLogger("asyncio").propagate = False
353387

354388
if not args.log_debug_adapter_launcher:
355-
logging.getLogger("robotcode.debug_adapter.launcher").propagate = False
389+
logging.getLogger("robotcode.debug_adapter").propagate = False
390+
logging.getLogger("robotcode.debug_adapter").disabled = True
356391

357392
_logger.info(f"starting {__package__} version={__version__}")
358393
_logger.debug(f"args={args}")
@@ -368,6 +403,9 @@ def main() -> None:
368403
args.debugpy,
369404
args.debugpy_wait_for_client,
370405
args.debugpy_port,
406+
args.output_messages,
407+
args.output_log,
408+
args.group_output,
371409
)
372410
)
373411

robotcode/debug_adapter/launcher/debugger.py

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
OutputCategory,
1919
OutputEvent,
2020
OutputEventBody,
21+
OutputGroup,
2122
Scope,
2223
Source,
2324
SourceBreakpoint,
@@ -127,6 +128,36 @@ def __init__(self) -> None:
127128
self.state: State = State.Stopped
128129
self.requested_state: RequestedState = RequestedState.Nothing
129130
self.stop_stack_len = 0
131+
self._robot_report_file: Optional[str] = None
132+
self._robot_log_file: Optional[str] = None
133+
self._robot_output_file: Optional[str] = None
134+
self.output_messages: bool = False
135+
self.output_log: bool = False
136+
self.group_output: bool = False
137+
138+
@property
139+
def robot_report_file(self) -> Optional[str]:
140+
return self._robot_report_file
141+
142+
@robot_report_file.setter
143+
def robot_report_file(self, value: Optional[str]) -> None:
144+
self._robot_report_file = value
145+
146+
@property
147+
def robot_log_file(self) -> Optional[str]:
148+
return self._robot_log_file
149+
150+
@robot_log_file.setter
151+
def robot_log_file(self, value: Optional[str]) -> None:
152+
self._robot_log_file = value
153+
154+
@property
155+
def robot_output_file(self) -> Optional[str]:
156+
return self._robot_output_file
157+
158+
@robot_output_file.setter
159+
def robot_output_file(self, value: Optional[str]) -> None:
160+
self._robot_output_file = value
130161

131162
@_logger.call
132163
def start(self) -> None:
@@ -326,6 +357,42 @@ def wait_for_running(self) -> None:
326357
with self.condition:
327358
self.condition.wait_for(lambda: self.state in [State.Running, State.Stopped])
328359

360+
def start_output_group(self, name: str, attributes: Dict[str, Any], type: Optional[str] = None) -> None:
361+
if self.group_output:
362+
source = attributes.get("source", None)
363+
line_no = attributes.get("lineno", None)
364+
365+
self.send_event(
366+
self,
367+
OutputEvent(
368+
body=OutputEventBody(
369+
output=f"{(type +' ') if type else ''}{name}\n",
370+
category=OutputCategory.CONSOLE,
371+
group=OutputGroup.STARTCOLLAPSED,
372+
source=Source(name=name, path=source) if source else None,
373+
line=line_no,
374+
)
375+
),
376+
)
377+
378+
def end_output_group(self, name: str, attributes: Dict[str, Any]) -> None:
379+
if self.group_output:
380+
source = attributes.get("source", None)
381+
line_no = attributes.get("lineno", None)
382+
383+
self.send_event(
384+
self,
385+
OutputEvent(
386+
body=OutputEventBody(
387+
output="",
388+
category=OutputCategory.CONSOLE,
389+
group=OutputGroup.END,
390+
source=Source(name=name, path=source) if source else None,
391+
line=line_no,
392+
)
393+
),
394+
)
395+
329396
def start_suite(self, name: str, attributes: Dict[str, Any]) -> None:
330397
from robot.running.context import EXECUTION_CONTEXTS
331398

@@ -376,11 +443,11 @@ def start_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
376443

377444
source = attributes.get("source", None)
378445
line_no = attributes.get("lineno", 1)
379-
longname = attributes.get("kwname", "")
446+
kwname = attributes.get("kwname", "")
380447
type = attributes.get("type", "KEYWORD")
381448

382449
self.stack_frames.appendleft(
383-
StackFrameEntry(weakref.ref(EXECUTION_CONTEXTS.current), longname, type, source, line_no)
450+
StackFrameEntry(weakref.ref(EXECUTION_CONTEXTS.current), kwname, type, source, line_no)
384451
)
385452

386453
self.process_state(source, line_no, type)
@@ -422,22 +489,27 @@ def get_stack_trace(
422489
)
423490

424491
def log_message(self, message: Dict[str, Any]) -> None:
425-
self.send_event(
426-
self,
427-
OutputEvent(
428-
body=OutputEventBody(output="LOG> {timestamp} {level}: {message}\n".format(**message), category="log")
429-
),
430-
)
492+
if self.output_log:
493+
self.send_event(
494+
self,
495+
OutputEvent(
496+
body=OutputEventBody(
497+
output="LOG> {timestamp} {level}: {message}\n".format(**message), category="log"
498+
)
499+
),
500+
)
431501

432502
def message(self, message: Dict[str, Any]) -> None:
433-
self.send_event(
434-
self,
435-
OutputEvent(
436-
body=OutputEventBody(
437-
output="MSG> {timestamp} {level}: {message}\n".format(**message), category=OutputCategory.CONSOLE
438-
)
439-
),
440-
)
503+
if self.output_messages:
504+
self.send_event(
505+
self,
506+
OutputEvent(
507+
body=OutputEventBody(
508+
output="MSG> {timestamp} {level}: {message}\n".format(**message),
509+
category=OutputCategory.CONSOLE,
510+
)
511+
),
512+
)
441513

442514
def get_scopes(self, frame_id: int) -> List[Scope]:
443515
result: List[Scope] = []

robotcode/debug_adapter/launcher/listeners.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,45 @@ def __init__(self, no_debug: bool = False) -> None:
1111
self.debug = not no_debug
1212

1313
def start_suite(self, name: str, attributes: Dict[str, Any]) -> None:
14+
Debugger.instance().start_output_group(name, attributes, "SUITE")
15+
1416
if self.debug:
1517
Debugger.instance().start_suite(name, attributes)
1618

1719
def end_suite(self, name: str, attributes: Dict[str, Any]) -> None:
1820
if self.debug:
1921
Debugger.instance().end_suite(name, attributes)
2022

23+
Debugger.instance().end_output_group(name, attributes)
24+
2125
def start_test(self, name: str, attributes: Dict[str, Any]) -> None:
26+
Debugger.instance().start_output_group(name, attributes, "TEST")
27+
2228
if self.debug:
2329
Debugger.instance().start_test(name, attributes)
2430

2531
def end_test(self, name: str, attributes: Dict[str, Any]) -> None:
2632
if self.debug:
2733
Debugger.instance().end_test(name, attributes)
2834

35+
Debugger.instance().end_output_group(name, attributes)
36+
2937
def start_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
38+
Debugger.instance().start_output_group(
39+
f"{name}({', '.join(repr(v) for v in attributes.get('args', []))})",
40+
attributes,
41+
attributes.get("type", None),
42+
)
43+
3044
if self.debug:
3145
Debugger.instance().start_keyword(name, attributes)
3246

3347
def end_keyword(self, name: str, attributes: Dict[str, Any]) -> None:
3448
if self.debug:
3549
Debugger.instance().end_keyword(name, attributes)
3650

51+
Debugger.instance().end_output_group(name, attributes)
52+
3753
def log_message(self, message: Dict[str, Any]) -> None:
3854
Debugger.instance().log_message(message)
3955

@@ -50,13 +66,13 @@ def variables_import(self, name: str, attributes: Dict[str, Any]) -> None:
5066
pass
5167

5268
def output_file(self, path: str) -> None:
53-
pass
69+
Debugger.instance().robot_output_file = path
5470

5571
def log_file(self, path: str) -> None:
56-
pass
72+
Debugger.instance().robot_log_file = path
5773

5874
def report_file(self, path: str) -> None:
59-
pass
75+
Debugger.instance().robot_report_file = path
6076

6177
def xunit_file(self, path: str) -> None:
6278
pass

0 commit comments

Comments
 (0)