1+ # Copyright The IETF Trust 2016, All Rights Reserved
12
3+ import os
24import json
35import codecs
46import gzip
1113import debug # pyflakes:ignore
1214
1315class Command (BaseCommand ):
14- help = "Compare coverage between the latest release and the latest test run."
15- args = "[master_json latest_json]"
16+ name , _ = os .path .splitext (os .path .basename (__file__ ))
17+ help = ("Show coverage info for the latest test run. By default, the difference in \n "
18+ "coverage compared with the latest available release data is shown.\n "
19+ "\n "
20+ "Examples:\n "
21+ "\n "
22+ " Show the coverage difference from the previous release:\n "
23+ " $ manage.py {name}\n "
24+ "\n "
25+ " Show the coverage difference with another release:\n "
26+ " $ manage.py {name} --release=6.0.0\n "
27+ "\n "
28+ " Show the coverage difference for a provided data-file:\n "
29+ " $ manage.py {name} release-coverage.json.gz beeblebrox.json\n "
30+ "\n "
31+ " List URLs which are not covered:\n "
32+ " $ manage.py {name} --absolute --sections=url | grep False\n "
33+ "\n "
34+ ).format (** locals ())
35+ args = "[[master_json] latest_json]"
1636 option_list = BaseCommand .option_list + (
1737 make_option ('--sections' , default = 'template,url,code' , dest = 'sections' ,
1838 help = 'Specify which kinds of coverage changes to show. Default: %default' ),
1939 make_option ('--release' , dest = 'release' ,
2040 help = 'Which release to use as baseline. Default is the latest release in '
2141 'the release coverage file.' ),
42+ make_option ('--absolute' , dest = 'absolute' , action = 'store_true' , default = False ,
43+ help = 'Show absolute figures instead of changes from last release.' ),
2244 )
2345
2446 diff_line_format = "%-58s %8s %8s\n "
47+ list_line_format = "%-68s %8s\n "
2548 valid_sections = ['template' , 'url' , 'code' ]
2649
2750 def read_coverage (self , filename , version = None ):
@@ -45,12 +68,7 @@ def read_coverage(self, filename, version=None):
4568 raise CommandError ("There is no data for version %s available in %s" % (version , filename ))
4669 return data [version ], version
4770
48- def coverage_diff (self , master , latest , sections = ',' .join (valid_sections ), release = None , ** options ):
49- sections = sections .split (',' )
50- for section in sections :
51- if not section in self .valid_sections :
52- raise CommandError ("Found an unexpected section name, '%s' in the section list. "
53- "Valid names are %s or any combination of them." % (section , ',' .join (self .valid_sections )))
71+ def coverage_diff (self , master , latest , sections , release = None , ** options ):
5472 master_coverage , mversion = self .read_coverage (master , release )
5573 latest_coverage , lversion = self .read_coverage (latest )
5674 self .stdout .write ("\n Showing coverage differeces between %s and %s:\n " % (mversion , lversion ))
@@ -116,15 +134,68 @@ def coverage_diff(self, master, latest, sections=','.join(valid_sections), relea
116134 self .stdout .write (" %s\n " % key )
117135
118136
137+ def coverage_list (self , latest , sections , ** options ):
138+ latest_coverage , lversion = self .read_coverage (latest )
139+ self .stdout .write ("\n Showing coverage for %s:\n " % (lversion , ))
140+ for section in sections :
141+ lcoverage = latest_coverage [section ]["covered" ]
142+ lformat = latest_coverage [section ].get ("format" , 1 )
143+ #
144+ lkeys = lcoverage .keys ()
145+ #
146+ keys = list (lkeys )
147+ keys .sort ()
148+ header_written = False
149+
150+ for key in keys :
151+ if lformat == 1 :
152+ llines , lcov = None , lcoverage [key ]
153+ elif lformat == 2 :
154+ llines , lcov = lcoverage [key ]
155+ else :
156+ raise CommandError ("The latest coverage data has an unknown format ('%s'), quitting." % lformat )
157+
158+ if type (lcov ) is float :
159+ lval = ("%5.1f %%" % (100 * lcov )) if lcov else "- "
160+ else :
161+ lval = lcov
162+ if not header_written :
163+ self .stdout .write (self .list_line_format %
164+ ("\n %s" % section .capitalize (), lversion [:7 ]))
165+ self .stdout .write (self .list_line_format % ("-" * 58 , "-" * 8 , ))
166+ header_written = True
167+ self .stdout .write (self .list_line_format % (key , lval ))
168+
119169 def handle (self , * filenames , ** options ):
120- if not filenames :
121- filenames = [
122- getattr (settings , 'TEST_COVERAGE_MASTER_FILE' ),
123- getattr (settings , 'TEST_COVERAGE_LATEST_FILE' ),
124- ]
125- # verbosity = int(options.get('verbosity'))
126- if len (filenames ) != 2 :
127- raise CommandError (
128- "Need two and only two files in order to show coverage difference, "
129- "got: %s" % " " .join (filenames ))
130- self .coverage_diff (* filenames , ** options )
170+ sections = options .get ('sections' , ',' .join (self .valid_sections ))
171+ options .pop ('sections' )
172+ sections = sections .split (',' )
173+ for section in sections :
174+ if not section in self .valid_sections :
175+ raise CommandError ("Found an unexpected section name, '%s' in the section list. "
176+ "Valid names are %s or any combination of them." % (section , ',' .join (self .valid_sections )))
177+
178+ absolute = options .get ('absolute' , False )
179+
180+ if absolute :
181+ if not filenames :
182+ filenames = [
183+ getattr (settings , 'TEST_COVERAGE_LATEST_FILE' ),
184+ ]
185+ if len (filenames ) != 1 :
186+ raise CommandError (
187+ "Coverage can be listed only for one json coverage-data file, "
188+ "got: %s" % " " .join (filenames ))
189+ self .coverage_list (filenames [0 ], sections = sections , ** options )
190+ else :
191+ # verbosity = int(options.get('verbosity'))
192+ if not filenames :
193+ filenames = [
194+ getattr (settings , 'TEST_COVERAGE_MASTER_FILE' ),
195+ getattr (settings , 'TEST_COVERAGE_LATEST_FILE' ),
196+ ]
197+ if len (filenames ) != 2 :
198+ raise CommandError (
199+ "Need two and only two files in order to show coverage difference, "
200+ "got: %s" % " " .join (filenames ))
201+ self .coverage_diff (* filenames , sections = sections , ** options )
0 commit comments