Skip to content
This repository was archived by the owner on Feb 19, 2020. It is now read-only.

Add multi-file coverage parsing #24

Merged
merged 2 commits into from
Aug 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 38 additions & 6 deletions src/codacy/reporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@ def strip_prefix(line, prefix):
return filename


def merge_reports(report_list):
"""Merges together several report structures from parse_report_file"""
final_report = {
'language': "python",
'fileReports': []
}

for report in report_list:
# First, merge together detailed report structures
# This assumes no overlap
# TODO: What should we do if there is a file listed multiple times?
final_report['fileReports'] += report['fileReports']

# Gather all per-file coverage
total_coverages = []
for fileentry in final_report['fileReports']:
total_coverages += [fileentry['total']]

# And average
final_report['total'] = sum(total_coverages)/len(total_coverages)

return final_report


def parse_report_file(report_file, git_directory):
"""Parse XML file and POST it to the Codacy API
:param report_file:
Expand Down Expand Up @@ -140,7 +164,9 @@ def upload_report(report, token, commit):

def run():
parser = argparse.ArgumentParser(description='Codacy coverage reporter for Python.')
parser.add_argument("-r", "--report", type=str, help="coverage report file", default=DEFAULT_REPORT_FILE)
parser.add_argument("-r", "--report", help="coverage report file",
default=[DEFAULT_REPORT_FILE], type=str,
action='append')
parser.add_argument("-c", "--commit", type=str, help="git commit hash")
parser.add_argument("-d", "--directory", type=str, help="git top level directory")
parser.add_argument("-v", "--verbose", help="show debug information", action="store_true")
Expand All @@ -157,12 +183,18 @@ def run():
if not args.commit:
args.commit = get_git_revision_hash()

if not os.path.isfile(args.report):
logging.error("Coverage report " + args.report + " not found.")
exit(1)
# Explictly check ALL files before parsing any
for rfile in args.report:
if not os.path.isfile(rfile):
logging.error("Coverage report " + args.report + " not found.")
exit(1)

reports = []
for rfile in args.report:
logging.info("Parsing report file %s...", rfile)
reports.append(parse_report_file(rfile, args.directory))

logging.info("Parsing report file...")
report = parse_report_file(args.report, args.directory)
report = merge_reports(reports)

logging.info("Uploading report...")
upload_report(report, CODACY_PROJECT_TOKEN, args.commit)
31 changes: 31 additions & 0 deletions tests/coverage-merge/cobertura.3.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<coverage line-rate="0.87">
<packages>
<package line-rate="0.87" name="com.github.codacy">
<classes>
<class line-rate="0.87" name="TestSourceFile" filename="src/test/resources/TestSourceFile.scala">
<methods/>
<lines>
<line number="4" hits="1"/>
<line number="5" hits="1"/>
<line number="6" hits="2"/>
</lines>
</class>
<class line-rate="0.87" name="TestSourceFile" filename="src/test/resources/TestSourceFile.scala">
<methods/>
<lines>
<line number="9" hits="1"/>
<line number="10" hits="1"/>
</lines>
</class>
<class line-rate="0.87" name="TestSourceFile2" filename="src/test/resources/TestSourceFile2.scala">
<methods/>
<lines>
<line number="1" hits="1"/>
<line number="2" hits="1"/>
<line number="3" hits="1"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
86 changes: 86 additions & 0 deletions tests/coverage-merge/cobertura.4.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0" ?>
<coverage branch-rate="0" line-rate="0.5" timestamp="1446545132707" version="4.0.1">
<!-- Generated by coverage.py: https://coverage.readthedocs.org -->
<!-- Based on https://raw.githubusercontent.com/cobertura/web/f0366e5e2cf18f111cbd61fc34ef720a6584ba02/htdocs/xml/coverage-03.dtd -->
<sources>
<source>/Users/rafaelcortes/Documents/qamine/python-codacycov</source>
</sources>
<packages>
<package branch-rate="0" complexity="0" line-rate="0.5" name="src.codacy">
<classes>
<class branch-rate="0" complexity="0" filename="src/codacy/__init__.py" line-rate="0.6667" name="__init__.py">
<methods/>
<lines>
<line hits="1" number="1"/>
<line hits="1" number="4"/>
<line hits="0" number="5"/>
</lines>
</class>
<class branch-rate="0" complexity="0" filename="src/codacy/reporter.py" line-rate="0.4915" name="reporter.py">
<methods/>
<lines>
<line hits="1" number="3"/>
<line hits="1" number="4"/>
<line hits="1" number="5"/>
<line hits="1" number="6"/>
<line hits="1" number="7"/>
<line hits="1" number="9"/>
<line hits="1" number="11"/>
<line hits="1" number="14"/>
<line hits="1" number="15"/>
<line hits="1" number="16"/>
<line hits="1" number="17"/>
<line hits="1" number="20"/>
<line hits="0" number="21"/>
<line hits="0" number="23"/>
<line hits="1" number="26"/>
<line hits="1" number="30"/>
<line hits="1" number="31"/>
<line hits="1" number="34"/>
<line hits="1" number="36"/>
<line hits="1" number="42"/>
<line hits="1" number="43"/>
<line hits="1" number="44"/>
<line hits="1" number="49"/>
<line hits="1" number="50"/>
<line hits="1" number="51"/>
<line hits="1" number="52"/>
<line hits="1" number="54"/>
<line hits="1" number="55"/>
<line hits="1" number="57"/>
<line hits="1" number="60"/>
<line hits="0" number="62"/>
<line hits="0" number="63"/>
<line hits="0" number="64"/>
<line hits="0" number="69"/>
<line hits="0" number="71"/>
<line hits="0" number="73"/>
<line hits="0" number="74"/>
<line hits="0" number="76"/>
<line hits="0" number="77"/>
<line hits="1" number="80"/>
<line hits="0" number="81"/>
<line hits="0" number="82"/>
<line hits="0" number="83"/>
<line hits="0" number="84"/>
<line hits="0" number="86"/>
<line hits="0" number="88"/>
<line hits="0" number="89"/>
<line hits="0" number="91"/>
<line hits="0" number="92"/>
<line hits="0" number="93"/>
<line hits="0" number="95"/>
<line hits="0" number="96"/>
<line hits="0" number="98"/>
<line hits="0" number="99"/>
<line hits="0" number="100"/>
<line hits="0" number="102"/>
<line hits="0" number="103"/>
<line hits="0" number="105"/>
<line hits="0" number="106"/>
</lines>
</class>
</classes>
</package>
</packages>
</coverage>
75 changes: 75 additions & 0 deletions tests/coverage-merge/coverage-merge.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"total": 75,
"fileReports": [
{
"total": 87,
"coverage": {
"5": 1,
"4": 1,
"6": 2
},
"filename": "src/test/resources/TestSourceFile.scala"
},
{
"total": 87,
"coverage": {
"9": 1,
"10": 1
},
"filename": "src/test/resources/TestSourceFile.scala"
},
{
"total": 87,
"coverage": {
"1": 1,
"3": 1,
"2": 1
},
"filename": "src/test/resources/TestSourceFile2.scala"
},
{
"total": 66,
"coverage": {
"1": 1,
"4": 1
},
"filename": "src/codacy/__init__.py"
},
{
"total": 49,
"coverage": {
"50": 1,
"60": 1,
"80": 1,
"52": 1,
"26": 1,
"20": 1,
"49": 1,
"44": 1,
"42": 1,
"43": 1,
"3": 1,
"5": 1,
"4": 1,
"7": 1,
"6": 1,
"9": 1,
"11": 1,
"15": 1,
"14": 1,
"17": 1,
"16": 1,
"55": 1,
"54": 1,
"31": 1,
"30": 1,
"51": 1,
"36": 1,
"34": 1,
"57": 1
},
"filename": "src/codacy/reporter.py"
}
],
"language": "python"
}
31 changes: 25 additions & 6 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ def _file_location(*args):

class ReporterTests(unittest.TestCase):

def compare_parse_result(self, generated_filename, expected_filename):
def compare_parse_result(self, generated, expected_filename):
def file_get_contents(filename):
with open(filename) as f:
return f.read()

generated = codacy.reporter.parse_report_file(generated_filename, '')

json_content = file_get_contents(expected_filename)
expected = json.loads(json_content)

Expand All @@ -30,21 +28,42 @@ def file_get_contents(filename):
def test_parser_coverage3(self):
self.maxDiff = None

self.compare_parse_result(_file_location('coverage3', 'cobertura.xml'),
generated = codacy.reporter.parse_report_file(
_file_location('coverage3', 'cobertura.xml'), '')
self.compare_parse_result(generated,
_file_location('coverage3', 'coverage.json'))

def test_parser_coverage4(self):
self.maxDiff = None

self.compare_parse_result(_file_location('coverage4', 'cobertura.xml'),
generated = codacy.reporter.parse_report_file(
_file_location('coverage4', 'cobertura.xml'), '')
self.compare_parse_result(generated,
_file_location('coverage4', 'coverage.json'))

def test_parser_git_filepath(self):
self.maxDiff = None

self.compare_parse_result(_file_location('filepath', 'cobertura.xml.tpl'),
generated = codacy.reporter.parse_report_file(
_file_location('filepath', 'cobertura.xml.tpl'), '')

self.compare_parse_result(generated,
_file_location('filepath', 'coverage.json'))

def test_merge(self):
self.maxDiff = None

generated3 = codacy.reporter.parse_report_file(
_file_location('coverage-merge', 'cobertura.3.xml'), '')
generated4 = codacy.reporter.parse_report_file(
_file_location('coverage-merge', 'cobertura.4.xml'), '')

result = codacy.reporter.merge_reports([generated3, generated4])

self.compare_parse_result(result, _file_location('coverage-merge', 'coverage-merge.json'))




if __name__ == '__main__':
unittest.main()