Skip to content

Commit 6b5dc4d

Browse files
author
Jeny Sadadia
committed
Implement results issue command
Fetch KCIDB issue matching provided ID. Also get associated builds and tests. Sample command: `kci-dev results issue --id <id> --origin <origin>` Signed-off-by: Jeny Sadadia <[email protected]>
1 parent 2c930e1 commit 6b5dc4d

File tree

3 files changed

+126
-15
lines changed

3 files changed

+126
-15
lines changed

kcidev/libs/dashboard.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
def _dashboard_request(func):
1515
@wraps(func)
16-
def wrapper(endpoint, params, use_json, body=None, max_retries=3):
16+
def wrapper(
17+
endpoint, params, use_json, body=None, max_retries=3, error_verbose=True
18+
):
1719
base_url = urllib.parse.urljoin(DASHBOARD_API, endpoint)
1820
url = "{}?{}".format(base_url, urllib.parse.urlencode(params))
1921
retries = 0
@@ -53,11 +55,12 @@ def wrapper(endpoint, params, use_json, body=None, max_retries=3):
5355
logging.debug(f"Response data size: {len(json.dumps(data))} bytes")
5456

5557
if "error" in data:
56-
logging.error(f"API returned error: {data.get('error')}")
57-
if use_json:
58-
kci_msg(data)
59-
else:
60-
kci_msg("json error: " + str(data["error"]))
58+
if error_verbose:
59+
logging.error(f"API returned error: {data.get('error')}")
60+
if use_json:
61+
kci_msg(data)
62+
else:
63+
kci_msg("json error: " + str(data["error"]))
6164
raise click.ClickException(data.get("error"))
6265

6366
logging.info(f"Successfully completed {func.__name__} request")
@@ -81,7 +84,7 @@ def dashboard_api_post(endpoint, params, use_json, body, max_retries=3):
8184

8285

8386
@_dashboard_request
84-
def dashboard_api_fetch(endpoint, params, use_json, max_retries=3):
87+
def dashboard_api_fetch(endpoint, params, use_json, max_retries=3, error_verbose=True):
8588
return requests.get(endpoint)
8689

8790

@@ -308,16 +311,20 @@ def dashboard_fetch_issue(issue_id, use_json):
308311
return dashboard_api_fetch(f"issue/{issue_id}", {}, use_json)
309312

310313

311-
def dashboard_fetch_issue_builds(origin, issue_id, use_json):
314+
def dashboard_fetch_issue_builds(origin, issue_id, use_json, error_verbose=True):
312315
logging.info(f"Fetching builds for issue ID: {issue_id}")
313-
params = {"filter_origin": origin}
314-
return dashboard_api_fetch(f"issue/{issue_id}/builds", params, use_json)
316+
params = {"filter_origin": origin} if origin else {}
317+
return dashboard_api_fetch(
318+
f"issue/{issue_id}/builds", params, use_json, error_verbose=error_verbose
319+
)
315320

316321

317-
def dashboard_fetch_issue_tests(origin, issue_id, use_json):
322+
def dashboard_fetch_issue_tests(origin, issue_id, use_json, error_verbose=True):
318323
logging.info(f"Fetching tests for issue ID: {issue_id}")
319-
params = {"filter_origin": origin}
320-
return dashboard_api_fetch(f"issue/{issue_id}/tests", params, use_json)
324+
params = {"filter_origin": origin} if origin else {}
325+
return dashboard_api_fetch(
326+
f"issue/{issue_id}/tests", params, use_json, error_verbose=error_verbose
327+
)
321328

322329

323330
def dashboard_fetch_issues_extra(issues, use_json):

kcidev/subcommands/results/__init__.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@
66
import click
77
from tabulate import tabulate
88

9-
from kcidev.libs.common import kci_msg_green, kci_msg_red
9+
from kcidev.libs.common import kci_msg, kci_msg_green, kci_msg_red
1010
from kcidev.libs.dashboard import (
1111
dashboard_fetch_boot_issues,
1212
dashboard_fetch_boots,
1313
dashboard_fetch_build,
1414
dashboard_fetch_build_issues,
1515
dashboard_fetch_builds,
1616
dashboard_fetch_commits_history,
17+
dashboard_fetch_issue,
18+
dashboard_fetch_issue_builds,
19+
dashboard_fetch_issue_tests,
1720
dashboard_fetch_issues_extra,
1821
dashboard_fetch_summary,
1922
dashboard_fetch_test,
@@ -36,6 +39,8 @@
3639
cmd_single_test,
3740
cmd_summary,
3841
cmd_tests,
42+
print_issue,
43+
print_issues,
3944
)
4045

