pyright-to-gitlab 1.1.0__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyright_to_gitlab-1.1.0.dist-info → pyright_to_gitlab-1.2.0.dist-info}/METADATA +13 -5
- pyright_to_gitlab-1.2.0.dist-info/RECORD +6 -0
- {pyright_to_gitlab-1.1.0.dist-info → pyright_to_gitlab-1.2.0.dist-info}/WHEEL +1 -1
- pyright_to_gitlab-1.2.0.dist-info/entry_points.txt +2 -0
- pyright_to_gitlab.py +125 -28
- pyright_to_gitlab-1.1.0.dist-info/RECORD +0 -6
- pyright_to_gitlab-1.1.0.dist-info/entry_points.txt +0 -2
- {pyright_to_gitlab-1.1.0.dist-info → pyright_to_gitlab-1.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyright-to-gitlab
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Convert Pyright JSON output to GitLab CI/CD format
|
|
5
5
|
Project-URL: homepage, https://github.com/schollm/pyright-to-gitlab/
|
|
6
6
|
Project-URL: repository, https://github.com/schollm/pyright-to-gitlab/
|
|
@@ -12,7 +12,6 @@ Keywords: ci/cd,gitlab,pyright
|
|
|
12
12
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.8
|
|
17
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
18
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -24,12 +23,21 @@ Classifier: Topic :: Software Development
|
|
|
24
23
|
Classifier: Topic :: Software Development :: Testing
|
|
25
24
|
Classifier: Topic :: Utilities
|
|
26
25
|
Classifier: Typing :: Typed
|
|
27
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.8
|
|
28
27
|
Description-Content-Type: text/markdown
|
|
29
28
|
|
|
30
29
|
# pyright to gitlab
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
|
|
31
|
+
[](https://pypi.org/project/pyright-to-gitlab)
|
|
32
|
+
[](https://pypi.org/project/pyright-to-gitlab)
|
|
33
|
+
[](https://opensource.org/licenses/MIT)
|
|
34
|
+
[](https://github.com/astral-sh/ruff)
|
|
35
|
+
[](https://github.com/python/mypy)
|
|
36
|
+
|
|
37
|
+
Simple Python tool to convert Pyright JSON output to GitLab Code Quality report format.
|
|
38
|
+
|
|
39
|
+
**Zero runtime dependencies** - Pure Python implementation using only the standard library.
|
|
40
|
+
|
|
33
41
|
|
|
34
42
|
## Usage
|
|
35
43
|
Run the script with the path to the pyright output file:
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
pyright_to_gitlab.py,sha256=6b1sRM7aYWQShpWpAxmz5ANYOZla6-wEOxaZba20f6o,5794
|
|
2
|
+
pyright_to_gitlab-1.2.0.dist-info/METADATA,sha256=R__O7qdhzXfc6Vos3LTzr2q-BNceCWCL1LFpBCEdEoQ,2632
|
|
3
|
+
pyright_to_gitlab-1.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
4
|
+
pyright_to_gitlab-1.2.0.dist-info/entry_points.txt,sha256=0RnHrvYlZf3zD9BRTVQL564gF_fSuwF5IP13OB18540,61
|
|
5
|
+
pyright_to_gitlab-1.2.0.dist-info/licenses/LICENSE,sha256=tY29-MdtyUNoC3XN4IBzu_jxmb8U82z9UvLkQJuBiJM,1070
|
|
6
|
+
pyright_to_gitlab-1.2.0.dist-info/RECORD,,
|
pyright_to_gitlab.py
CHANGED
|
@@ -1,50 +1,147 @@
|
|
|
1
1
|
"""Convert pyright.json output to GitLab Code Quality report format."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import argparse
|
|
4
6
|
import hashlib
|
|
5
7
|
import json
|
|
6
8
|
import sys
|
|
7
9
|
import textwrap
|
|
8
|
-
from typing import TextIO,
|
|
10
|
+
from typing import Literal, TextIO, TypedDict
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Typing for PyRight Issue
|
|
14
|
+
class PyrightRangeElement(TypedDict):
|
|
15
|
+
"""Pyright Range Element (part of Range)."""
|
|
16
|
+
|
|
17
|
+
line: int
|
|
18
|
+
character: int
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class PyrightRange(TypedDict):
|
|
22
|
+
"""Pyright Range (Part of Issue)."""
|
|
23
|
+
|
|
24
|
+
start: PyrightRangeElement
|
|
25
|
+
end: PyrightRangeElement
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class PyrightIssue(TypedDict):
|
|
29
|
+
"""Single Pyright Issue.
|
|
30
|
+
|
|
31
|
+
Note: 'rule' field is optional in practice but marked as required in type hints.
|
|
32
|
+
Runtime code handles this with defensive .get() calls.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
file: str
|
|
36
|
+
severity: Literal["error", "warning", "information"]
|
|
37
|
+
message: str
|
|
38
|
+
rule: str # Optional in practice, handled via .get() at runtime
|
|
39
|
+
range: PyrightRange
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Typing for Gitlab Issue
|
|
43
|
+
class GitlabIssuePositionLocation(TypedDict):
|
|
44
|
+
"""Single Gitlab Position (Part of Position)."""
|
|
45
|
+
|
|
46
|
+
line: int
|
|
47
|
+
column: int
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class GitlabIssuePositions(TypedDict):
|
|
51
|
+
"""Gitlab ranged Position within a file (Part of Location)."""
|
|
52
|
+
|
|
53
|
+
begin: GitlabIssuePositionLocation
|
|
54
|
+
end: GitlabIssuePositionLocation
|
|
55
|
+
|
|
9
56
|
|
|
57
|
+
class GitlabIssueLocation(TypedDict):
|
|
58
|
+
"""Gitlab location (Part of Issue)."""
|
|
10
59
|
|
|
60
|
+
path: str
|
|
61
|
+
positions: GitlabIssuePositions
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class GitlabIssue(TypedDict):
|
|
65
|
+
"""Single Gitlab Issue."""
|
|
66
|
+
|
|
67
|
+
description: str
|
|
68
|
+
severity: Literal["major", "minor"]
|
|
69
|
+
fingerprint: str
|
|
70
|
+
check_name: str
|
|
71
|
+
location: GitlabIssueLocation
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### Functions
|
|
11
75
|
def _pyright_to_gitlab(input_: TextIO, prefix: str = "") -> str:
|
|
12
76
|
"""Convert pyright.json output to GitLab Code Quality report format.
|
|
13
77
|
|
|
78
|
+
Line numbers from Pyright are passed through unchanged (0-based per LSP spec).
|
|
79
|
+
GitLab expects the same format, so no conversion is needed.
|
|
80
|
+
|
|
14
81
|
:arg prefix: A string to prepend to each file path in the output.
|
|
15
82
|
This is useful if the application is in a subdirectory of the repository.
|
|
16
83
|
:return: JSON of issues in GitLab Code Quality report format.
|
|
84
|
+
:raises ValueError: If input is not a JSON object.
|
|
85
|
+
:raises TypeError: If input JSON is not an object.
|
|
17
86
|
|
|
18
87
|
Pyright format at https://github.com/microsoft/pyright/blob/main/docs/command-line.md
|
|
19
88
|
Gitlab format at https://docs.gitlab.com/ci/testing/code_quality/#code-quality-report-format
|
|
20
89
|
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
90
|
+
try:
|
|
91
|
+
data = json.load(input_)
|
|
92
|
+
except json.JSONDecodeError as e:
|
|
93
|
+
err_msg = f"Invalid JSON input: {e}"
|
|
94
|
+
raise ValueError(err_msg) from e
|
|
95
|
+
|
|
96
|
+
if not isinstance(data, dict):
|
|
97
|
+
err_msg = "Input must be a JSON object"
|
|
98
|
+
raise TypeError(err_msg)
|
|
99
|
+
|
|
100
|
+
return json.dumps(
|
|
101
|
+
[
|
|
102
|
+
_pyright_issue_to_gitlab(issue, prefix)
|
|
103
|
+
for issue in data.get("generalDiagnostics", [])
|
|
104
|
+
],
|
|
105
|
+
indent=2,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _pyright_issue_to_gitlab(issue: PyrightIssue, prefix: str) -> GitlabIssue:
|
|
110
|
+
"""Convert a single issue to gitlab.
|
|
111
|
+
|
|
112
|
+
Uses defensive .get() with defaults to handle missing optional fields.
|
|
113
|
+
File path defaults to '<anonymous>' and missing rule to 'unknown'.
|
|
114
|
+
|
|
115
|
+
:param issue: A pyright single issue.
|
|
116
|
+
:param prefix: The path prefix.
|
|
117
|
+
:returns: A gitlab single issue.
|
|
118
|
+
"""
|
|
119
|
+
start, end = (
|
|
120
|
+
issue.get("range", {}).get("start", {}),
|
|
121
|
+
issue.get("range", {}).get("end", {}),
|
|
122
|
+
)
|
|
123
|
+
rule = "pyright: " + issue.get("rule", "unknown")
|
|
124
|
+
# Unique fingerprint including file path to prevent collisions across files
|
|
125
|
+
fp_str = "--".join([issue.get("file", "<anonymous>"), str(start), str(end), rule])
|
|
126
|
+
|
|
127
|
+
return GitlabIssue(
|
|
128
|
+
description=issue.get("message", ""),
|
|
129
|
+
severity="major" if issue.get("severity") == "error" else "minor",
|
|
130
|
+
# Any hash function really works, does not have to be cryptographic.
|
|
131
|
+
fingerprint=hashlib.sha3_224(fp_str.encode()).hexdigest(),
|
|
132
|
+
check_name=rule,
|
|
133
|
+
location=GitlabIssueLocation(
|
|
134
|
+
path=f"{prefix}{issue['file']}" if "file" in issue else "<anonymous>",
|
|
135
|
+
positions=GitlabIssuePositions(
|
|
136
|
+
begin=GitlabIssuePositionLocation(
|
|
137
|
+
line=start.get("line", 0), column=start.get("character", 0)
|
|
138
|
+
),
|
|
139
|
+
end=GitlabIssuePositionLocation(
|
|
140
|
+
line=end.get("line", 0), column=end.get("character", 0)
|
|
141
|
+
),
|
|
142
|
+
),
|
|
143
|
+
),
|
|
144
|
+
)
|
|
48
145
|
|
|
49
146
|
|
|
50
147
|
def main() -> None:
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
pyright_to_gitlab.py,sha256=i_54FlXg4RD1_1dr5Kq6onIAua2zRsi9hs_uejB_SK0,3150
|
|
2
|
-
pyright_to_gitlab-1.1.0.dist-info/METADATA,sha256=9WGRB8rUH9ylhs98la_TMihlgQ6VNBe_gTAtrFOGjJk,2034
|
|
3
|
-
pyright_to_gitlab-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
4
|
-
pyright_to_gitlab-1.1.0.dist-info/entry_points.txt,sha256=MbNff91bPuO2XhW0P03N9O1Z7xtlr3x9duU5BftRbZo,60
|
|
5
|
-
pyright_to_gitlab-1.1.0.dist-info/licenses/LICENSE,sha256=tY29-MdtyUNoC3XN4IBzu_jxmb8U82z9UvLkQJuBiJM,1070
|
|
6
|
-
pyright_to_gitlab-1.1.0.dist-info/RECORD,,
|
|
File without changes
|