289 lines
15 KiB
GDScript
289 lines
15 KiB
GDScript
class_name BugbotServerGiteaAPI
|
|
extends "res://addons/Bugbot/Scripts/server_api.gd"
|
|
|
|
#region Consts
|
|
const DEFAULT_SERVER : StringName = &"https://gitea.example.com"
|
|
const DEFAULT_BASE_URL : StringName = &"api/v1/"
|
|
const DEFAULT_OWNER_NAME : StringName = &"ProjectOwner"
|
|
const DEFAULT_REPO_NAME : StringName = &"ProjectName"
|
|
const DEFAULT_API_KEY : StringName = &"0123456789abcdef0123456789abcdef01234567"
|
|
const DEFAULT_BUG_LABEL : StringName = &"Kind/Bug"
|
|
const DEFAULT_STATUS_LABEL : StringName = &"Status/Need More Info"
|
|
const DEFAULT_VERSION_LABEL_PREFIX : StringName = &"Version/"
|
|
const DEFAULT_HARDWARE_LABEL_PREFIX : StringName = &"Hardware/"
|
|
const DEFAULT_OS_LABEL_PREFIX : StringName = &"OS/"
|
|
const DEFAULT_COMPONENT_LABEL_PREFIX : StringName = &"Component/"
|
|
const DEFAULT_PRIORITY_LABEL_PREFIX : StringName = &"Priority/"
|
|
const DEFAULT_SHOW_ASSIGNED_AS_IN_PROGRESS : bool = true
|
|
|
|
const DEFAULT_UNRESOLVED_STATUSES : Array = []
|
|
const DEFAULT_IN_PROGRESS_STATUSES : Array = []
|
|
const DEFAULT_RESOLVED_STATUSES : Array = []
|
|
#endregion
|
|
|
|
|
|
func __return_list_of_bugs_thread(map_name:String, callback:Callable) -> void:
|
|
var http_client : HTTPClient = HTTPClient.new()
|
|
if __connect_to_server(http_client, ProjectSettings.get_setting("bugbot/reporting/gitea/server", DEFAULT_SERVER)) != HTTPClient.STATUS_CONNECTED:
|
|
printerr("Could not connect to server.")
|
|
return
|
|
|
|
var api_url : String = __build_url_string("issues")
|
|
api_url += "?state=all&labels=" + ProjectSettings.get_setting("bugbot/reporting/gitea/bug_label", DEFAULT_BUG_LABEL).uri_encode()
|
|
var header_data : Array = __create_header_data()
|
|
var error : int = 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 response_string : String = __get_http_client_chunk_response(http_client)
|
|
|
|
var response_data := JSON.parse_string(response_string)
|
|
if __validate_server_response(response_data) != Error.OK:
|
|
return
|
|
|
|
var bug_array : Array
|
|
var label_dict : Dictionary = {
|
|
"show_unresolved": ProjectSettings.get_setting("bugbot/markers/unresolved/show_unresolved_bugs", BugbotServerAPI.DEFAULT_SHOW_UNRESOLVED_BUGS),
|
|
"show_in_progress": ProjectSettings.get_setting("bugbot/markers/in_progress/show_in_progress_bugs", BugbotServerAPI.DEFAULT_SHOW_IN_PROGRESS_BUGS),
|
|
"show_resolved": ProjectSettings.get_setting("bugbot/markers/resolved/show_resolved_bugs", BugbotServerAPI.DEFAULT_SHOW_RESOLVED_BUGS),
|
|
|
|
"unresolved_labels": ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/unresolved_statuses", DEFAULT_UNRESOLVED_STATUSES),
|
|
"in_progress_labels": ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/in_progress_statuses", DEFAULT_IN_PROGRESS_STATUSES),
|
|
"resolved_labels": ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/resolved_statuses", DEFAULT_RESOLVED_STATUSES),
|
|
}
|
|
for bug_in:Dictionary in response_data:
|
|
var assigned_as_in_progress : bool = ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/show_assigned_as_in_progress", DEFAULT_SHOW_ASSIGNED_AS_IN_PROGRESS)
|
|
var bug : BugbotBugData = __create_bug_data_from_server_response(bug_in, map_name, label_dict, true, assigned_as_in_progress)
|
|
if bug:
|
|
bug_array.append(bug)
|
|
|
|
callback.call_deferred(bug_array)
|
|
__bugbot_server_thread.call_deferred("wait_to_finish")
|
|
|
|
func __prepare_form_thread(callback:Callable) -> void:
|
|
var http_client : HTTPClient = HTTPClient.new()
|
|
if __connect_to_server(http_client, ProjectSettings.get_setting("bugbot/reporting/gitea/server", DEFAULT_SERVER)) != HTTPClient.STATUS_CONNECTED:
|
|
printerr("Could not connect to server.")
|
|
return
|
|
|
|
# Pull a list of issue labels so we can get the ones we care about.
|
|
var api_url : String = __build_url_string("labels")
|
|
var header_data : Array = __create_header_data()
|
|
var error : int = 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 response_string : String = __get_http_client_chunk_response(http_client)
|
|
|
|
var response_data : Variant = JSON.parse_string(response_string)
|
|
if __validate_server_response(response_data) != Error.OK:
|
|
return
|
|
|
|
var tag_lists : Array
|
|
tag_lists.resize(BugbotTagArray.MAX)
|
|
tag_lists[BugbotTagArray.VERSION] = Array()
|
|
tag_lists[BugbotTagArray.HARDWARE] = Array()
|
|
tag_lists[BugbotTagArray.OS] = Array()
|
|
tag_lists[BugbotTagArray.COMPONENT] = Array()
|
|
tag_lists[BugbotTagArray.SEVERITY] = Array()
|
|
var priority_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/priority_label_prefix", DEFAULT_PRIORITY_LABEL_PREFIX)
|
|
var version_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/optional_labels/version_label_prefix", DEFAULT_VERSION_LABEL_PREFIX)
|
|
var hardware_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/optional_labels/hardware_label_prefix", DEFAULT_HARDWARE_LABEL_PREFIX)
|
|
var os_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/optional_labels/os_label_prefix", DEFAULT_OS_LABEL_PREFIX)
|
|
var component_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/optional_labels/component_label_prefix", DEFAULT_COMPONENT_LABEL_PREFIX)
|
|
|
|
response_data.sort_custom(func(a,b):return a["id"] < b["id"])
|
|
for label_in:Dictionary in response_data:
|
|
if version_prefix and label_in["name"].begins_with(version_prefix):
|
|
label_in["name"] = (label_in["name"] as String).replace(version_prefix, "")
|
|
tag_lists[BugbotTagArray.VERSION].append(label_in)
|
|
if hardware_prefix and label_in["name"].begins_with(hardware_prefix):
|
|
label_in["name"] = (label_in["name"] as String).replace(hardware_prefix, "")
|
|
tag_lists[BugbotTagArray.HARDWARE].append(label_in)
|
|
if os_prefix and label_in["name"].begins_with(os_prefix):
|
|
label_in["name"] = (label_in["name"] as String).replace(os_prefix, "")
|
|
tag_lists[BugbotTagArray.OS].append(label_in)
|
|
if component_prefix and label_in["name"].begins_with(component_prefix):
|
|
label_in["name"] = (label_in["name"] as String).replace(component_prefix, "")
|
|
tag_lists[BugbotTagArray.COMPONENT].append(label_in)
|
|
if priority_prefix and label_in["name"].begins_with(priority_prefix):
|
|
label_in["name"] = (label_in["name"] as String).replace(priority_prefix, "")
|
|
tag_lists[BugbotTagArray.SEVERITY].append(label_in)
|
|
|
|
callback.call_deferred(tag_lists)
|
|
__bugbot_server_thread.call_deferred("wait_to_finish")
|
|
|
|
func __send_form_data_thread(data:Dictionary, map_name:String, bug_position:Vector3, bug_normal:Vector3, callback:Callable) -> void:
|
|
var http_client : HTTPClient = HTTPClient.new()
|
|
if __connect_to_server(http_client, ProjectSettings.get_setting("bugbot/reporting/gitea/server", DEFAULT_SERVER)) != HTTPClient.STATUS_CONNECTED:
|
|
printerr("Could not connect to server.")
|
|
return
|
|
|
|
# Get a list of available labels to apply to the issue
|
|
var api_url : String = __build_url_string("labels")
|
|
var header_data : Array = __create_header_data()
|
|
var error : int = 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 response_data : Variant = JSON.parse_string(__get_http_client_chunk_response(http_client))
|
|
if __validate_server_response(response_data) != Error.OK:
|
|
return
|
|
|
|
# Collect the label IDs for each label we want to apply to this issue
|
|
var labels : Array
|
|
var bug_label : String = ProjectSettings.get_setting("bugbot/reporting/gitea/bug_label", DEFAULT_BUG_LABEL)
|
|
var status_label : String = ProjectSettings.get_setting("bugbot/reporting/gitea/default_status_label", DEFAULT_STATUS_LABEL)
|
|
for label_in:Dictionary in response_data:
|
|
if label_in["name"] == bug_label or label_in["name"] == status_label:
|
|
labels.append(label_in["id"])
|
|
if data["labels"].has("version"): labels.append(data["labels"]["version"]["id"])
|
|
if data["labels"].has("hardware"): labels.append(data["labels"]["hardware"]["id"])
|
|
if data["labels"].has("os"): labels.append(data["labels"]["os"]["id"])
|
|
if data["labels"].has("component"): labels.append(data["labels"]["component"]["id"])
|
|
if data["labels"].has("severity"): labels.append(data["labels"]["severity"]["id"])
|
|
|
|
var marker_data : Dictionary = {
|
|
"map_name": map_name,
|
|
"bug_position": [bug_position.x, bug_position.y, bug_position.z],
|
|
"bug_normal": [bug_normal.x, bug_normal.y, bug_normal.z]
|
|
}
|
|
|
|
var post_data : Dictionary = {
|
|
"title": data["title"],
|
|
"body": data["body"] + "\n\n" + JSON.stringify(marker_data, "", false),
|
|
"labels": labels
|
|
}
|
|
|
|
# Post issue to Gitea
|
|
api_url = __build_url_string("issues")
|
|
var post_data_string : String = JSON.stringify(post_data)
|
|
header_data = __create_header_data(post_data_string.length())
|
|
error = http_client.request(HTTPClient.METHOD_POST, api_url, header_data, post_data_string)
|
|
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 post_response_data : Variant = JSON.parse_string(__get_http_client_chunk_response(http_client))
|
|
if __validate_server_response(post_response_data) != Error.OK:
|
|
return
|
|
|
|
var label_dict : Dictionary = {
|
|
"show_unresolved": ProjectSettings.get_setting("bugbot/markers/unresolved/show_unresolved_bugs", true),
|
|
"show_in_progress": ProjectSettings.get_setting("bugbot/markers/in_progress/show_in_progress_bugs", true),
|
|
"show_resolved": ProjectSettings.get_setting("bugbot/markers/resolved/show_resolved_bugs", false),
|
|
|
|
"unresolved_labels": ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/unresolved_statuses", Array()),
|
|
"in_progress_labels": ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/in_progress_statuses", Array()),
|
|
"resolved_labels": ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/resolved_statuses", Array()),
|
|
}
|
|
var assigned_as_in_progress : bool = ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/show_assigned_as_in_progress", DEFAULT_SHOW_ASSIGNED_AS_IN_PROGRESS)
|
|
var bug_data : BugbotBugData = __create_bug_data_from_server_response(post_response_data, map_name, label_dict, false, assigned_as_in_progress)
|
|
|
|
callback.call_deferred(bug_data)
|
|
__bugbot_server_thread.call_deferred("wait_to_finish")
|
|
|
|
|
|
func _current_server_api() -> String:
|
|
return "Gitea"
|
|
|
|
func __build_url_string(_api_suffix:String) -> String:
|
|
return "/" + \
|
|
ProjectSettings.get_setting("bugbot/reporting/gitea/base_URL", DEFAULT_BASE_URL) + \
|
|
"/repos/" + \
|
|
ProjectSettings.get_setting("bugbot/reporting/gitea/owner_name", DEFAULT_OWNER_NAME) + \
|
|
"/" + \
|
|
ProjectSettings.get_setting("bugbot/reporting/gitea/repo_name", DEFAULT_REPO_NAME) + \
|
|
"/" + _api_suffix
|
|
|
|
func __create_header_data(content_length:int = -1) -> Array:
|
|
var header : Array = [
|
|
"User-Agent: Pirulo/1.0 (Godot)",
|
|
"Accept: application/json",
|
|
]
|
|
header.append("Authorization: token " + ProjectSettings.get_setting("bugbot/reporting/gitea/API_key", DEFAULT_API_KEY))
|
|
if content_length >= 0:
|
|
header.append("Content-Type: application/json")
|
|
header.append("Content-Length: " + String.num_uint64(content_length))
|
|
return header
|
|
|
|
func __validate_server_response(_response:Variant) -> int:
|
|
# If the response has a message field, make the assumption that this is
|
|
# because the response was an error code.
|
|
if _response.has("message"):
|
|
var error_data : BugbotErrorData = BugbotErrorData.new()
|
|
error_data.code = 1
|
|
error_data.message = _response["message"]
|
|
error_data.url = _response["url"]
|
|
printerr(error_data.message)
|
|
__bugbot_server_thread.call_deferred("wait_to_finish")
|
|
return Error.FAILED
|
|
return Error.OK
|
|
|
|
func __create_bug_data_from_server_response(bug_in:Dictionary, map_name:String, label_dict:Dictionary, validate_labels:bool, assigned_as_in_progress:bool) -> BugbotBugData:
|
|
var bugbot_marker_string : String = bug_in["body"].split("\n")[-1]
|
|
if not bugbot_marker_string.begins_with("{") and not bugbot_marker_string.ends_with("}"):
|
|
return null
|
|
|
|
var bug : BugbotBugData = BugbotBugData.new()
|
|
|
|
# Check if the map name is valid for the scene we're in.
|
|
var bugbot_marker_data : Dictionary = JSON.parse_string(bugbot_marker_string)
|
|
bug.map_name = bugbot_marker_data["map_name"]
|
|
if bug.map_name != map_name:
|
|
return null
|
|
|
|
var marker_location : Array = bugbot_marker_data["bug_position"]
|
|
var marker_normal : Array = bugbot_marker_data["bug_normal"]
|
|
bug.marker_position = Vector3(marker_location[0], marker_location[1], marker_location[2])
|
|
bug.marker_normal = Vector3(marker_normal[0], marker_normal[1], marker_normal[2])
|
|
|
|
var bug_labels : Array = []
|
|
var resolved_tag_found : bool = false
|
|
var in_progress_tag_found : bool = false
|
|
var unresolved_tag_found : bool = false
|
|
|
|
# Find which resolution statuses apply to this bug.
|
|
bug.is_open = (bug_in["state"] == "open")
|
|
if not bug.is_open:
|
|
resolved_tag_found = true
|
|
elif assigned_as_in_progress and bug_in["assignees"] is Array:
|
|
in_progress_tag_found = true
|
|
else:
|
|
for labels:Dictionary in bug_in["labels"]:
|
|
bug_labels.append(labels["name"] as String)
|
|
for label:String in label_dict["resolved_labels"] as Array:
|
|
if bug_labels.has(label): resolved_tag_found = true
|
|
for label:String in label_dict["in_progress_labels"] as Array:
|
|
if bug_labels.has(label): in_progress_tag_found = true
|
|
for label:String in label_dict["unresolved_labels"] as Array:
|
|
if bug_labels.has(label): unresolved_tag_found = true
|
|
|
|
# Figure out which resolution tag to prioritise, and whether we should show the marker.
|
|
var show_marker : bool
|
|
if resolved_tag_found:
|
|
bug.resolution = BugbotServerAPI.RESOLVED_TAG
|
|
show_marker = label_dict["show_resolved"] as bool
|
|
elif in_progress_tag_found:
|
|
bug.resolution = BugbotServerAPI.IN_PROGRESS_TAG
|
|
show_marker = label_dict["show_in_progress"] as bool
|
|
elif unresolved_tag_found or (label_dict["unresolved_labels"] as Array).is_empty():
|
|
bug.resolution = BugbotServerAPI.UNRESOLVED_TAG
|
|
show_marker = label_dict["show_unresolved"] as bool
|
|
if validate_labels and not show_marker:
|
|
return null
|
|
|
|
bug.id = bug_in["id"]
|
|
bug.title = bug_in["title"]
|
|
bug.body = bug_in["body"]
|
|
bug.component = &"Unused"
|
|
bug.platform = &"Unused"
|
|
bug.operating_system = &"Unused"
|
|
bug.severity = "Severity will go here."
|
|
bug.status = bug_in["state"]
|
|
|
|
return bug
|