Commits

Ned Batchelder committed 90014f4

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.

Comments (0)

Files changed (3)

coverage/cmdline.py

         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."
             actions=[],
             branch=None,
             directory=None,
+            fail_under=None,
             help=None,
             ignore_errors=None,
             include=None,
     'html': CmdOptionParser("html",
         [
             Opts.directory,
+            Opts.fail_under,
             Opts.ignore_errors,
             Opts.omit,
             Opts.include,
 
     'report': CmdOptionParser("report",
         [
+            Opts.fail_under,
             Opts.ignore_errors,
             Opts.omit,
             Opts.include,
 
     'xml': CmdOptionParser("xml",
         [
+            Opts.fail_under,
             Opts.ignore_errors,
             Opts.omit,
             Opts.include,
     }
 
 
-OK, ERR = 0, 1
+OK, ERR, FAIL_UNDER = 0, 1, 2
 
 
 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):
 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:

test/test_process.py

                 # 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)