Skip to content

Commit 437febf

Browse files
samael500dbrgn
authored andcommitted
Add support for multi-color badges (dbrgn#3)
* 🚀 add color ranges for badge * 🔁 color in template * 🔁 gitignore virtualenv * ✅ update test for color ranges * 📝 upd readme * 📝 abs path to badge * 🔁 force overwrite filepath * 📝 upd readme * 🔁 add missing flag in helptext * 🔁 default color const use * 🔁 add plain color mode flag * 📝 upd helptext * ✅ upd test to check correct color outputs * 🔁 upd example images with xml prefix row
1 parent f559654 commit 437febf

File tree

12 files changed

+253
-9
lines changed

12 files changed

+253
-9
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ dist/
66
*.egg-info/
77
.cache/
88
.coverage
9+
venv/

README.rst

+23-2
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,42 @@ either return the badge SVG to stdout::
3636
It's important that you run ``coverage-badge`` from the directory where the
3737
``.coverage`` data file is located.
3838

39+
Different colors for cover ranges:
40+
41+
.. image:: https://cdn.rawgit.com/samael500/coverage-badge/master/media/15.svg
42+
:alt: 15%
43+
44+
.. image:: https://cdn.rawgit.com/samael500/coverage-badge/master/media/45.svg
45+
:alt: 45%
46+
47+
.. image:: https://cdn.rawgit.com/samael500/coverage-badge/master/media/65.svg
48+
:alt: 65%
49+
50+
.. image:: https://cdn.rawgit.com/samael500/coverage-badge/master/media/80.svg
51+
:alt: 80%
52+
53+
.. image:: https://cdn.rawgit.com/samael500/coverage-badge/master/media/93.svg
54+
:alt: 93%
55+
56+
.. image:: https://cdn.rawgit.com/samael500/coverage-badge/master/media/97.svg
57+
:alt: 97%
58+
3959
---
4060

4161
The full usage text::
4262

43-
usage: __main__.py [-h] [-o FILEPATH] [-q] [-v]
63+
usage: __main__.py [-h] [-o FILEPATH] [-p] [-f] [-q] [-v]
4464

4565
Generate coverage badges for Coverage.py.
4666

4767
optional arguments:
4868
-h, --help show this help message and exit
4969
-o FILEPATH Save the file to the specified path.
70+
-p Plain color mode. Standard green badge.
71+
-f Force overwrite image, use with -o key.
5072
-q Don't output any non-error messages.
5173
-v Show version.
5274

53-
5475
License
5576
-------
5677

coverage_badge/__main__.py

+46-6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,27 @@
1717
__version__ = '0.1.2'
1818

1919

20+
DEFAULT_COLOR = '#a4a61d'
21+
COLORS = {
22+
'brightgreen': '#4c1',
23+
'green': '#97CA00',
24+
'yellowgreen': '#a4a61d',
25+
'yellow': '#dfb317',
26+
'orange': '#fe7d37',
27+
'red': '#e05d44',
28+
'lightgrey': '#9f9f9f',
29+
}
30+
31+
COLOR_RANGES = [
32+
(95, 'brightgreen'),
33+
(90, 'green'),
34+
(75, 'yellowgreen'),
35+
(60, 'yellow'),
36+
(40, 'orange'),
37+
(0, 'red'),
38+
]
39+
40+
2041
class Devnull(object):
2142
"""
2243
A file like object that does nothing.
@@ -35,14 +56,27 @@ def get_total():
3556
return '{0:.0f}'.format(total)
3657

3758

38-
def get_badge(total):
59+
def get_color(total):
60+
"""
61+
Return color for current coverage precent
62+
"""
63+
try:
64+
xtotal = int(total)
65+
except ValueError:
66+
return COLORS['lightgrey']
67+
for range_, color in COLOR_RANGES:
68+
if xtotal >= range_:
69+
return COLORS[color]
70+
71+
72+
def get_badge(total, color=DEFAULT_COLOR):
3973
"""
4074
Read the SVG template from the package, update total, return SVG as a
4175
string.
4276
"""
4377
template_path = os.path.join('templates', 'flat.svg')
4478
template = pkg_resources.resource_string(__name__, template_path).decode('utf8')
45-
return template.replace('{{ total }}', total)
79+
return template.replace('{{ total }}', total).replace('{{ color }}', color)
4680

4781

4882
def parse_args(argv=None):
@@ -52,6 +86,10 @@ def parse_args(argv=None):
5286
parser = argparse.ArgumentParser(description=__doc__)
5387
parser.add_argument('-o', dest='filepath',
5488
help='Save the file to the specified path.')
89+
parser.add_argument('-p', dest='plain_color', action='store_true',
90+
help='Plain color mode. Standard green badge.')
91+
parser.add_argument('-f', dest='force', action='store_true',
92+
help='Force overwrite image, use with -o key.')
5593
parser.add_argument('-q', dest='quiet', action='store_true',
5694
help='Don\'t output any non-error messages.')
5795
parser.add_argument('-v', dest='print_version', action='store_true',
@@ -66,7 +104,7 @@ def parse_args(argv=None):
66104
return parser.parse_args()
67105

68106

69-
def save_badge(badge, filepath):
107+
def save_badge(badge, filepath, force=False):
70108
"""
71109
Save badge to the specified path.
72110
"""
@@ -81,7 +119,7 @@ def save_badge(badge, filepath):
81119
path += '.svg'
82120

83121
# Validate path (part 2)
84-
if os.path.exists(path):
122+
if not force and os.path.exists(path):
85123
print('Error: "{}" already exists.'.format(path))
86124
sys.exit(1)
87125

@@ -114,11 +152,13 @@ def main(argv=None):
114152
except coverage.misc.CoverageException as e:
115153
print('Error: {} Did you run coverage first?'.format(e))
116154
sys.exit(1)
117-
badge = get_badge(total)
155+
156+
color = DEFAULT_COLOR if args.plain_color else get_color(total)
157+
badge = get_badge(total, color)
118158

119159
# Show or save output
120160
if args.filepath:
121-
path = save_badge(badge, args.filepath)
161+
path = save_badge(badge, args.filepath, args.force)
122162
if not args.quiet:
123163
print('Saved badge to {}'.format(path))
124164
else:

coverage_badge/templates/flat.svg

+1-1
Loading

media/15.svg

+21
Loading

media/45.svg

+21
Loading

media/65.svg

+21
Loading

media/80.svg

+21
Loading

media/93.svg

+21
Loading

media/97.svg

+21
Loading

media/na.svg

+21
Loading

tests/test_output.py

+35
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import print_function, division, absolute_import, unicode_literals
33

44
import sys
5+
from textwrap import dedent
56

67
import pytest
78

@@ -39,3 +40,37 @@ def test_svg_output(cb, capsys):
3940
assert '<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20">' in out
4041
assert '<text x="80" y="14">79%</text>' in out
4142
assert out.endswith('</svg>\n')
43+
44+
45+
def test_color_ranges(cb, capsys):
46+
"""
47+
Test color total value
48+
"""
49+
for total, color in (('97', '#4c1'), ('93', '#97CA00'), ('80', '#a4a61d'), ('65', '#dfb317'),
50+
('45', '#fe7d37'), ('15', '#e05d44'), ('n/a', '#9f9f9f')):
51+
__main__.get_total = lambda: total
52+
cb.main([])
53+
out, _ = capsys.readouterr()
54+
row = '<path fill="%s" d="M63 0h36v20H63z"/>' % color
55+
assert out.startswith(dedent('''\
56+
<?xml version="1.0" encoding="UTF-8"?>
57+
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20">'''))
58+
assert row in out
59+
assert out.endswith('</svg>\n')
60+
61+
62+
def test_plain_color_mode(cb, capsys):
63+
"""
64+
Should get always one color in badge
65+
"""
66+
assert __main__.DEFAULT_COLOR == '#a4a61d'
67+
for total in ('97', '93', '80', '65', '45', '15', 'n/a'):
68+
__main__.get_total = lambda: total
69+
cb.main(['-p'])
70+
out, _ = capsys.readouterr()
71+
row = '<path fill="#a4a61d" d="M63 0h36v20H63z"/>'
72+
assert out.startswith(dedent('''\
73+
<?xml version="1.0" encoding="UTF-8"?>
74+
<svg xmlns="http://www.w3.org/2000/svg" width="99" height="20">'''))
75+
assert row in out
76+
assert out.endswith('</svg>\n')

0 commit comments

Comments
 (0)