Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save quanterium/53a277cab4136963374cf703dfe399bd to your computer and use it in GitHub Desktop.
Save quanterium/53a277cab4136963374cf703dfe399bd to your computer and use it in GitHub Desktop.
Convert pylint output to simplified CodeClimate JSON suitable for Gitlab Code Quality checks
import hashlib
import json
import sys
from typing import TYPE_CHECKING, Optional
from pylint.interfaces import IReporter
from pylint.reporters import JSONReporter
from pylint.lint import Run
from pylint.message import Message
if TYPE_CHECKING:
from pylint.reporters.ureports.nodes import Section
# map pylint categories to CodeClimate severity
PYLINT_CATEGORY_TO_SEVERITY = {
"fatal": "blocker",
"error": "critical",
"warning": "major",
"refactor": "minor",
"convention": "minor",
}
class GitlabCodeClimateReporter(JSONReporter):
"""
Custom pylint reporter to convert pylint messages into a reduced CodeClimate JSON report
suitable for Gitlab's Code Quality. Only reports `description`, `fingerprint`, `severity`,
`location`.
See:
1. https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#implementing-a-custom-tool.
2. https://github.com/PyCQA/pylint/blob/master/pylint/reporters/json_reporter.py
Small portions taken from https://github.com/mercos/codeclimate-pylint where no copyright or
license was asserted as of February 2020
"""
__implements__ = IReporter
name = "gitlabcodeclimate"
def display_messages(self, layout: Optional["Section"]) -> None:
"""Launch layouts display"""
json_dumpable = [
{
"description": msg["description"],
"severity": msg["severity"],
"location": msg["location"],
"fingerprint": msg["fingerprint"]
}
for msg in self.messages
]
print(json.dumps(json_dumpable, indent=4), file=self.out)
def handle_message(self, msg: Message):
"""
Convert a pylint Message into a reduced CodeClimate report dictionary and append to the messages list.
"""
codeclimate_dict = dict()
message_lines = self._parse_message(msg.msg).splitlines()
codeclimate_dict["description"] = message_lines[0]
codeclimate_dict["severity"] = PYLINT_CATEGORY_TO_SEVERITY[msg.category]
# gitlab only uses the "lines.begin" version of location
codeclimate_dict["location"] = {"path": msg.path, "lines": {"begin": msg.line}}
# gitlab needs a fingerprint
# hash the issue, filename and line number
codeclimate_dict["fingerprint"] = hashlib.sha1(
(msg.symbol + msg.path + str(msg.line)).encode()
).hexdigest()
self.messages.append(codeclimate_dict)
def _parse_message(self, msg: str):
""" Helper to cleanup the message string. """
while " " in msg:
msg = msg.replace(" ", " ")
msg = msg.replace('"', "`")
msg = msg.replace("\\", "")
return msg
if __name__ == "__main__":
Run(sys.argv[1:], reporter=GitlabCodeClimateReporter())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment