From 3a36d1316bb11cf297e6bbadc76b59c73fa7aaa8 Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Mon, 3 Jun 2024 14:20:46 -0400 Subject: [PATCH] Jira now supports all the same field types as the other APIs, with the addition of supporting cascading select lists for Hardware and OS combined. --- Scripts/server_jira_api.gd | 199 +++++++++++++++++++++++-------------- UI/bug_report_form.gd | 8 +- bugbot.gd | 3 +- 3 files changed, 134 insertions(+), 76 deletions(-) diff --git a/Scripts/server_jira_api.gd b/Scripts/server_jira_api.gd index 3f319c9..f04c258 100644 --- a/Scripts/server_jira_api.gd +++ b/Scripts/server_jira_api.gd @@ -2,6 +2,8 @@ class_name BugbotServerJiraAPI extends "res://addons/Bugbot/Scripts/server_api.gd" ##region Consts +const CHILD_OPTION_SEPARATOR : StringName = &" - " + const DEFAULT_SERVER : StringName = &"https://jira.example.com" const DEFAULT_REST_URI : StringName = &"rest/" const DEFAULT_PROJECT_NAME : StringName = &"ProjectName" @@ -13,6 +15,7 @@ const DEFAULT_MARKER_LOCATION_FIELD : StringName = &"Marker Location" const DEFAULT_DEPARTMENT_FIELD : StringName = &"" const DEFAULT_SEVERITY_FIELD : StringName = &"" const DEFAULT_PLATFORM_FIELD : StringName = &"" +const DEFAULT_OS_FIELD : StringName = &"" const DEFAULT_VERSION_FIELD : StringName = &"" const DEFAULT_UNRESOLVED_STATUSES : Array = [&"To Do"] @@ -29,6 +32,9 @@ func __return_list_of_bugs_thread(map_name:String, callback:Callable) -> void: var header_data : Array = __create_header_data() var server_data : BugbotJiraServerData = __get_server_data(http_client, header_data) + if not server_data: + __bugbot_server_thread.call_deferred("wait_to_finish") + return var project_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/project_name", DEFAULT_PROJECT_NAME) var url_string : String = "api/2/search" @@ -37,11 +43,14 @@ func __return_list_of_bugs_thread(map_name:String, callback:Callable) -> void: "fields": ["summary", "description", "issuetype", "status"] } if not server_data.map_name_field_key.is_empty(): post_data["fields"].append(server_data.map_name_field_key) - #if not server_data.department_field_key.is_empty(): post_data["fields"].append(server_data.department_field_key) if not server_data.marker_location_field_key.is_empty(): post_data["fields"].append(server_data.marker_location_field_key) if not server_data.severity_field_key.is_empty(): post_data["fields"].append(server_data.severity_field_key) + + if not server_data.department_field_key.is_empty(): post_data["fields"].append(server_data.department_field_key) if not server_data.platform_field_key.is_empty(): post_data["fields"].append(server_data.platform_field_key) - #if not server_data.version_field_key.is_empty(): post_data["fields"].append(server_data.version_field_key) + if not server_data.os_field_key.is_empty(): post_data["fields"].append(server_data.os_field_key) + if not server_data.version_field_key.is_empty(): post_data["fields"].append(server_data.version_field_key) + var post_data_string : String = JSON.stringify(post_data) header_data = __create_header_data(post_data_string.length()) @@ -51,9 +60,11 @@ func __return_list_of_bugs_thread(map_name:String, callback:Callable) -> void: http_client.poll() assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) var issue_response_string : String = __get_http_client_chunk_response(http_client) + var issue_response : Dictionary = JSON.parse_string(issue_response_string) + if __validate_server_response(issue_response) != Error.OK: + return var bug_array : Array - var issue_response : Dictionary = JSON.parse_string(issue_response_string) if issue_response: var issues_array : Array = issue_response["issues"] for issue:Dictionary in issues_array: @@ -81,33 +92,9 @@ func __prepare_form_thread(callback:Callable) -> void: var header_data : Array = __create_header_data() var server_data : BugbotJiraServerData = __get_server_data(http_client, header_data) - - # Send a query to retrieve issue types - var url_string : String = "api/2/issue/createmeta/%d/issuetypes?" % [server_data.project_id] - var error : int = http_client.request(HTTPClient.METHOD_GET, __build_url_string(url_string), header_data) - assert(error == Error.OK) - while http_client.get_status() == HTTPClient.STATUS_REQUESTING: - http_client.poll() - assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) - var issue_response_string : String = __get_http_client_chunk_response(http_client) - var issue_response : Dictionary = JSON.parse_string(issue_response_string) - - var bug_issue_type : String = ProjectSettings.get_setting("bugbot/reporting/jira/bug_issue_type", DEFAULT_BUG_ISSUE_TYPE) - var bug_issue_id : int = -1 - for issue_type:Dictionary in issue_response["issueTypes"]: - if issue_type["name"] == bug_issue_type: - bug_issue_id = int(issue_type["id"]) - break - - # Send a query to retrieve field options - url_string = "api/2/issue/createmeta/%d/issuetypes/%d" % [server_data.project_id, bug_issue_id] - error = http_client.request(HTTPClient.METHOD_GET, __build_url_string(url_string), header_data) - assert(error == Error.OK) - while http_client.get_status() == HTTPClient.STATUS_REQUESTING: - http_client.poll() - assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) - var field_response_string : String = __get_http_client_chunk_response(http_client) - var field_response : Dictionary = JSON.parse_string(field_response_string) + if not server_data: + __bugbot_server_thread.call_deferred("wait_to_finish") + return var tag_lists : Array tag_lists.resize(BugbotTagArray.MAX) @@ -116,18 +103,39 @@ func __prepare_form_thread(callback:Callable) -> void: tag_lists[BugbotTagArray.OS] = [] tag_lists[BugbotTagArray.COMPONENT] = [] tag_lists[BugbotTagArray.SEVERITY] = [] - #var version_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/version_label_prefix", DEFAULT_VERSION_LABEL_PREFIX) + var severity_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/status_labels/severity_field", DEFAULT_SEVERITY_FIELD) + + var department_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/department_field", DEFAULT_DEPARTMENT_FIELD) var platform_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/platform_field", DEFAULT_PLATFORM_FIELD) - var severity_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/severity_field", DEFAULT_SEVERITY_FIELD) - for field:Dictionary in field_response["fields"]: - if (field["name"] as String) == severity_field_name: + var os_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/os_field", DEFAULT_OS_FIELD) + var version_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/version_field", DEFAULT_VERSION_FIELD) + + for field:Dictionary in server_data.fields_response: + var field_name : String = (field["name"] as String) + if field_name == severity_field_name: for value:Dictionary in field["allowedValues"]: tag_lists[BugbotTagArray.SEVERITY].append({ "name": value["value"], "id": int(value["id"]) }) continue -# if (field["name"] as String) == platform_field_name: -# for value:Dictionary in field["allowedValues"]: -# tag_lists[BugbotTagArray.OS].append(value["value"]) -# continue + if field_name == department_field_name: + for value:Dictionary in field["allowedValues"]: + tag_lists[BugbotTagArray.COMPONENT].append({ "name": value["value"], "id": int(value["id"]) }) + continue + if field_name == platform_field_name: + for value:Dictionary in field["allowedValues"]: + if value.has("children"): + for child:Dictionary in value["children"]: + tag_lists[BugbotTagArray.HARDWARE].append({ "name": value["value"] + CHILD_OPTION_SEPARATOR + child["value"], "id": int(value["id"]), "child_name": child["value"], "child_id": int(child["id"]) }) + else: + tag_lists[BugbotTagArray.HARDWARE].append({ "name": value["value"], "id": int(value["id"]) }) + continue + if field_name == os_field_name: + for value:Dictionary in field["allowedValues"]: + tag_lists[BugbotTagArray.OS].append({ "name": value["value"], "id": int(value["id"]) }) + continue + if field_name == version_field_name: + for value:Dictionary in field["allowedValues"]: + tag_lists[BugbotTagArray.VERSION].append({ "name": value["name"], "id": int(value["id"]) }) + continue callback.call_deferred(tag_lists) __bugbot_server_thread.call_deferred("wait_to_finish") @@ -140,6 +148,9 @@ func __send_form_data_thread(data:Dictionary, map_name:String, bug_position:Vect var header_data : Array = __create_header_data() var server_data : BugbotJiraServerData = __get_server_data(http_client, header_data) + if not server_data: + __bugbot_server_thread.call_deferred("wait_to_finish") + return var project_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/project_name", DEFAULT_PROJECT_NAME) var bug_issue_type : String = ProjectSettings.get_setting("bugbot/reporting/jira/bug_issue_type", DEFAULT_BUG_ISSUE_TYPE) @@ -156,6 +167,16 @@ func __send_form_data_thread(data:Dictionary, map_name:String, bug_position:Vect } if data["labels"].has("severity"): post_data["fields"][server_data.severity_field_key] = { "value": data["labels"]["severity"]["name"] } + if data["labels"].has("version"): post_data["fields"][server_data.version_field_key] = { "value": data["labels"]["version"]["name"] } + if data["labels"].has("os"): post_data["fields"][server_data.os_field_key] = { "value": data["labels"]["os"]["name"] } + if data["labels"].has("component"): post_data["fields"][server_data.department_field_key] = { "value": data["labels"]["component"]["name"] } + + if data["labels"].has("hardware"): + post_data["fields"][server_data.platform_field_key] = { "value": data["labels"]["hardware"]["name"] } + if data["labels"]["hardware"].has("child_name"): + post_data["fields"][server_data.platform_field_key]["value"] = post_data["fields"][server_data.platform_field_key]["value"].split(CHILD_OPTION_SEPARATOR)[0] + post_data["fields"][server_data.platform_field_key]["child"] = { "value": data["labels"]["hardware"]["child_name"] } + var post_data_string : String = JSON.stringify(post_data) header_data = __create_header_data(post_data_string.length()) @@ -211,7 +232,11 @@ func __validate_server_response(_response:Variant) -> int: # If the response has an errorMessages field, make the assumption that this # is because the response was an error code. if _response.has("errors"): - for message:String in _response["errors"]: + if _response["errors"] is Dictionary: + for m:String in (_response["errors"] as Dictionary).values(): + printerr(m) + return Error.FAILED + for message:Variant in _response["errors"]: var error_data : BugbotErrorData = BugbotErrorData.new() error_data.code = 1 error_data.message = message @@ -302,17 +327,11 @@ func __get_server_data(http_client:HTTPClient, header_data:Array) -> BugbotJiraS http_client.poll() assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) var project_response_string : String = __get_http_client_chunk_response(http_client) - - api_url = __build_url_string("api/2/field") - error = http_client.request(HTTPClient.METHOD_GET, api_url, header_data) - assert(error == Error.OK) - while http_client.get_status() == HTTPClient.STATUS_REQUESTING: - http_client.poll() - assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) - var fields_response_string : String = __get_http_client_chunk_response(http_client) + var project_response : Array = JSON.parse_string(project_response_string) + if __validate_server_response(project_response) != Error.OK: + return server_data.project_name = ProjectSettings.get_setting("bugbot/reporting/jira/project_name", DEFAULT_PROJECT_NAME) - var project_response : Array = JSON.parse_string(project_response_string) for project:Dictionary in project_response: if project["name"] == server_data.project_name: server_data.project_id = project["id"] @@ -324,35 +343,66 @@ func __get_server_data(http_client:HTTPClient, header_data:Array) -> BugbotJiraS printerr(server_data.project_name + " could not not found.") return null + # Send a query to retrieve issue types + api_url = "api/2/issue/createmeta/%d/issuetypes" % [server_data.project_id] + error = http_client.request(HTTPClient.METHOD_GET, __build_url_string(api_url), header_data) + assert(error == Error.OK) + while http_client.get_status() == HTTPClient.STATUS_REQUESTING: + http_client.poll() + assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) + var issue_response_string : String = __get_http_client_chunk_response(http_client) + var issue_response : Dictionary = JSON.parse_string(issue_response_string) + if __validate_server_response(issue_response) != Error.OK: + return + + var bug_issue_type : String = ProjectSettings.get_setting("bugbot/reporting/jira/bug_issue_type", DEFAULT_BUG_ISSUE_TYPE) + var bug_issue_id : int = -1 + for issue_type:Dictionary in issue_response["issueTypes"]: + if issue_type["name"] == bug_issue_type: + bug_issue_id = int(issue_type["id"]) + break + + # Send a query to retrieve field options + api_url = "api/2/issue/createmeta/%d/issuetypes/%d" % [server_data.project_id, bug_issue_id] + error = http_client.request(HTTPClient.METHOD_GET, __build_url_string(api_url), header_data) + assert(error == Error.OK) + while http_client.get_status() == HTTPClient.STATUS_REQUESTING: + http_client.poll() + assert(http_client.get_status() == HTTPClient.STATUS_BODY or http_client.get_status() == HTTPClient.STATUS_CONNECTED) + var fields_response_string : String = __get_http_client_chunk_response(http_client) + var fields_response : Dictionary = JSON.parse_string(fields_response_string) + if __validate_server_response(fields_response) != Error.OK: + return + var map_name_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/map_name_field", DEFAULT_MAP_NAME_FIELD) var marker_location_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/marker_location_field", DEFAULT_MARKER_LOCATION_FIELD) - var severity_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/severity_field", DEFAULT_SEVERITY_FIELD) + var severity_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/status_labels/severity_field", DEFAULT_SEVERITY_FIELD) var platform_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/platform_field", DEFAULT_PLATFORM_FIELD) + var department_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/department_field", DEFAULT_DEPARTMENT_FIELD) + var version_field_name : String = ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/version_field", DEFAULT_VERSION_FIELD) - var fields_response : Array = JSON.parse_string(fields_response_string) - for field:Dictionary in fields_response: - if field.has("scope") and int(field["scope"]["project"]["id"]) != server_data.project_id: - continue - - var field_name : String = field["name"] - if field_name == map_name_field_name: - server_data.map_name_field_key = field["key"] - continue - if field_name == marker_location_field_name: - server_data.marker_location_field_key = field["key"] - continue - if field_name == severity_field_name: - server_data.severity_field_key = field["key"] - continue - if field_name == platform_field_name: - server_data.platform_field_key = field["key"] - continue -# if field_name == ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/department_field", DEFAULT_DEPARTMENT_FIELD): -# server_data.department_field_key = field["key"] -# continue -# if field_name == ProjectSettings.get_setting("bugbot/reporting/jira/optional_fields/version_field", DEFAULT_VERSION_FIELD): -# server_data.version_field_key = field["key"] -# continue + if fields_response.has("fields"): + for field:Dictionary in fields_response["fields"]: + var field_name : String = field["name"] + if field_name == map_name_field_name: + server_data.map_name_field_key = field["key"] + continue + if field_name == marker_location_field_name: + server_data.marker_location_field_key = field["key"] + continue + if field_name == severity_field_name: + server_data.severity_field_key = field["key"] + continue + if field_name == platform_field_name: + server_data.platform_field_key = field["key"] + continue + if field_name == department_field_name: + server_data.department_field_key = field["key"] + continue + if field_name == version_field_name: + server_data.version_field_key = field["key"] + continue + server_data.fields_response = fields_response["fields"] var map_name_error : bool = false var marker_location_error : bool = false @@ -378,6 +428,9 @@ class BugbotJiraServerData: var department_field_key : String var severity_field_key : String var platform_field_key : String + var os_field_key : String var version_field_key : String + var fields_response : Array + var timestamp : int diff --git a/UI/bug_report_form.gd b/UI/bug_report_form.gd index 88a2422..a88a2d0 100644 --- a/UI/bug_report_form.gd +++ b/UI/bug_report_form.gd @@ -126,9 +126,13 @@ func _on_submit_button_pressed() -> void: __server_api._send_form_data(bug_report_form_data, map_name, bug_location, bug_rotation, __submission_response) func __get_label_ids_for_submission_data(tag:Array, label_group_id:int, label:Label, button:MenuButton) -> bool: - for applied_label in __label_groups[label_group_id]: + for applied_label:Dictionary in __label_groups[label_group_id]: if applied_label["name"] == button.text: - tag.append({ "name": applied_label["name"], "id": applied_label["id"] }) + var label_data : Dictionary = { "name": applied_label["name"], "id": applied_label["id"] } + if applied_label.has("child_name"): + label_data["child_name"] = applied_label["child_name"] + label_data["child_id"] = applied_label["child_id"] + tag.append(label_data) break if tag.is_empty() and not (__label_groups[label_group_id] as Array).is_empty(): diff --git a/bugbot.gd b/bugbot.gd index 3524b59..dd685bf 100644 --- a/bugbot.gd +++ b/bugbot.gd @@ -84,9 +84,10 @@ func __initialise_project_settings() -> void: __add_project_setting("bugbot/reporting/jira/status_labels/unresolved_statuses", TYPE_ARRAY, BugbotServerJiraAPI.DEFAULT_UNRESOLVED_STATUSES, PROPERTY_HINT_ARRAY_TYPE, &"21/:") __add_project_setting("bugbot/reporting/jira/status_labels/in_progress_statuses", TYPE_ARRAY, BugbotServerJiraAPI.DEFAULT_IN_PROGRESS_STATUSES, PROPERTY_HINT_ARRAY_TYPE, &"21/:") __add_project_setting("bugbot/reporting/jira/status_labels/resolved_statuses", TYPE_ARRAY, BugbotServerJiraAPI.DEFAULT_RESOLVED_STATUSES, PROPERTY_HINT_ARRAY_TYPE, &"21/:") + __add_project_setting("bugbot/reporting/jira/status_labels/severity_field", TYPE_STRING, BugbotServerJiraAPI.DEFAULT_SEVERITY_FIELD) __add_project_setting("bugbot/reporting/jira/optional_fields/department_field", TYPE_STRING, BugbotServerJiraAPI.DEFAULT_DEPARTMENT_FIELD) - __add_project_setting("bugbot/reporting/jira/optional_fields/severity_field", TYPE_STRING, BugbotServerJiraAPI.DEFAULT_SEVERITY_FIELD) __add_project_setting("bugbot/reporting/jira/optional_fields/platform_field", TYPE_STRING, BugbotServerJiraAPI.DEFAULT_PLATFORM_FIELD) + __add_project_setting("bugbot/reporting/jira/optional_fields/os_field", TYPE_STRING, BugbotServerJiraAPI.DEFAULT_OS_FIELD) __add_project_setting("bugbot/reporting/jira/optional_fields/version_field", TYPE_STRING, BugbotServerJiraAPI.DEFAULT_VERSION_FIELD) #endregion #endregion