Skip to content

Commit 869104f

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 0e290f3 commit 869104f

File tree

3 files changed

+355
-16
lines changed

3 files changed

+355
-16
lines changed

kcidev/libs/dashboard.py

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

289289

290-
def dashboard_fetch_build_issues(build_id, use_json):
290+
def dashboard_fetch_build_issues(build_id, use_json, error_verbose):
291291
endpoint = f"build/{build_id}/issues"
292292
logging.info(f"Fetching build issues for build ID: {build_id}")
293-
return dashboard_api_fetch(endpoint, {}, use_json)
293+
return dashboard_api_fetch(endpoint, {}, use_json, error_verbose=error_verbose)
294294

295295

296-
def dashboard_fetch_boot_issues(test_id, use_json):
296+
def dashboard_fetch_boot_issues(test_id, use_json, error_verbose):
297297
endpoint = f"test/{test_id}/issues"
298298
logging.info(f"Fetching test issues for test ID: {test_id}")
299-
return dashboard_api_fetch(endpoint, {}, use_json)
299+
return dashboard_api_fetch(endpoint, {}, use_json, error_verbose=error_verbose)
300300

301301

302302
def dashboard_fetch_issue_list(origin, days, use_json):
303303
params = {
304-
"filter_origin": origin,
305304
"interval_in_days": days,
306305
}
306+
if origin:
307+
params["filter_origin"] = origin
307308
logging.info(f"Fetching issue list for origin: {origin}")
308309
return dashboard_api_fetch("issue/", params, use_json)
309310

kcidev/subcommands/results/__init__.py

Lines changed: 292 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
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,
12-
dashboard_fetch_boots,
12+
dashboard_fetch_boots,
1313
dashboard_fetch_build,
1414
dashboard_fetch_build_issues,
1515
dashboard_fetch_builds,
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

@@ -500,21 +502,22 @@ def print_stats(data, headers, max_col_width, table_fmt):
500502
)
501503

502504

503-
def get_new_issues(origin, tree_name, giturl, branch, commit, arch):
505+
def get_new_issues(origin, tree_name, giturl, branch, commit, arch, use_json=False):
504506
"""Get new KCIDB issue for a checkout"""
505507
try:
508+
kci_msg_green(f"{tree_name}/{branch}:{commit}")
506509
data = dashboard_fetch_summary(origin, giturl, branch, commit, arch, True)
507510
tree_summary = data["summary"]
508511
items = ["builds", "boots", "tests"]
509-
all_issues = []
510512
new_issues = []
513+
issue_id_version = []
511514
for item in items:
512515
for i in tree_summary[item]["issues"]:
513-
all_issues.append([i["id"], i["version"]])
514-
if not all_issues:
515-
kci_msg_red(f"{tree_name}/{branch}:{commit} No issues found")
516+
issue_id_version.append([i["id"], i["version"]])
517+
if not issue_id_version:
518+
kci_msg("No issues found")
516519
return
517-
issue_extras = dashboard_fetch_issues_extra(all_issues, True)["issues"]
520+
issue_extras = dashboard_fetch_issues_extra(issue_id_version, True)["issues"]
518521
for issue_id, extras in issue_extras.items():
519522
first_incident = extras.get("first_incident")
520523
if first_incident:
@@ -523,13 +526,18 @@ def get_new_issues(origin, tree_name, giturl, branch, commit, arch):
523526
first_incident["git_commit_hash"] == commit,
524527
first_incident["git_repository_url"] == giturl,
525528
first_incident["git_repository_branch"] == branch,
529+
first_incident["tree_name"] == tree_name,
526530
]
527531
):
528-
new_issues.append(issue_id)
532+
new_issues.append(dashboard_fetch_issue(issue_id, False))
529533
if not new_issues:
530-
kci_msg_red(f"{tree_name}/{branch}:{commit} No new issues found")
534+
kci_msg("No new issues found")
531535
else:
532-
kci_msg_green(f"{tree_name}/{branch}:{commit} New issues: {new_issues}")
536+
if use_json:
537+
kci_msg_json(new_issues)
538+
else:
539+
for i in new_issues:
540+
print_issue(i)
533541
except click.ClickException as e:
534542
print("Exception:", e.message)
535543

@@ -709,6 +717,279 @@ def detect(
709717
print_stats(stats, headers, max_col_width, table_fmt)
710718

711719

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

0 commit comments

Comments
 (0)