diff --git a/CHANGES.md b/CHANGES.md index 8814ae23..d69457ba 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased +* Add phorge-json format. + ## 3.3.2 (2024-05-26) * Improve error message as to why parsing the Cobertura report failed. diff --git a/README.md b/README.md index 2f1b6ccf..45087f54 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ TOTAL;794;264;66.75%; ``` ```shell -$ pycobertura show --format markdown coverage.xml +$ pycobertura show --format markdown coverage.xml | Filename | Stmts | Miss | Cover | Missing | |-----------------------------------|---------|--------|---------|--------------------| | pycobertura/__init__.py | 2 | 0 | 100.00% | | @@ -214,6 +214,19 @@ If you run it in GitHub Actions/Apps, the above log generates check annotations. ![Example output of github-annotation formatted pycobertura show command](images/example_github_annotation_show.png) +The following shows how to generate a JSON in the [Phorge/Phabricator coverage +format](https://we.phorge.it/book/phorge/article/arcanist_coverage/#building-coverage-support). + +```shell +$ pycobertura show --format phorge-json tests/dummy.source1/coverage.xml +{ + "dummy/__init__.py": "", + "dummy/dummy.py": "CCNCUU", + "dummy/dummy2.py": "CC", + "dummy/dummy4.py": "UUNUUU" +} +``` + ### Command `diff` You can also use the `diff` command to show the difference between two coverage diff --git a/pycobertura/cli.py b/pycobertura/cli.py index 83a6ac1b..5ee8543b 100644 --- a/pycobertura/cli.py +++ b/pycobertura/cli.py @@ -9,6 +9,7 @@ MarkdownReporter, JsonReporter, YamlReporter, + PhorgeJsonReporter, HtmlReporterDelta, TextReporterDelta, CsvReporterDelta, @@ -31,6 +32,7 @@ "json": JsonReporter, "yaml": YamlReporter, "github-annotation": GitHubAnnotationReporter, + "phorge-json": PhorgeJsonReporter, } diff --git a/pycobertura/reporters.py b/pycobertura/reporters.py index dc923e99..fa5f739b 100644 --- a/pycobertura/reporters.py +++ b/pycobertura/reporters.py @@ -174,6 +174,28 @@ def generate(self): ) +class PhorgeJsonReporter(Reporter): + """ + A reporter that outputs a JSON object in the Phorge/Phabricator + coverage format. It is required to have the source files available. + """ + + def generate_one(self, filename): + statuses = self.cobertura.line_statuses(filename) + with self.cobertura.filesystem.open(filename) as f: + lines = ["N" for _ in f] + for lineNum, covered in statuses: + lines[lineNum - 1] = "C" if covered else "U" + return "".join(lines) + + def generate(self): + filenames = self.cobertura.files(ignore_regex=self.ignore_regex) + res = {} + for filename in filenames: + res[filename] = self.generate_one(filename) + return json.dumps(res, indent=4) + + class DeltaReporter: def __init__( self, diff --git a/tests/test_reporters.py b/tests/test_reporters.py index 5e164947..4bd20619 100644 --- a/tests/test_reporters.py +++ b/tests/test_reporters.py @@ -810,3 +810,41 @@ def test_delta_reporter__single_file_coverage_changed(): "Cover": "+16.67%" } } + + +def test_phorge_json_reporter(): + from pycobertura.reporters import PhorgeJsonReporter + + cobertura = make_cobertura('tests/dummy.source1/coverage.xml') + report = PhorgeJsonReporter(cobertura) + + assert report.generate() == """\ +{ + "dummy/__init__.py": "", + "dummy/dummy.py": "CCNCUU", + "dummy/dummy2.py": "CC", + "dummy/dummy4.py": "UUNUUU" +}""" + + +def test_phorge_json_reporter__no_source(): + """ + This checks that if a file is not found, the PhorgeJsonReporter + always raises an exception. This is because the phorge-json + format only wants coverage information for each line, and this + does not make sense if a source file is not found. + """ + from pycobertura.reporters import PhorgeJsonReporter + import pycobertura.filesystem + + cobertura = make_cobertura('tests/cobertura.xml') + report = PhorgeJsonReporter(cobertura) + + exception = None + + try: + report.generate() + except pycobertura.filesystem.FileSystem.FileNotFound as e: + exception = e + + assert exception is not None