From c90a777557dff0a1bdadc65797dd4ac37b720f56 Mon Sep 17 00:00:00 2001 From: Erle Carrara Date: Thu, 24 Apr 2025 21:45:48 -0300 Subject: [PATCH] Add support for ReviewDog JSON output format Introduce a new command-line option '--rdjson' to format Cyclomatic Complexity results for ReviewDog. --- radon/cli/__init__.py | 9 ++++++++ radon/cli/harvest.py | 13 +++++++++++ radon/cli/tools.py | 50 +++++++++++++++++++++++++++++++++++++++++ radon/tests/test_cli.py | 1 + 4 files changed, 73 insertions(+) diff --git a/radon/cli/__init__.py b/radon/cli/__init__.py index 3af5138..e5681db 100644 --- a/radon/cli/__init__.py +++ b/radon/cli/__init__.py @@ -110,6 +110,7 @@ def cc( xml=False, md=False, codeclimate=False, + rdjson=False, output_file=_cfg.get_value('output_file', str, None), include_ipynb=_cfg.get_value('include_ipynb', bool, False), ipynb_cells=_cfg.get_value('ipynb_cells', bool, False), @@ -142,6 +143,7 @@ def cc( :param --xml: Format results in XML (compatible with CCM). :param --md: Format results in Markdown. :param --codeclimate: Format results for Code Climate. + :param --rdjson: Format results for ReviewDog. :param --no-assert: Do not count `assert` statements when computing complexity. :param --show-closures: Add closures/inner classes to the output. @@ -171,6 +173,7 @@ def cc( xml=xml, md=md, codeclimate=codeclimate, + rdjson=rdjson, stream=stream, ) @@ -380,6 +383,12 @@ def log_result(harvester, **kwargs): noformat=True, **kwargs ) + elif kwargs.get('rdjson'): + log( + harvester.as_reviewdog_diagnostic_format(), + noformat=True, + **kwargs + ) elif kwargs.get('md'): log(harvester.as_md(), noformat=True, **kwargs) else: diff --git a/radon/cli/harvest.py b/radon/cli/harvest.py index ac14fe5..32fd0c1 100644 --- a/radon/cli/harvest.py +++ b/radon/cli/harvest.py @@ -15,6 +15,7 @@ dict_to_md, iter_filenames, raw_to_dict, + dict_to_reviewdog_diagnostic_format, strip_ipython, ) from radon.complexity import ( @@ -163,6 +164,10 @@ def as_codeclimate_issues(self): '''Format the results as Code Climate issues.''' raise NotImplementedError + def as_reviewdog_diagnostic_format(self): + '''Format the results as ReviewDog Diagnostic Format (RDJSON).''' + raise NotImplementedError + def to_terminal(self): '''Yields tuples representing lines to be printed to a terminal. @@ -216,6 +221,14 @@ def as_codeclimate_issues(self): '''Format the result as Code Climate issues.''' return dict_to_codeclimate_issues(self._to_dicts(), self.config.min) + def as_reviewdog_diagnostic_format(self): + '''Formatthe result as Reviewdog Diagnostic Format + + See https://github.com/reviewdog/reviewdog/tree/master/proto/rdf#rdjson + for more information about the format. + ''''' + return dict_to_reviewdog_diagnostic_format(self._to_dicts(), self.config.min) + def to_terminal(self): '''Yield lines to be printed in a terminal.''' average_cc = 0.0 diff --git a/radon/cli/tools.py b/radon/cli/tools.py index cc8d4fa..c582519 100644 --- a/radon/cli/tools.py +++ b/radon/cli/tools.py @@ -446,6 +446,56 @@ def dict_to_codeclimate_issues(results, threshold='B'): return codeclimate_issues + +def dict_to_reviewdog_diagnostic_format(results, threshold='B'): + diagnostics = [] + + for path in results: + info = results[path] + for offender in info: + beginline = offender['lineno'] + col_offset = offender['col_offset'] + endline = offender['endline'] + complexity = offender['complexity'] + rank = offender['rank'] + description = ( + 'Cyclomatic complexity is too high in {0} {1}. ' + '({2})'.format( + offender['type'], offender['name'], rank + ) + ) + remediation_points = get_remediation_points( + complexity, threshold + ) + + if remediation_points > 0: + diagnostics.append({ + "message": description, + "location": { + "path": path, + "range": { + "start": { + "line": beginline, + "column": col_offset + }, + "end": { + "line": endline, + "column": None + } + } + }, + }) + + return json.dumps({ + "source": { + "name": "radon cc", + "url": "https://radon.readthedocs.io/en/latest/commandline.html#the-cc-command" + }, + "severity": "WARNING", + "diagnostics": diagnostics + }) + + def cc_to_terminal(results, show_complexity, min, max, total_average): '''Transform Cyclomatic Complexity results into a 3-elements tuple: diff --git a/radon/tests/test_cli.py b/radon/tests/test_cli.py index 8b19372..e05fcc4 100644 --- a/radon/tests/test_cli.py +++ b/radon/tests/test_cli.py @@ -112,6 +112,7 @@ def test_cc(mocker, log_mock): log_mock.assert_called_once_with( mocker.sentinel.harvester, codeclimate=False, + rdjson=False, json=True, stream=sys.stdout, xml=False,