Skip to content

Commit 047d02c

Browse files
committed
add JUNIT xml export to CI result command
1 parent dd8f7e5 commit 047d02c

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

onekey_client/cli/ci.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import sys
22
import time
3+
from pathlib import Path
4+
from typing import Optional
35
from uuid import UUID
46

57
import click
68
import httpx
79

10+
from junit_xml import TestSuite, TestCase
11+
812
from onekey_client import Client
913
from onekey_client.queries import load_query
1014

@@ -165,6 +169,94 @@ def get_firmware_compare_ui_url(self, recent_id, firmware_id):
165169
return f"https://{self.client.api_url.host}/firmwares/compare-firmwares?baseFirmwareId={recent_id}&otherFirmwareId={firmware_id}"
166170

167171

172+
class JUnitExporter:
173+
def __init__(self, client: Client, firmware_id: UUID):
174+
self.client = client
175+
self.firmware_id = str(firmware_id)
176+
177+
def create_new_issue_testcase(self, issue):
178+
url = self.get_firmware_issues_ui_url()
179+
test_case = TestCase(
180+
name=issue["id"],
181+
classname=f"Issue: {issue['type']}",
182+
file=issue["file"]["path"],
183+
status="NEW",
184+
url=url,
185+
)
186+
187+
test_case.add_failure_info(
188+
message="New issue",
189+
output=f"""New issue detected
190+
URL: {url}
191+
Type: {issue["type"]}
192+
Severity: {issue["severity"]}
193+
File: {issue["file"]["path"]}
194+
""",
195+
)
196+
return test_case
197+
198+
def create_new_cve_testcase(self, cve):
199+
cve = dict(cve)
200+
url = self.get_firmware_cves_ui_url()
201+
test_case = TestCase(name=cve["id"], classname="CVE", status="NEW", url=url)
202+
test_case.add_failure_info(
203+
message="New CVE",
204+
output=f"""New CVE detected
205+
URL: {url}
206+
CVE ID: {cve['id']}
207+
Severity: {cve['severity']}
208+
Description: {cve['description']}
209+
""",
210+
)
211+
return test_case
212+
213+
def generate_junit_xml(
214+
self, new_issues, dropped_issues, new_cves, dropped_cves, output_path: Path
215+
):
216+
new_issues_test_cases = [
217+
self.create_new_issue_testcase(issue) for issue in new_issues
218+
]
219+
220+
dropped_issues_test_cases = [
221+
TestCase(
222+
name=issue["id"],
223+
classname=f"Issue: {issue['type']}",
224+
file=issue["file"]["path"],
225+
status="DROPPED",
226+
url=self.get_firmware_issues_ui_url(),
227+
)
228+
for issue in dropped_issues
229+
]
230+
231+
new_cves_test_cases = [self.create_new_cve_testcase(cve) for cve in new_cves]
232+
dropped_cves_test_cases = [
233+
TestCase(
234+
name=cve_id,
235+
classname="CVE",
236+
status="DROPPED",
237+
url=self.get_firmware_cves_ui_url(),
238+
)
239+
for cve_id in dropped_cves
240+
]
241+
242+
issues_test_suite = TestSuite(
243+
"ONEKEY identified issues",
244+
new_issues_test_cases + dropped_issues_test_cases,
245+
)
246+
cves_test_suite = TestSuite(
247+
"ONEKEY identified CVE entries",
248+
new_cves_test_cases + dropped_cves_test_cases,
249+
)
250+
with output_path.open("w") as f:
251+
TestSuite.to_file(f, [issues_test_suite, cves_test_suite])
252+
253+
def get_firmware_issues_ui_url(self):
254+
return f"https://{self.client.api_url.host}/firmwares/issues?firmwareId={self.firmware_id}"
255+
256+
def get_firmware_cves_ui_url(self):
257+
return f"https://{self.client.api_url.host}/firmwares/cves?firmwareId={self.firmware_id}"
258+
259+
168260
@click.command()
169261
@click.option("--firmware-id", required=True, type=UUID, help="Firmware ID")
170262
@click.option(
@@ -196,6 +288,11 @@ def get_firmware_compare_ui_url(self, recent_id, firmware_id):
196288
show_default=True,
197289
help="Wait time between retries due to communication problem",
198290
)
291+
@click.option(
292+
"--junit-path",
293+
type=click.Path(exists=False, path_type=Path),
294+
help="File to export JUNIT xml",
295+
)
199296
@click.pass_obj
200297
def ci_result(
201298
client: Client,
@@ -204,6 +301,7 @@ def ci_result(
204301
retry_count: int,
205302
retry_wait: int,
206303
check_interval: int,
304+
junit_path: Optional[Path],
207305
):
208306
"""Fetch analysis results for CI"""
209307

@@ -216,6 +314,12 @@ def ci_result(
216314
)
217315
new_issues, dropped_issues, new_cves, dropped_cves = handler.get_result()
218316

317+
if junit_path is not None:
318+
junit_exporter = JUnitExporter(client, firmware_id)
319+
junit_exporter.generate_junit_xml(
320+
new_issues, dropped_issues, new_cves, dropped_cves, junit_path
321+
)
322+
219323
exit_code = exit_code if new_issues or new_cves else 0
220324

221325
sys.exit(exit_code)

0 commit comments

Comments
 (0)