summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2012-11-03 22:17:35 -0400
committerNed Batchelder <ned@nedbatchelder.com>2012-11-03 22:17:35 -0400
commit2ed120a530c3563056dba02562fbf9df642d13a6 (patch)
tree46177baa64968af6a3ce10320e1054a1e5e1cbd0
parent82f9dd6e35c811eb53051f70ebf51bea2740f9dd (diff)
downloadpython-coveragepy-2ed120a530c3563056dba02562fbf9df642d13a6.tar.gz
Issue #139: Now the report, html, and xml commands take a --fail-under=MIN switch, and exit with 2 if the coverage is less than MIN.
-rw-r--r--coverage/cmdline.py27
-rw-r--r--doc/cmd.rst5
-rw-r--r--test/test_process.py33
3 files changed, 58 insertions, 7 deletions
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index 1ce5e0f..59ef183 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -20,10 +20,13 @@ class Opts(object):
help="Measure branch coverage in addition to statement coverage."
)
directory = optparse.make_option(
- '-d', '--directory', action='store',
- metavar="DIR",
+ '-d', '--directory', action='store', metavar="DIR",
help="Write the output files to DIR."
)
+ fail_under = optparse.make_option(
+ '', '--fail-under', action='store', metavar="MIN", type="int",
+ help="Exit with a status of 2 if the total coverage is less than MIN."
+ )
help = optparse.make_option(
'-h', '--help', action='store_true',
help="Get help on this command."
@@ -111,6 +114,7 @@ class CoverageOptionParser(optparse.OptionParser, object):
actions=[],
branch=None,
directory=None,
+ fail_under=None,
help=None,
ignore_errors=None,
include=None,
@@ -273,6 +277,7 @@ CMDS = {
'html': CmdOptionParser("html",
[
Opts.directory,
+ Opts.fail_under,
Opts.ignore_errors,
Opts.omit,
Opts.include,
@@ -285,6 +290,7 @@ CMDS = {
'report': CmdOptionParser("report",
[
+ Opts.fail_under,
Opts.ignore_errors,
Opts.omit,
Opts.include,
@@ -314,6 +320,7 @@ CMDS = {
'xml': CmdOptionParser("xml",
[
+ Opts.fail_under,
Opts.ignore_errors,
Opts.omit,
Opts.include,
@@ -327,7 +334,7 @@ CMDS = {
}
-OK, ERR = 0, 1
+OK, ERR, FAIL_UNDER = 0, 1, 2
class CoverageScript(object):
@@ -539,19 +546,25 @@ class CoverageScript(object):
)
if 'report' in options.actions:
- self.coverage.report(
+ total = self.coverage.report(
show_missing=options.show_missing, **report_args)
if 'annotate' in options.actions:
self.coverage.annotate(
directory=options.directory, **report_args)
if 'html' in options.actions:
- self.coverage.html_report(
+ total = self.coverage.html_report(
directory=options.directory, **report_args)
if 'xml' in options.actions:
outfile = options.outfile
- self.coverage.xml_report(outfile=outfile, **report_args)
+ total = self.coverage.xml_report(outfile=outfile, **report_args)
- return OK
+ if options.fail_under is not None:
+ if total >= options.fail_under:
+ return OK
+ else:
+ return FAIL_UNDER
+ else:
+ return OK
def unshell_list(s):
diff --git a/doc/cmd.rst b/doc/cmd.rst
index 4555208..c15857c 100644
--- a/doc/cmd.rst
+++ b/doc/cmd.rst
@@ -204,6 +204,11 @@ encountered trying to find source files to report on. This can be useful if
some files are missing, or if your Python execution is tricky enough that file
names are synthesized without real source files.
+If you provide a ``--fail-under`` value, the total percentage covered will be
+compared to that value. If it is less, the command will exit with a status
+code of 2, indicating that the total coverage was less than your target. This
+can be used as part of a pass/fail condition, for example in a continuous
+integration server. This option isn't available for **annotate**.
.. _cmd_summary:
diff --git a/test/test_process.py b/test/test_process.py
index f8d1b8d..9f8aacc 100644
--- a/test/test_process.py
+++ b/test/test_process.py
@@ -382,3 +382,36 @@ class ProcessTest(CoverageTest):
# imported is 120 or so. Just running os.getenv executes
# about 5.
self.assertGreater(data.summary()['os.py'], 50)
+
+class FailUnderTest(CoverageTest):
+ """Tests of the --fail-under switch."""
+
+ def setUp(self):
+ super(FailUnderTest, self).setUp()
+ self.make_file("fifty.py", """\
+ # I have 50% coverage!
+ a = 1
+ if a > 2:
+ b = 3
+ c = 4
+ """)
+ status, out = self.run_command_status("coverage run fifty.py", 0)
+ self.assertEqual(status, 0)
+
+ def test_report(self):
+ status, out = self.run_command_status("coverage report --fail-under=50", 0)
+ self.assertEqual(status, 0)
+ status, out = self.run_command_status("coverage report --fail-under=51", 2)
+ self.assertEqual(status, 2)
+
+ def test_html_report(self):
+ status, out = self.run_command_status("coverage html --fail-under=50", 0)
+ self.assertEqual(status, 0)
+ status, out = self.run_command_status("coverage html --fail-under=51", 2)
+ self.assertEqual(status, 2)
+
+ def test_xml_report(self):
+ status, out = self.run_command_status("coverage xml --fail-under=50", 0)
+ self.assertEqual(status, 0)
+ status, out = self.run_command_status("coverage xml --fail-under=51", 2)
+ self.assertEqual(status, 2)