Skip to content

Commit fbc9cde

Browse files
author
Jeny Sadadia
committed
Implement results issues command
`kci-dev results issues` command utilities: - Fetch KCIDB issues from the dashboard with `results issues` command - Filter issues by checkout by providing `--giturl`, `--branch`, `--commit` and `--tree`(optional) options - Get new issues for checkouts with `--new` option - Get failed/inconclusive builds and boots without any associated issues with `--missing` option Signed-off-by: Jeny Sadadia <[email protected]>
1 parent dc09960 commit fbc9cde

File tree

3 files changed

+357
-15
lines changed

3 files changed

+357
-15
lines changed

kcidev/libs/dashboard.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -296,23 +296,24 @@ def dashboard_fetch_hardware_tests(name, origin, use_json):
296296
)
297297

298298

299-
def dashboard_fetch_build_issues(build_id, use_json):
299+
def dashboard_fetch_build_issues(build_id, use_json, error_verbose):
300300
endpoint = f"build/{build_id}/issues"
301301
logging.info(f"Fetching build issues for build ID: {build_id}")
302-
return dashboard_api_fetch(endpoint, {}, use_json)
302+
return dashboard_api_fetch(endpoint, {}, use_json, error_verbose=error_verbose)
303303

304304

305-
def dashboard_fetch_boot_issues(test_id, use_json):
305+
def dashboard_fetch_boot_issues(test_id, use_json, error_verbose):
306306
endpoint = f"test/{test_id}/issues"
307307
logging.info(f"Fetching test issues for test ID: {test_id}")
308-
return dashboard_api_fetch(endpoint, {}, use_json)
308+
return dashboard_api_fetch(endpoint, {}, use_json, error_verbose=error_verbose)
309309

310310

311311
def dashboard_fetch_issue_list(origin, days, use_json):
312312
params = {
313-
"filter_origin": origin,
314313
"interval_in_days": days,
315314
}
315+
if origin:
316+
params["filter_origin"] = origin
316317
logging.info(f"Fetching issue list for origin: {origin}")
317318
return dashboard_api_fetch("issue/", params, use_json)
318319

kcidev/subcommands/results/__init__.py

Lines changed: 294 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import click
77
from tabulate import tabulate
88

9-
from kcidev.libs.common import kci_msg, kci_msg_green, kci_msg_red
9+
from kcidev.libs.common import kci_msg, kci_msg_green, kci_msg_json, kci_msg_red
1010
from kcidev.libs.dashboard import (
1111
dashboard_fetch_boot_issues,
1212
dashboard_fetch_boots,
@@ -16,6 +16,7 @@
1616
dashboard_fetch_commits_history,
1717
dashboard_fetch_issue,
1818
dashboard_fetch_issue_builds,
19+
dashboard_fetch_issue_list,
1920
dashboard_fetch_issue_tests,
2021
dashboard_fetch_issues_extra,
2122
dashboard_fetch_summary,
@@ -41,6 +42,7 @@
4142
cmd_tests,
4243
print_issue,
4344
print_issues,
45+
print_missing_data,
4446
)
4547

4648

@@ -509,21 +511,22 @@ def print_stats(data, headers, max_col_width, table_fmt):
509511
)
510512

511513

512-
def get_new_issues(origin, tree_name, giturl, branch, commit, arch):
514+
def get_new_issues(origin, tree_name, giturl, branch, commit, arch, use_json=False):
513515
"""Get new KCIDB issue for a checkout"""
514516
try:
517+
kci_msg_green(f"{tree_name}/{branch}:{commit}")
515518
data = dashboard_fetch_summary(origin, giturl, branch, commit, arch, True)
516519
tree_summary = data["summary"]
517520
items = ["builds", "boots", "tests"]
518-
all_issues = []
519521
new_issues = []
522+
issue_id_version = []
520523
for item in items:
521524
for i in tree_summary[item]["issues"]:
522-
all_issues.append([i["id"], i["version"]])
523-
if not all_issues:
524-
kci_msg_red(f"{tree_name}/{branch}:{commit} No issues found")
525+
issue_id_version.append([i["id"], i["version"]])
526+
if not issue_id_version:
527+
kci_msg("No issues found")
525528
return
526-
issue_extras = dashboard_fetch_issues_extra(all_issues, True)["issues"]
529+
issue_extras = dashboard_fetch_issues_extra(issue_id_version, True)["issues"]
527530
for issue_id, extras in issue_extras.items():
528531
first_incident = extras.get("first_incident")
529532
if first_incident:
@@ -532,13 +535,18 @@ def get_new_issues(origin, tree_name, giturl, branch, commit, arch):
532535
first_incident["git_commit_hash"] == commit,
533536
first_incident["git_repository_url"] == giturl,
534537
first_incident["git_repository_branch"] == branch,
538+
first_incident["tree_name"] == tree_name,
535539
]
536540
):
537-
new_issues.append(issue_id)
541+
new_issues.append(dashboard_fetch_issue(issue_id, False))
538542
if not new_issues:
539-
kci_msg_red(f"{tree_name}/{branch}:{commit} No new issues found")
543+
kci_msg("No new issues found")
540544
else:
541-
kci_msg_green(f"{tree_name}/{branch}:{commit} New issues: {new_issues}")
545+
if use_json:
546+
kci_msg_json(new_issues)
547+
else:
548+
for i in new_issues:
549+
print_issue(i)
542550
except click.ClickException as e:
543551
print("Exception:", e.message)
544552

