import hashlib import json import os import re import sys from typing import Dict, List class SourceRange(dict): def __init__(self, begin: int, end: int, column: int): super().__init__(begin=begin, end=end, column=column) class SourceLocation(dict): def __init__(self, path: str, lines: Dict[str, int]): super().__init__(path=path, lines=lines) class ClangTidyError(dict): def __init__( self, description: str, check_name: str, fingerprint: str, severity: str, location: SourceLocation, ): super().__init__( description=description, check_name=check_name, fingerprint=fingerprint, severity=severity, location=location, ) def parse_clang_tidy(log_file_path: str) -> List[ClangTidyError]: issues = [] pattern = re.compile( r"^(.*?):(\d+):(\d+):\s+(warning|error|note):\s+(.*?)\s+\[(.*?)\]$" ) repo_root = os.environ.get("CI_PROJECT_DIR", os.getcwd()) with open(log_file_path, "r") as f: for line in f: match = pattern.match(line) if not match: continue path, line, column, severity, message, name = match.groups() severity = "minor" if severity == "warning" else "major" try: path = os.path.relpath(path, repo_root) except ValueError: pass fingerprint_data = f"{path}:{line}:{column}:{message}:{name}" fingerprint = hashlib.sha256(fingerprint_data.encode()).hexdigest() issues.append( ClangTidyError( description=f"{message}", check_name=name, fingerprint=fingerprint, severity=severity, location=SourceLocation( path=path, lines=SourceRange( begin=int(line), end=int(line), column=int(column), ), ), ) ) return issues if __name__ == "__main__": if len(sys.argv) < 2: sys.exit("Usage: python3 parse_clang_tidy.py ") issues = parse_clang_tidy(sys.argv[1]) print(json.dumps(issues, indent=2))