Skip to content

Commit 7f9ea0f

Browse files
tuxusoul-catcher
authored andcommitted
Stabilize the fingerprint
Remove the line number from fingerprint. If the same fingerprint is already used for another issue in the same file, generate another one. This is more stable compared to the line number itself, which changes whenever code is added or removed above the issue.
1 parent 33c6232 commit 7f9ea0f

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

mypy_gitlab_code_quality/__init__.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class GitlabIssue(TypedDict):
3535
location: GitlabIssueLocation
3636

3737

38-
def parse_issue(line: str) -> GitlabIssue | None:
38+
def parse_issue(line: str, fingerprints: set[str] | None = None) -> GitlabIssue | None:
3939
if line.startswith("{"):
4040
try:
4141
match = json.loads(line)
@@ -54,17 +54,38 @@ def parse_issue(line: str) -> GitlabIssue | None:
5454
)
5555
if match is None:
5656
return None
57-
fingerprint = hashlib.md5(line.encode("utf-8"), usedforsecurity=False).hexdigest()
5857
error_levels_table = {"error": Severity.major, "note": Severity.info}
58+
59+
path = match["file"]
60+
line_number = int(match["line"])
61+
error_level = match["severity"]
62+
message = match["message"]
63+
error_code = match["code"]
64+
65+
if fingerprints is None:
66+
fingerprints = set()
67+
68+
def make_fingerprint(salt: str) -> str:
69+
fingerprint_text = f"{salt}::{path}::{error_level}::{error_code}::{message}"
70+
return hashlib.md5(
71+
fingerprint_text.encode("utf-8"),
72+
usedforsecurity=False,
73+
).hexdigest()
74+
75+
fingerprint = make_fingerprint("")
76+
while fingerprint in fingerprints:
77+
fingerprint = make_fingerprint(fingerprint)
78+
fingerprints.add(fingerprint)
79+
5980
return {
60-
"description": match["message"],
61-
"check_name": match["code"],
81+
"description": message,
82+
"check_name": error_code,
6283
"fingerprint": fingerprint,
63-
"severity": error_levels_table.get(match["severity"], Severity.unknown),
84+
"severity": error_levels_table.get(error_level, Severity.unknown),
6485
"location": {
65-
"path": match["file"],
86+
"path": path,
6687
"lines": {
67-
"begin": int(match["line"]),
88+
"begin": line_number,
6889
},
6990
},
7091
}
@@ -91,7 +112,8 @@ def append_or_extend(issues: list[GitlabIssue], new: GitlabIssue) -> list[Gitlab
91112

92113

93114
def generate_report(lines: Iterable[str]) -> list[GitlabIssue]:
94-
issues = filter(None, map(parse_issue, lines))
115+
fingerprints: set[str] = set()
116+
issues = filter(None, (parse_issue(line, fingerprints) for line in lines))
95117
return reduce(append_or_extend, issues, [])
96118

97119

tests.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
import unittest
23

34
from mypy_gitlab_code_quality import Severity, parse_issue
@@ -14,7 +15,7 @@ def test_line_number(self):
1415

1516
def test_fingerprint(self):
1617
issue = parse_issue("module.py:2: error: Description")
17-
self.assertEqual("a19285c6cdf4dafe237cc5d2de6c0308", issue["fingerprint"])
18+
self.assertEqual("d84c90ce1414af244070c71da60f2388", issue["fingerprint"])
1819

1920
def test_error_level_error(self):
2021
issue = parse_issue("module.py:2: error: Description")
@@ -80,18 +81,21 @@ def test_line_number(self):
8081
self.assertEqual(2, issue["location"]["lines"]["begin"])
8182

8283
def test_fingerprint(self):
83-
issue = parse_issue(
84-
r"""{
85-
"file": "module.py",
86-
"line": 2,
87-
"column": 4,
88-
"message": "Description",
89-
"hint": null,
90-
"code": "error-code",
91-
"severity": "error"
92-
}"""
93-
)
94-
self.assertEqual("4455bb04f307121aa95a7b3725996837", issue["fingerprint"])
84+
fingerprints = set()
85+
issue_dict = {
86+
"file": "module.py",
87+
"line": 2,
88+
"column": 4,
89+
"message": "Description",
90+
"hint": None,
91+
"code": "error-code",
92+
"severity": "error",
93+
}
94+
issue = parse_issue(json.dumps(issue_dict), fingerprints)
95+
issue_dict["line"] = 3
96+
other_issue = parse_issue(json.dumps(issue_dict), fingerprints)
97+
self.assertEqual("59d5fc1777dba182a0bcac9dc1bd33a6", issue["fingerprint"])
98+
self.assertEqual("895f1dad0c7bb31d7bb4f792b2b16784", other_issue["fingerprint"])
9599

96100
def test_error_level_error(self):
97101
issue = parse_issue(

0 commit comments

Comments
 (0)