@@ -718,6 +726,282 @@ def detect(
718726
print_stats(stats, headers, max_col_width, table_fmt)
719727

720728

729+
def get_missing_issue_items(
730+
ctx, origin, item_type, giturl, branch, commit, tree_name, arch
731+
):
732+
"""Get information of failed or inconclusive builds/boots for which KCIDB
733+
issues don't exist"""
734+
try:
735+
if item_type == "builds":
736+
results_cmd = builds
737+
dashboard_func = dashboard_fetch_build_issues
738+
elif item_type == "boots":
739+
results_cmd = boots
740+
dashboard_func = dashboard_fetch_boot_issues
741+
else:
742+
kci_msg_red("Please specify 'builds' or 'boots' as items type")
743+
return []
744+
745+
dashboard_items = ctx.invoke(
746+
results_cmd,
747+
origin=origin,
748+
giturl=giturl,
749+
branch=branch,
750+
commit=commit,
751+
status="all",
752+
count=True,
753+
verbose=False,
754+
arch=arch,
755+
error_verbose=False,
756+
)
757+
758+
missing_ids = []
759+
for item in dashboard_items:
760+
# Exclude passed builds/boots
761+
if item["status"] == "PASS":
762+
continue
763+
item_id = item["id"]
764+
try:
765+
_ = dashboard_func(item_id, False, error_verbose=False)
766+
except click.ClickException as e:
767+
if "No issues" in e.message:
768+
missing_ids.append({item_id: item["status"]})
769+
if missing_ids:
770+
return [f"{tree_name}/{branch}", commit, missing_ids]
771+
return []
772+
except click.Abort:
773+
kci_msg_red(
774+
f"{tree_name}/{branch}: Aborted while fetching dashboard builds/boots"
775+
)
776+
return []
777+
except click.ClickException as e:
778+
kci_msg_red(f"{tree_name}/{branch}: {e.message}")
779+
return []
780+
781+
782+
def get_filtered_issues(origin, tree_name, giturl, branch, commit, arch):
783+
"""Get KCIDB issues for a checkout"""
784+
try:
785+
kci_msg_green(f"{tree_name}/{branch}:{commit}")
786+
data = dashboard_fetch_summary(origin, giturl, branch, commit, arch, True)
787+
tree_summary = data["summary"]
788+
items = ["builds", "boots", "tests"]
789+
all_issues = []
790+
new_issues = []
791+
issue_id_version = []
792+
for item in items:
793+
for i in tree_summary[item]["issues"]:
794+
issue_item = dashboard_fetch_issue(i["id"], False)
795+
all_issues.append(issue_item)
796+
issue_id_version.append([i["id"], i["version"]])
797+
if not all_issues:
798+
kci_msg("No issues found")
799+
return
800+
issue_extras = dashboard_fetch_issues_extra(issue_id_version, True)["issues"]
801+
for issue_id, extras in issue_extras.items():
802+
first_incident = extras.get("first_incident")
803+
if first_incident:
804+
if all(
805+
[
806+
first_incident["git_commit_hash"] == commit,
807+
first_incident["git_repository_url"] == giturl,
808+
first_incident["git_repository_branch"] == branch,
809+
first_incident["tree_name"] == tree_name,
810+
]
811+
):
812+
new_issues.append(issue_id)
813+
814+
for i in all_issues:
815+
if i["id"] in new_issues:
816+
print_issue(i, True)
817+
else:
818+
print_issue(i)
819+
820+
except click.ClickException as e:
821+
print("Exception:", e.message)
822+
823+
824+
@results.command(
825+
name="issues",
826+
help="""Fetch KCIDB issues from the dashboard
827+
828+
\b
829+
Examples:
830+
# Get issues
831+
kci-dev results issues --origin <origin> --days <number-of-days>
832+
# Get new issues for all checkouts
833+
kci-dev issues --new --days <number-of-days> --origin <origin>
834+
# Get new issues for a checkout
835+
kci-dev issues --new --giturl <git-url> --branch <git-branch> --commit <commit> --origin <origin>
836+
# Get failed or inconclusive builds and boots without any issue for all checkouts
837+
kci-dev issues --missing
838+
# Get failed or inconclusive builds and boots without any issue for specific checkout
839+
kci-dev issues --missing --giturl <git-url> --branch <git-branch> --commit <commit> --origin <origin>
840+
# Get failed/inconclusive builds without issues
841+
kci-dev issues --missing --builds
842+
# Get failed/inconclusive boots without issues
843+
kci-dev issues --missing --boots
844+
""",
845+
)
846+
@click.option(
847+
"--origin",
848+
help="Select KCIDB origin",
849+
default="maestro",
850+
)
851+
@click.option(
852+
"--days",
853+
help="Provide a period of time in days to get results for",
854+
type=int,
855+
default="5",
856+
)
857+
@click.option(
858+
"--new",
859+
is_flag=True,
860+
help="Fetch new KCIDB issues for a checkout",
861+
)
862+
@click.option(
863+
"--giturl",
864+
help="Git URL of kernel tree",
865+
)
866+
@click.option(
867+
"--branch",
868+
help="Branch to get results for",
869+
)
870+
@click.option(
871+
"--commit",
872+
help="Commit or tag to get results for",
873+
)
874+
@click.option(
875+
"--git-folder",
876+
help="Path of git repository folder",
877+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
878+
)
879+
@click.option(
880+
"--latest",
881+
is_flag=True,
882+
help="Select latest results available",
883+
)
884+
@click.option(
885+
"--missing",
886+
is_flag=True,
887+
help="List all failed/incomplete builds and boots without any issue associated to them",
888+
)
889+
@click.option(
890+
"--builds",
891+
is_flag=True,
892+
help="The option can be used along with '--missing' to list only builds",
893+
)
894+
@click.option(
895+
"--boots",
896+
is_flag=True,
897+
help="The option can be used along with '--missing' to list only boots",
898+
)
899+
@click.option("--arch", help="Filter by arch")
900+
@click.option("--tree", help="Filter by tree name")
901+
@click.pass_context
902+
@results_display_options
903+
def issues(
904+
ctx,
905+
origin,
906+
days,
907+
new,
908+
giturl,
909+
branch,
910+
commit,
911+
use_json,
912+
latest,
913+
git_folder,
914+
arch,
915+
tree,
916+
missing,
917+
builds,
918+
boots,
919+
):
920+
"""Issues command handler"""
921+
if not new and not missing:
922+
if not any([giturl, branch, commit]):
923+
data = dashboard_fetch_issue_list(origin, days, use_json)
924+
print_issues(data)
925+
return
926+
if not all([giturl, branch, commit]):
927+
raise click.UsageError(
928+
"Please provide --giturl, --branch and --commit to get issues for"
929+
)
930+
if not tree:
931+
tree = get_tree_name(origin, giturl, branch)
932+
giturl, branch, commit = set_giturl_branch_commit(
933+
origin, giturl, branch, commit, latest, git_folder
934+
)
935+
get_filtered_issues(origin, tree, giturl, branch, commit, arch)
936+
if new:
937+
if not any([giturl, branch, commit]):
938+
kci_msg("Fetching new issues for all checkouts...")
939+
trees_list = ctx.invoke(trees, origin=origin, days=days, verbose=False)
940+
for t in trees_list:
941+
giturl = t["git_repository_url"]
942+
branch = t["git_repository_branch"]
943+
commit = t["git_commit_hash"]
944+
tree_name = t["tree_name"]
945+
get_new_issues(
946+
origin, tree_name, giturl, branch, commit, arch, use_json
947+
)
948+
return
949+
if not all([giturl, branch, commit]):
950+
raise click.UsageError(
951+
"Please provide --giturl, --branch, and --commit to fetch new issues for "
952+
"a checkout or else omit all these options to fetch new issues for all the "
953+
"checkouts"
954+
)
955+
kci_msg("Fetching new issues for the checkout...")
956+
giturl, branch, commit = set_giturl_branch_commit(
957+
origin, giturl, branch, commit, latest, git_folder
958+
)
959+
if not tree:
960+
tree = get_tree_name(origin, giturl, branch)
961+
get_new_issues(origin, tree, giturl, branch, commit, arch, use_json)
962+
if missing:
963+
if builds:
964+
item_types = ["builds"]
965+
elif boots:
966+
item_types = ["boots"]
967+
else:
968+
item_types = ["builds", "boots"]
969+
970+
if all([giturl, branch, commit]):
971+
if not tree:
972+
tree = get_tree_name(origin, giturl, branch)
973+
for item_type in item_types:
974+
final_stats = []
975+
kci_msg("")
976+
kci_msg_green(f"Fetching data for {item_type}...")
977+
stats = get_missing_issue_items(
978+
ctx, origin, item_type, giturl, branch, commit, tree, arch
979+
)
980+
if stats:
981+
final_stats.append(stats)
982+
if final_stats:
983+
print_missing_data(item_type, final_stats)
984+
985+
else:
986+
trees_list = ctx.invoke(trees, origin=origin, days=days, verbose=False)
987+
for item_type in item_types:
988+
kci_msg("")
989+
kci_msg_green(f"Fetching data for {item_type}...")
990+
final_stats = []
991+
for tree in trees_list:
992+
giturl = tree["git_repository_url"]
993+
branch = tree["git_repository_branch"]
994+
commit = tree["git_commit_hash"]
995+
tree_name = tree["tree_name"]
996+
stats = get_missing_issue_items(
997+
ctx, origin, item_type, giturl, branch, commit, tree_name, arch
998+
)
999+
if stats:
1000+
final_stats.append(stats)
1001+
if final_stats:
1002+
print_missing_data(item_type, final_stats)
1003+
1004+
7211005
@results.command(
7221006
name="issue",
7231007
help="""Fetch KCIDB issue matching provided ID.

0 commit comments

Comments
 (0)