1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-15 12:40:30 +00:00
CC-Tweaked/tools/parse-reports.py
Jonathan Coates 895bc7721a
License CC:T according to the REUSE specification (#1351)
This adds SPDX license headers to all source code files, following the
REUSE[1] specification. This does not include any asset files (such as
generated JSON files, or textures). While REUSE does support doing so
with ".license" files, for now we define these licences using the
.reuse/dep5 file.

[1]: https://reuse.software/
2023-03-15 21:52:13 +00:00

154 lines
4.4 KiB
Python
Executable File

#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
#
# SPDX-License-Identifier: MPL-2.0
"""
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.
"""
import os.path
import pathlib
import re
import xml.etree.ElementTree as ET
from typing import Optional, Tuple
LUA_ERROR_LOCATION = re.compile(r"^\s+(/[\w./-]+):(\d+):", re.MULTILINE)
JAVA_LUA_ERROR_LOCATION = re.compile(r"^java.lang.IllegalStateException: (/[\w./-]+):(\d+):")
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",
]
PROJECT_LOCATIONS = [
"projects/core-api",
"projects/core",
"projects/common-api",
"projects/common",
"projects/fabric-api",
"projects/fabric",
"projects/forge-api",
"projects/forge",
]
TEST_REPORTS = []
def find_file(path: str) -> Optional[str]:
while len(path) > 0 and path[0] == "/":
path = path[1:]
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
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]
location = JAVA_LUA_ERROR_LOCATION.search(message)
if location:
file = find_file(location[1])
if file:
return file, location[2]
for location in JAVA_ERROR_LOCATION.findall(message):
file = find_file(location[0].replace(".", "/") + ".java")
if file:
return file, location[1]
return None
def _parse_junit_file(path: pathlib.Path):
for testcase in ET.parse(path).findall(".//testcase"):
for result in testcase:
if result.tag == "skipped":
continue
name = f'{testcase.attrib["classname"]}.{testcase.attrib["name"]}'
message = result.attrib.get("message")
full_message = result.text or message
location = find_location(full_message)
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")
print(full_message)
print("::endgroup::")
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")
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)
for path in pathlib.Path(os.path.join(project, "build/test-results")).glob("run*.xml"):
_parse_junit_file(path)
print("::remove-matcher owner=junit::")
def _parse_checkstyle(path: pathlib.Path):
for file in ET.parse(path).getroot():
for error in file:
filename = os.path.relpath(file.attrib["name"])
attrib = error.attrib
print(
f'{attrib["severity"]} {filename}:{attrib["line"]}:{attrib.get("column", 1)}: {SPACES.sub(" ", attrib["message"])}'
)
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")
for project in PROJECT_LOCATIONS:
for path in pathlib.Path(os.path.join(project, "build/reports/checkstyle/")).glob("*.xml"):
_parse_checkstyle(path)
print("::remove-matcher owner=checkstyle::")
if __name__ == "__main__":
parse_junit()
parse_checkstyle()