2021-05-17 16:31:58 +00:00
|
|
|
#!/usr/bin/env python3
|
2023-03-15 21:52:13 +00:00
|
|
|
|
|
|
|
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2021-05-17 16:31:58 +00:00
|
|
|
"""
|
|
|
|
Parse reports generated by Gradle and convert them into GitHub annotations.
|
|
|
|
|
|
|
|
See https://github.com/actions/toolkit/blob/master/docs/problem-matchers.md and
|
|
|
|
https://github.com/actions/toolkit/blob/master/docs/commands.md.
|
|
|
|
"""
|
|
|
|
|
2022-11-10 09:12:28 +00:00
|
|
|
import os.path
|
2021-05-17 16:31:58 +00:00
|
|
|
import pathlib
|
|
|
|
import re
|
2022-11-10 09:12:28 +00:00
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
from typing import Optional, Tuple
|
2021-05-17 16:31:58 +00:00
|
|
|
|
|
|
|
LUA_ERROR_LOCATION = re.compile(r"^\s+(/[\w./-]+):(\d+):", re.MULTILINE)
|
2021-07-18 15:17:11 +00:00
|
|
|
JAVA_LUA_ERROR_LOCATION = re.compile(r"^java.lang.IllegalStateException: (/[\w./-]+):(\d+):")
|
2021-05-17 16:31:58 +00:00
|
|
|
JAVA_ERROR_LOCATION = re.compile(r"^\tat ([\w.]+)\.[\w]+\([\w.]+:(\d+)\)$", re.MULTILINE)
|
|
|
|
ERROR_MESSAGE = re.compile(r"(.*)\nstack traceback:", re.DOTALL)
|
|
|
|
|
|
|
|
SPACES = re.compile(r"\s+")
|
|
|
|
|
|
|
|
SOURCE_LOCATIONS = [
|
|
|
|
"src/main/java",
|
|
|
|
"src/main/resources/data/computercraft/lua",
|
|
|
|
"src/test/java",
|
|
|
|
"src/test/resources",
|
|
|
|
]
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
PROJECT_LOCATIONS = [
|
|
|
|
"projects/core-api",
|
|
|
|
"projects/core",
|
|
|
|
"projects/common-api",
|
2022-11-10 09:12:28 +00:00
|
|
|
"projects/common",
|
2022-11-18 23:57:25 +00:00
|
|
|
"projects/fabric-api",
|
|
|
|
"projects/fabric",
|
2022-11-06 17:01:07 +00:00
|
|
|
"projects/forge-api",
|
2022-11-10 09:12:28 +00:00
|
|
|
"projects/forge",
|
2022-11-06 17:01:07 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
TEST_REPORTS = []
|
|
|
|
|
2021-05-17 16:31:58 +00:00
|
|
|
|
|
|
|
def find_file(path: str) -> Optional[str]:
|
2022-11-06 17:01:07 +00:00
|
|
|
while len(path) > 0 and path[0] == "/":
|
2021-05-17 16:31:58 +00:00
|
|
|
path = path[1:]
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
for project in PROJECT_LOCATIONS:
|
|
|
|
for source_dir in SOURCE_LOCATIONS:
|
|
|
|
child_path = os.path.join(project, source_dir, path)
|
|
|
|
if os.path.exists(child_path):
|
|
|
|
return child_path
|
2021-05-17 16:31:58 +00:00
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def find_location(message: str) -> Optional[Tuple[str, str]]:
|
|
|
|
location = LUA_ERROR_LOCATION.search(message)
|
|
|
|
if location:
|
|
|
|
file = find_file(location[1])
|
|
|
|
if file:
|
|
|
|
return file, location[2]
|
|
|
|
|
2021-07-18 15:17:11 +00:00
|
|
|
location = JAVA_LUA_ERROR_LOCATION.search(message)
|
|
|
|
if location:
|
|
|
|
file = find_file(location[1])
|
|
|
|
if file:
|
|
|
|
return file, location[2]
|
|
|
|
|
2021-05-17 16:31:58 +00:00
|
|
|
for location in JAVA_ERROR_LOCATION.findall(message):
|
|
|
|
file = find_file(location[0].replace(".", "/") + ".java")
|
|
|
|
if file:
|
|
|
|
return file, location[1]
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
def _parse_junit_file(path: pathlib.Path):
|
2022-11-18 23:57:25 +00:00
|
|
|
for testcase in ET.parse(path).findall(".//testcase"):
|
2022-11-06 17:01:07 +00:00
|
|
|
for result in testcase:
|
2022-11-18 23:57:25 +00:00
|
|
|
if result.tag == "skipped":
|
2022-11-06 17:01:07 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
name = f'{testcase.attrib["classname"]}.{testcase.attrib["name"]}'
|
|
|
|
message = result.attrib.get("message")
|
2022-11-18 23:57:25 +00:00
|
|
|
full_message = result.text or message
|
2022-11-06 17:01:07 +00:00
|
|
|
|
2022-11-18 23:57:25 +00:00
|
|
|
location = find_location(full_message)
|
2022-11-06 17:01:07 +00:00
|
|
|
error = ERROR_MESSAGE.match(message)
|
|
|
|
if error:
|
|
|
|
error = error[1]
|
|
|
|
else:
|
|
|
|
error = message
|
|
|
|
|
|
|
|
if location:
|
|
|
|
print(f'## {location[0]}:{location[1]}: {name} failed: {SPACES.sub(" ", error)}')
|
|
|
|
else:
|
|
|
|
print(f"::error::{name} failed")
|
|
|
|
|
|
|
|
print("::group::Full error message")
|
2022-11-18 23:57:25 +00:00
|
|
|
print(full_message)
|
2022-12-09 22:01:01 +00:00
|
|
|
print("::endgroup::")
|
2022-11-06 17:01:07 +00:00
|
|
|
|
|
|
|
|
2021-05-17 16:31:58 +00:00
|
|
|
def parse_junit() -> None:
|
|
|
|
"""
|
|
|
|
Scrape JUnit test reports for errors. We determine the location from the Lua
|
|
|
|
or Java stacktrace.
|
|
|
|
"""
|
|
|
|
print("::add-matcher::.github/matchers/junit.json")
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
for project in PROJECT_LOCATIONS:
|
|
|
|
for path in pathlib.Path(os.path.join(project, "build/test-results/test")).glob("TEST-*.xml"):
|
|
|
|
_parse_junit_file(path)
|
2021-05-17 16:31:58 +00:00
|
|
|
|
2022-11-18 23:57:25 +00:00
|
|
|
for path in pathlib.Path(os.path.join(project, "build/test-results")).glob("run*.xml"):
|
|
|
|
_parse_junit_file(path)
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
print("::remove-matcher owner=junit::")
|
2021-05-17 16:31:58 +00:00
|
|
|
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
def _parse_checkstyle(path: pathlib.Path):
|
|
|
|
for file in ET.parse(path).getroot():
|
|
|
|
for error in file:
|
|
|
|
filename = os.path.relpath(file.attrib["name"])
|
2021-05-17 16:31:58 +00:00
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
attrib = error.attrib
|
|
|
|
print(
|
|
|
|
f'{attrib["severity"]} {filename}:{attrib["line"]}:{attrib.get("column", 1)}: {SPACES.sub(" ", attrib["message"])}'
|
|
|
|
)
|
2021-05-17 16:31:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
def parse_checkstyle() -> None:
|
|
|
|
"""
|
|
|
|
Scrape JUnit test reports for errors. We determine the location from the Lua
|
|
|
|
or Java stacktrace.
|
|
|
|
"""
|
|
|
|
print("::add-matcher::.github/matchers/checkstyle.json")
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
for project in PROJECT_LOCATIONS:
|
|
|
|
for path in pathlib.Path(os.path.join(project, "build/reports/checkstyle/")).glob("*.xml"):
|
|
|
|
_parse_checkstyle(path)
|
2021-05-17 16:31:58 +00:00
|
|
|
|
|
|
|
print("::remove-matcher owner=checkstyle::")
|
|
|
|
|
2022-11-06 17:01:07 +00:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2021-05-17 16:31:58 +00:00
|
|
|
parse_junit()
|
|
|
|
parse_checkstyle()
|