4146

@@ -677,5 +682,55 @@ def detect(
677682
print_stats(stats, headers, max_col_width, table_fmt)
678683

679684

685+
@results.command(
686+
name="issue",
687+
help="""Fetch KCIDB issue matching provided ID.
688+
Also get associated builds and tests.
689+
690+
\b
691+
Examples:
692+
# Get issue information and associated builds/tests
693+
kci-dev results issue --id <id> --origin <origin>
694+
""",
695+
)
696+
@click.option(
697+
"--id",
698+
"issue_id",
699+
required=True,
700+
help="Issue ID to get information for",
701+
)
702+
@click.option(
703+
"--origin",
704+
help="Select KCIDB origin",
705+
)
706+
@results_display_options
707+
def issue(issue_id, origin, use_json):
708+
"""Get issue matching ID command handler"""
709+
# Get issue information
710+
data = dashboard_fetch_issue(issue_id, use_json)
711+
kci_msg_green("Issue information:")
712+
print_issue(data)
713+
714+
# Get associated builds and tests
715+
item_types = ["builds", "tests"]
716+
for item_type in item_types:
717+
if item_type == "builds":
718+
dashboard_func = dashboard_fetch_issue_builds
719+
else:
720+
dashboard_func = dashboard_fetch_issue_tests
721+
722+
try:
723+
kci_msg_green(f"Associated {item_type}:")
724+
data = dashboard_func(origin, issue_id, use_json, error_verbose=False)
725+
item_ids = [item["id"] for item in data]
726+
for item_id in item_ids:
727+
kci_msg(f"- {item_id}")
728+
kci_msg("")
729+
except click.ClickException as e:
730+
if f"No {item_type}" in e.message:
731+
kci_msg(f"No associated {item_type} found")
732+
kci_msg("")
733+
734+
680735
if __name__ == "__main__":
681736
main_kcidev()

kcidev/subcommands/results/parser.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import json
33
import logging
44
import re
5+
from urllib.parse import urlparse
56

67
import requests
78
import yaml
89

910
from kcidev.libs.common import *
10-
from kcidev.libs.dashboard import dashboard_fetch_tree_list
11+
from kcidev.libs.dashboard import DASHBOARD_API, dashboard_fetch_tree_list
1112
from kcidev.libs.files import download_logs_to_file
1213
from kcidev.libs.filters import (
1314
CompatibleFilter,
@@ -937,3 +938,51 @@ def format_item_json(regression):
937938

938939
if total_regressions == 0:
939940
kci_msg("✅ No regressions found - all status changes are expected")
941+
942+
943+
def print_issue_information(issue, dashboard_url):
944+
"""Extract and print issue information"""
945+
946+
if not isinstance(issue, dict):
947+
kci_err("Please provide issue dictionary to extract information")
948+
return
949+
950+
kci_msg_bold(f"- {issue.get('comment')}")
951+
kci_msg(f" {dashboard_url}/issue/{issue.get('id')}]")
952+
kci_msg(f" origin: {issue.get('origin')}")
953+
kci_msg(f" version: {issue.get('version')}")
954+
kci_msg(f" field_timestamp: {issue.get('field_timestamp')}")
955+
956+
for field in ["culprit_code", "culprit_tool", "culprit_harness"]:
957+
if not issue.get(field):
958+
continue
959+
if issue[field]:
960+
kci_msg_nonl(f" {field}: ")
961+
kci_msg_red(issue[field])
962+
else:
963+
kci_msg(f" {field}: {issue[field]}")
964+
965+
if issue.get("categories"):
966+
kci_msg_nonl(" categories:")
967+
kci_msg(issue["categories"])
968+
969+
970+
def print_issue(issue):
971+
"""Print issue information
972+
issue (dict): KCIDB issue dictionary"""
973+
974+
parsed = urlparse(DASHBOARD_API)
975+
dashboard_url = f"{parsed.scheme}://{parsed.netloc}"
976+
977+
print_issue_information(issue, dashboard_url)
978+
979+
extra = issue.get("extra")
980+
if extra.get(issue["id"]):
981+
incident = extra.get(issue["id"]).get("first_incident")
982+
if incident:
983+
tree_branch = (
984+
f'{incident.get("tree_name")}/{incident.get("git_repository_branch")}'
985+
)
986+
kci_msg_nonl(" First incident seen on ")
987+
kci_msg_bold(tree_branch)
988+
kci_msg("")

0 commit comments

Comments
 (0)