diff options
author | Mike Crute <mike@crute.us> | 2020-06-03 21:38:28 +0000 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2020-06-03 22:41:23 +0000 |
commit | fceff55ff94d88bd314dbe03ec6727c9e1e40de9 (patch) | |
tree | 38aa6152692d986e40ba8b0ee67201da2261b83c | |
parent | 6031c1f78a3ab0c30fb7c108df28281ca1dbce83 (diff) | |
download | pydora-fceff55ff94d88bd314dbe03ec6727c9e1e40de9.tar.bz2 pydora-fceff55ff94d88bd314dbe03ec6727c9e1e40de9.tar.xz pydora-fceff55ff94d88bd314dbe03ec6727c9e1e40de9.zip |
Enable coverage enforcement
-rw-r--r-- | setup.cfg | 3 | ||||
-rwxr-xr-x | setup.py | 55 |
2 files changed, 51 insertions, 7 deletions
@@ -1,5 +1,2 @@ | |||
1 | [aliases] | 1 | [aliases] |
2 | release = test flake8 | 2 | release = test flake8 |
3 | |||
4 | [coverage:run] | ||
5 | branch = True | ||
@@ -1,11 +1,13 @@ | |||
1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
2 | 2 | ||
3 | import os | 3 | import os |
4 | import math | ||
4 | import shutil | 5 | import shutil |
5 | import subprocess | 6 | import subprocess |
6 | from distutils import log | 7 | from distutils import log |
7 | from distutils.core import Command | 8 | from distutils.core import Command |
8 | from setuptools.command.test import test | 9 | from setuptools.command.test import test |
10 | from distutils.errors import DistutilsError | ||
9 | from setuptools import setup, find_packages | 11 | from setuptools import setup, find_packages |
10 | 12 | ||
11 | 13 | ||
@@ -13,18 +15,63 @@ class TestsWithCoverage(test): | |||
13 | 15 | ||
14 | description = "run unit tests with coverage" | 16 | description = "run unit tests with coverage" |
15 | 17 | ||
18 | coverage_goal = 100 | ||
19 | missed_branches_goal = 0 | ||
20 | partial_branches_goal = 0 | ||
21 | |||
22 | def initialize_options(self): | ||
23 | super().initialize_options() | ||
24 | self.missed_coverage_goals = False | ||
25 | |||
26 | def enforce_coverage_goals(self, rel_path, analysis): | ||
27 | # There is no coverage goal for the player package, just the API | ||
28 | if os.path.split(rel_path)[0] == "pydora": | ||
29 | return | ||
30 | |||
31 | coverage_percent = math.ceil(analysis.numbers.pc_covered) | ||
32 | if coverage_percent != self.coverage_goal: | ||
33 | self.missed_coverage_goals = True | ||
34 | self.announce( | ||
35 | "Coverage: {!r} coverage is {}%, goal is {}%".format( | ||
36 | rel_path, coverage_percent, self.coverage_goal), log.ERROR) | ||
37 | |||
38 | missed_branches = analysis.numbers.n_missing_branches | ||
39 | if missed_branches != self.missed_branches_goal: | ||
40 | self.missed_coverage_goals = True | ||
41 | self.announce( | ||
42 | "Coverage: {!r} missed branch count is {}, goal is {}".format( | ||
43 | rel_path, missed_branches, self.missed_branches_goal), | ||
44 | log.ERROR) | ||
45 | |||
46 | partially_covered_branches = analysis.numbers.n_partial_branches | ||
47 | if partially_covered_branches != self.partial_branches_goal: | ||
48 | self.missed_coverage_goals = True | ||
49 | self.announce( | ||
50 | "Coverage: {!r} partial branch count is {}, goal is {}".format( | ||
51 | rel_path, partially_covered_branches, | ||
52 | self.partial_branches_goal), log.ERROR) | ||
53 | |||
16 | def run(self): | 54 | def run(self): |
17 | from coverage import Coverage | 55 | from coverage import Coverage |
18 | 56 | ||
19 | cov = Coverage(source=self.distribution.packages) | 57 | cov = Coverage(source=self.distribution.packages, branch=True) |
20 | cov.start() | ||
21 | 58 | ||
59 | cov.start() | ||
22 | super().run() | 60 | super().run() |
23 | |||
24 | cov.stop() | 61 | cov.stop() |
25 | cov.xml_report() | 62 | |
63 | # Save HTML report for debugging missed coverage | ||
26 | cov.html_report() | 64 | cov.html_report() |
27 | 65 | ||
66 | # Print coverage report to console for CI log | ||
67 | cov.report() | ||
68 | |||
69 | for rep in cov._get_file_reporters(): | ||
70 | self.enforce_coverage_goals(rep.relname, cov._analyze(rep)) | ||
71 | |||
72 | if self.missed_coverage_goals: | ||
73 | raise DistutilsError("Project missed coverage goals") | ||
74 | |||
28 | 75 | ||
29 | class PyPiReleaseCommand(Command): | 76 | class PyPiReleaseCommand(Command): |
30 | 77 | ||