pyright-to-gitlab 1.0.1__tar.gz

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.
@@ -0,0 +1,92 @@
1
+ name: Python Application
2
+
3
+ on: [push]
4
+
5
+ jobs:
6
+ testing:
7
+ name: Testing
8
+ uses: ./.github/workflows/testing.yml
9
+
10
+ build:
11
+ name: Build package 📦
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - name: Set up Python 3.12
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: 3.12
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v5
21
+ - name: Build package
22
+ run: uv build
23
+ - name: Upload dist-build
24
+ uses: actions/upload-artifact@v4
25
+ with:
26
+ name: python-package-distributions
27
+ path: dist/
28
+
29
+ publish-to-pypi:
30
+ name: >-
31
+ Publish Python 🐍 distribution 📦 to PyPI
32
+ needs: [testing]
33
+ if: success() && startsWith(github.ref, 'refs/tags/v')
34
+ runs-on: ubuntu-latest
35
+ environment:
36
+ name: pypi
37
+ url: https://pypi.org/p/pyright-to-gitlab
38
+ permissions:
39
+ id-token: write # IMPORTANT: mandatory for trusted publishing
40
+
41
+ steps:
42
+ - name: Download all the dists
43
+ uses: actions/download-artifact@v4
44
+ with:
45
+ name: python-package-distributions
46
+ path: dist/
47
+ - name: Publish distribution 📦 to PyPI
48
+ uses: pypa/gh-action-pypi-publish@release/v1
49
+
50
+ github-release:
51
+ name: >-
52
+ Sign the Python 🐍 distribution 📦 with Sigstore
53
+ and upload them to GitHub Release
54
+ needs: [testing]
55
+ if: success() && startsWith(github.ref, 'refs/tags/v')
56
+ runs-on: ubuntu-latest
57
+
58
+ permissions:
59
+ contents: write # IMPORTANT: mandatory for making GitHub Releases
60
+ id-token: write # IMPORTANT: mandatory for sigstore
61
+
62
+ steps:
63
+ - name: Download all the dists
64
+ uses: actions/download-artifact@v4
65
+ with:
66
+ name: python-package-distributions
67
+ path: dist/
68
+ - name: Sign the dists with Sigstore
69
+ uses: sigstore/gh-action-sigstore-python@v3.0.0
70
+ with:
71
+ inputs: >-
72
+ ./dist/*.tar.gz
73
+ ./dist/*.whl
74
+ - name: Create GitHub Release
75
+ env:
76
+ GITHUB_TOKEN: ${{ github.token }}
77
+ run: >-
78
+ gh release create
79
+ '${{ github.ref_name }}'
80
+ --repo '${{ github.repository }}'
81
+ --notes "" || echo "Release already exists, continuing to sign artifacts."
82
+ - name: Upload artifact signatures to GitHub Release
83
+ env:
84
+ GITHUB_TOKEN: ${{ github.token }}
85
+ # Upload to GitHub Release using the `gh` CLI.
86
+ # `dist/` contains the built packages and the
87
+ # sigstore-produced signatures and certificates.
88
+ run: >-
89
+ gh release upload --clobber
90
+ '${{ github.ref_name }}' dist/**
91
+ --repo '${{ github.repository }}'
92
+
@@ -0,0 +1,72 @@
1
+ name: Testing
2
+
3
+ on:
4
+ workflow_call:
5
+
6
+ jobs:
7
+ lint-typing:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - uses: actions/checkout@v4
11
+ - name: Install uv
12
+ uses: astral-sh/setup-uv@v5
13
+ - name: Install project dependencies
14
+ run: uv sync
15
+ - name: 'Type check'
16
+ run: uv run pyright src
17
+ lint:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - uses: astral-sh/ruff-action@v3
22
+ with:
23
+ src: "./src"
24
+ args: "check"
25
+ - name: 'Ruff format check'
26
+ run: ruff format --check
27
+ - name: 'Ruff check'
28
+ run: ruff check
29
+ test:
30
+ name: 🐍
31
+ strategy:
32
+ matrix:
33
+ os: ['ubuntu-latest', 'macos-latest', 'windows-latest']
34
+ python-version: ["3.12"]
35
+ # Add all python versions for ubuntu.
36
+ include:
37
+ - os: "ubuntu-latest"
38
+ python-version: "3.8"
39
+ - os: "ubuntu-latest"
40
+ python-version: "3.10"
41
+ - os: "ubuntu-latest"
42
+ python-version: "3.11"
43
+ - os: "ubuntu-latest"
44
+ python-version: "3.13"
45
+ coverage: true
46
+ runs-on: ${{ matrix.os }}
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ - name: Set up Python ${{ matrix.python-version }}
50
+ uses: actions/setup-python@v5
51
+ with:
52
+ python-version: ${{ matrix.python-version }}
53
+ - name: Install uv
54
+ uses: astral-sh/setup-uv@v5
55
+ - name: Install dependencies
56
+ run: uv sync
57
+ - name: Run pytest
58
+ run: |
59
+ echo ${{ github.ref }}
60
+ uv run --python ${{ matrix.python-version }} pytest tests/
61
+ - name: Code Coverage Summary Report
62
+ if: matrix.coverage==true
63
+ uses: irongut/CodeCoverageSummary@v1.3.0
64
+ with:
65
+ filename: '.out/coverage*.xml'
66
+ badge: true
67
+ format: 'markdown'
68
+ output: 'both'
69
+ thresholds: '75 98'
70
+ - name: Write to Job Summary
71
+ if: matrix.coverage==true
72
+ run: cat code-coverage-results.md >> $GITHUB_STEP_SUMMARY
@@ -0,0 +1,13 @@
1
+ # Python-generated files
2
+ .idea/**
3
+ __pycache__/
4
+ *.py[oc]
5
+ build/
6
+ dist/
7
+ wheels/
8
+ *.egg-info
9
+ **/.out/**
10
+ .python-version
11
+ **/.coverage
12
+ # Virtual environments
13
+ .venv
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+
8
+ ## [Upcoming]
9
+
10
+ ## [1.0.0] - 2025-06-02
11
+ Initial release.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Micha Schöll
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyright-to-gitlab
3
+ Version: 1.0.1
4
+ Summary: Convert Pyright JSON output to GitLab CI/CD format
5
+ Author: Micha Schöll
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Micha Schöll
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ License-File: LICENSE
28
+ Requires-Python: >=3.6
29
+ Description-Content-Type: text/markdown
30
+
31
+ # pyright to gitlab
32
+ Simple Python script to convert a pyright --outputjson to a gitlab code-quality report.
33
+
34
+ ## Usage
35
+ Run the script with the path to the pyright output file:
36
+ ```shell
37
+ $ pip install pyright-to-gitlab
38
+ $ pyright . --outputjson | pyright-to-gitlab > code-quality.json
39
+ ```
40
+
41
+ Alternatively, the module can be called:
42
+ ```shell
43
+ $ pip install pyright-to-gitlab
44
+ $ pyright . --outputjson | python -m pyright_to_gitlab > code-quality.json
45
+ ```
46
+ ### Custom path prefix
47
+ The `--prefix` option adds a custom prefix to the file paths in the output. This is
48
+ useful if the paths in the pyright output are not relative to the root of the repository.
49
+
50
+
51
+ ```shell
52
+ $ pyright . --outputjson | pyright-to-gitlab --prefix my-app/ > code-quality.json
53
+ ```
54
+
55
+ ## Testing
56
+ To run the tests, execute
57
+ ```shell
58
+ $ uv run pytest tests/
59
+ ```
@@ -0,0 +1,29 @@
1
+ # pyright to gitlab
2
+ Simple Python script to convert a pyright --outputjson to a gitlab code-quality report.
3
+
4
+ ## Usage
5
+ Run the script with the path to the pyright output file:
6
+ ```shell
7
+ $ pip install pyright-to-gitlab
8
+ $ pyright . --outputjson | pyright-to-gitlab > code-quality.json
9
+ ```
10
+
11
+ Alternatively, the module can be called:
12
+ ```shell
13
+ $ pip install pyright-to-gitlab
14
+ $ pyright . --outputjson | python -m pyright_to_gitlab > code-quality.json
15
+ ```
16
+ ### Custom path prefix
17
+ The `--prefix` option adds a custom prefix to the file paths in the output. This is
18
+ useful if the paths in the pyright output are not relative to the root of the repository.
19
+
20
+
21
+ ```shell
22
+ $ pyright . --outputjson | pyright-to-gitlab --prefix my-app/ > code-quality.json
23
+ ```
24
+
25
+ ## Testing
26
+ To run the tests, execute
27
+ ```shell
28
+ $ uv run pytest tests/
29
+ ```
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "pyright-to-gitlab"
3
+ version = "1.0.1"
4
+ description = "Convert Pyright JSON output to GitLab CI/CD format"
5
+ readme = "README.md"
6
+ requires-python = ">=3.6"
7
+ authors = [
8
+ { name = "Micha Schöll", email = "" }
9
+ ]
10
+ license = { file = "LICENSE" }
11
+ [project.scripts]
12
+ pyrigh-to-gitlab = 'pyright_to_gitlab:main'
13
+
14
+ [build-system]
15
+ requires = ["hatchling"]
16
+ build-backend = "hatchling.build"
17
+
18
+ [tool.hatch.build.targets.wheel]
19
+ packages = ["src/pyright_to_gitlab.py"]
20
+
21
+ [dependency-groups]
22
+ dev = [
23
+ "pyright>=0.0.13.post0",
24
+ "pytest>=7.0.1",
25
+ "pytest-cov>=4.0.0",
26
+ "ruff>=0.0.17",
27
+ ]
28
+
29
+ [tool.ruff]
30
+ line-length = 88
31
+
32
+ [tool.ruff.lint]
33
+ select = ["ALL"]
34
+ ignore = [
35
+ "D213", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible.
36
+ "D203", # `incorrect-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible.
37
+ "COM812", # Missing trailing comma in a single-line list - already applied by ruff format.
38
+ "D205", # 1 blank line required between summary line and description: ruff format disagrees.
39
+
40
+ ]
41
+
42
+ [tool.ruff.lint.per-file-ignores]
43
+ "tests/**/*.py" = [
44
+ # at least this three should be fine in tests:
45
+ "S101", # asserts allowed in tests...
46
+ "ARG", # Unused function args -> fixtures nevertheless are functionally relevant...
47
+ "FBT", # Don't care about booleans as positional arguments in tests, e.g. via @pytest.mark.parametrize()
48
+ ]
49
+
50
+ [tool.pytest.ini_options]
51
+ addopts = """
52
+ --junit-xml=.out/junit-pytest.xml
53
+ --cov=pyright_to_gitlab
54
+ --cov-report=xml:.out/coverage.xml
55
+ --cov-report=html:.out/coverage-html
56
+ --cov-report term-missing
57
+ --cov-branch
58
+ """
@@ -0,0 +1,66 @@
1
+ """Convert pyright.json output to GitLab Code Quality report format."""
2
+
3
+ import argparse
4
+ import hashlib
5
+ import json
6
+ import sys
7
+ from typing import cast
8
+
9
+
10
+ def _pyright_to_gitlab(prefix: str = "") -> str:
11
+ """Convert pyright.json output to GitLab Code Quality report format.
12
+
13
+ :arg prefix: A string to prepend to each file path in the output.
14
+ This is useful if the application is in a subdirectory of the repository.
15
+ :return: JSON of issues in GitLab Code Quality report format.
16
+
17
+ Pyright format at https://github.com/microsoft/pyright/blob/main/docs/command-line.md
18
+ Gitlab format at https://docs.gitlab.com/ci/testing/code_quality/#code-quality-report-format
19
+ """
20
+ data = cast("dict", json.load(sys.stdin))
21
+
22
+ issues = []
23
+ for issue in data.get("generalDiagnostics", []):
24
+ file = issue["file"]
25
+ start, end = issue["range"]["start"], issue["range"]["end"]
26
+ rule = "pyright: " + issue.get("rule", "")
27
+ severity = "major" if issue["severity"] == "error" else "minor"
28
+ # unique fingerprint
29
+ fp_str = "--".join([str(start), str(end), rule])
30
+
31
+ issues.append(
32
+ {
33
+ "description": issue["message"],
34
+ "severity": severity,
35
+ "fingerprint": hashlib.sha3_224(fp_str.encode()).hexdigest(),
36
+ "check_name": rule,
37
+ "location": {
38
+ "path": f"{prefix}{file}",
39
+ "positions": {
40
+ "begin": {"line": start["line"], "column": start["character"]},
41
+ "end": {"line": end["line"], "column": end["character"]},
42
+ },
43
+ },
44
+ }
45
+ )
46
+ return json.dumps(issues, indent=2)
47
+
48
+
49
+ def main() -> None:
50
+ """Parse arguments and call the conversion function."""
51
+ parser = argparse.ArgumentParser(
52
+ description="Convert pyright.json to GitLab Code Quality report."
53
+ )
54
+ parser.add_argument(
55
+ "--prefix",
56
+ type=str,
57
+ default="",
58
+ help="Prefix to add to each file (default: empty string)",
59
+ )
60
+ args = parser.parse_args()
61
+
62
+ print(_pyright_to_gitlab(prefix=args.prefix)) # noqa: T201
63
+
64
+
65
+ if __name__ == "__main__": # pragma: no cover
66
+ main()
@@ -0,0 +1 @@
1
+ """Tests for the pyright_to_gitlab module."""
@@ -0,0 +1,125 @@
1
+ """Tests for the pyright_to_gitlab module."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import io
6
+ import json
7
+
8
+ import pytest
9
+
10
+ from pyright_to_gitlab import main
11
+
12
+ PYRIGHT = {
13
+ "version": "1.1.385",
14
+ "time": "1748865254393",
15
+ "generalDiagnostics": [
16
+ {
17
+ "file": "test1.py",
18
+ "severity": "error",
19
+ "message": 'Message "foo"',
20
+ "range": {
21
+ "start": {"line": 101, "character": 27},
22
+ "end": {"line": 101, "character": 35},
23
+ },
24
+ "rule": "reportGeneralTypeIssues",
25
+ },
26
+ {
27
+ "file": "test2.py",
28
+ "severity": "error",
29
+ "message": "Message bar",
30
+ "range": {
31
+ "start": {"line": 130, "character": 18},
32
+ "end": {"line": 130, "character": 24},
33
+ },
34
+ "rule": "reportInvalidTypeForm",
35
+ },
36
+ ],
37
+ "summary": {
38
+ "filesAnalyzed": 3,
39
+ "errorCount": 2,
40
+ "warningCount": 0,
41
+ "informationCount": 0,
42
+ "timeInSec": 0.200,
43
+ },
44
+ }
45
+ GITLAB = [
46
+ {
47
+ "check_name": "pyright: reportGeneralTypeIssues",
48
+ "description": 'Message "foo"',
49
+ "fingerprint": "636af0d195f1115a2100087f399ea9759e20a6bf30494b881653eb7b",
50
+ "location": {
51
+ "path": "test1.py",
52
+ "positions": {
53
+ "begin": {"column": 27, "line": 101},
54
+ "end": {"column": 35, "line": 101},
55
+ },
56
+ },
57
+ "severity": "major",
58
+ },
59
+ {
60
+ "check_name": "pyright: reportInvalidTypeForm",
61
+ "description": "Message bar",
62
+ "fingerprint": "b0678d27f9d033a7176fcaf13dcfd449a7ec9cff211484ff730b32b2",
63
+ "location": {
64
+ "path": "test2.py",
65
+ "positions": {
66
+ "begin": {"column": 18, "line": 130},
67
+ "end": {"column": 24, "line": 130},
68
+ },
69
+ },
70
+ "severity": "major",
71
+ },
72
+ ]
73
+
74
+
75
+ @pytest.mark.parametrize(
76
+ ("pyright", "gitlab"),
77
+ [
78
+ ({}, []), # Empty input should yield empty output
79
+ (PYRIGHT, GITLAB),
80
+ ],
81
+ )
82
+ def test(
83
+ monkeypatch: pytest.MonkeyPatch,
84
+ capsys: pytest.CaptureFixture,
85
+ pyright: dict,
86
+ gitlab: list[dict],
87
+ ) -> None:
88
+ """Test that the pyright.json is converted to GitLab Code Quality report format."""
89
+ monkeypatch.setattr("sys.stdin", io.StringIO(json.dumps(pyright)))
90
+ monkeypatch.setattr("sys.argv", ["pyright_to_gitlab.py"])
91
+ main()
92
+ captured = capsys.readouterr()
93
+ assert json.loads(captured.out) == gitlab
94
+
95
+
96
+ @pytest.mark.parametrize(
97
+ ("pyright", "gitlab"),
98
+ [
99
+ ({}, []), # Empty input should yield empty output
100
+ (PYRIGHT, GITLAB),
101
+ ],
102
+ )
103
+ def test_prefix(
104
+ monkeypatch: pytest.MonkeyPatch,
105
+ capsys: pytest.CaptureFixture,
106
+ pyright: dict,
107
+ gitlab: list[dict],
108
+ ) -> None:
109
+ """Test that the prefix is added to the file paths in the output."""
110
+ monkeypatch.setattr("sys.stdin", io.StringIO(json.dumps(pyright)))
111
+ monkeypatch.setattr("sys.argv", ["pyright_to_gitlab.py", "--prefix", "prefix/"])
112
+ prefix = "prefix/"
113
+ main()
114
+ captured = capsys.readouterr()
115
+ gitlab_with_prefix = [
116
+ {
117
+ **issue,
118
+ "location": {
119
+ **issue["location"],
120
+ "path": f"{prefix}{issue['location']['path']}",
121
+ },
122
+ }
123
+ for issue in gitlab
124
+ ]
125
+ assert json.loads(captured.out) == gitlab_with_prefix