If the description box is empty, new lines are not added between the last line and the marker data. If empty description boxes are eventually made possible, this will allow for that.
304 lines
16 KiB
GDScript
304 lines
16 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"],
|
|
"labels": labels
|
|
}
|
|
|
|
if not post_data["body"].is_empty(): post_data["body"] += "\n\n"
|
|
post_data["body"] += JSON.stringify(marker_data, "", false)
|
|
|
|
# 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 _get_project_name() -> String:
|
|
return ProjectSettings.get_setting("bugbot/reporting/gitea/repo_name", DEFAULT_REPO_NAME)
|
|
|
|
func _get_bug_url(bug_data:BugbotBugData) -> String:
|
|
var gitea_server : String = ProjectSettings.get_setting("bugbot/reporting/gitea/server", DEFAULT_SERVER)
|
|
var owner_name : String = ProjectSettings.get_setting("bugbot/reporting/gitea/owner_name", DEFAULT_OWNER_NAME)
|
|
var repo_name : String = ProjectSettings.get_setting("bugbot/reporting/gitea/repo_name", DEFAULT_REPO_NAME)
|
|
return "%s/%s/%s/issues/%d" % [gitea_server, owner_name, repo_name, bug_data.id]
|
|
|
|
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.
|
|
var priority_prefix : String = ProjectSettings.get_setting("bugbot/reporting/gitea/status_labels/priority_label_prefix", DEFAULT_PRIORITY_LABEL_PREFIX)
|
|
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 label:Dictionary in bug_in["labels"]:
|
|
bug_labels.append(label["name"] as String)
|
|
if priority_prefix and label["name"].begins_with(priority_prefix):
|
|
bug.severity = label["name"]
|
|
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["number"]
|
|
bug.key = String.num_int64(bug.id)
|
|
bug.title = bug_in["title"]
|
|
bug.body = bug_in["body"]
|
|
bug.component = &"Unused"
|
|
bug.platform = &"Unused"
|
|
bug.operating_system = &"Unused"
|
|
bug.status = bug_in["state"]
|
|
|
|
return bug
|