55import re
66from enum import Enum
77from functools import reduce
8+ from pathlib import Path
89from sys import stdin , stdout
9- from typing import TYPE_CHECKING , TypedDict
10+ from typing import TYPE_CHECKING , Any , TypedDict
1011
1112if TYPE_CHECKING :
1213 from collections .abc import Iterable
@@ -35,7 +36,7 @@ class GitlabIssue(TypedDict):
3536 location : GitlabIssueLocation
3637
3738
38- def parse_issue (line : str ) -> GitlabIssue | None :
39+ def parse_issue (line : str , cache : dict [ str , Any ] | None = None ) -> GitlabIssue | None :
3940 if line .startswith ("{" ):
4041 try :
4142 match = json .loads (line )
@@ -54,17 +55,43 @@ def parse_issue(line: str) -> GitlabIssue | None:
5455 )
5556 if match is None :
5657 return None
57- fingerprint = hashlib .md5 (line .encode ("utf-8" ), usedforsecurity = False ).hexdigest ()
5858 error_levels_table = {"error" : Severity .major , "note" : Severity .info }
59+
60+ path = match ["file" ]
61+ line_number = int (match ["line" ])
62+ error_level = match ["severity" ]
63+ message = match ["message" ]
64+ error_code = match ["code" ]
65+
66+ if cache is None :
67+ cache = {}
68+ if cache .get ("path" , "" ) != path :
69+ cache ["path" ] = path
70+ try :
71+ cache ["contents" ] = Path (path ).read_text ().splitlines ()
72+ except FileNotFoundError :
73+ # ignore non-existent files
74+ cache ["contents" ] = []
75+
76+ try :
77+ flagged_line = cache ["contents" ][line_number - 1 ]
78+ except IndexError :
79+ flagged_line = ""
80+
81+ fingerprint = f"{ path } ::{ error_level } ::{ error_code } ::{ message } ::{ flagged_line } "
82+ fingerprint = hashlib .md5 (
83+ fingerprint .encode ("utf-8" ), usedforsecurity = False
84+ ).hexdigest ()
85+
5986 return {
60- "description" : match [ " message" ] ,
61- "check_name" : match [ "code" ] ,
87+ "description" : message ,
88+ "check_name" : error_code ,
6289 "fingerprint" : fingerprint ,
63- "severity" : error_levels_table .get (match [ "severity" ] , Severity .unknown ),
90+ "severity" : error_levels_table .get (error_level , Severity .unknown ),
6491 "location" : {
65- "path" : match [ "file" ] ,
92+ "path" : path ,
6693 "lines" : {
67- "begin" : int ( match [ "line" ]) ,
94+ "begin" : line_number ,
6895 },
6996 },
7097 }
@@ -91,7 +118,8 @@ def append_or_extend(issues: list[GitlabIssue], new: GitlabIssue) -> list[Gitlab
91118
92119
93120def generate_report (lines : Iterable [str ]) -> list [GitlabIssue ]:
94- issues = filter (None , map (parse_issue , lines ))
121+ cache : dict [str , Any ] = {}
122+ issues = filter (None , (parse_issue (line , cache ) for line in lines ))
95123 return reduce (append_or_extend , issues , [])
96124
97125
0 commit comments