@@ -308,6 +308,8 @@ def description(
308308 show_annotations ,
309309 filter_values ,
310310 filter_keys ,
311+ start_date ,
312+ end_date ,
311313 ):
312314 # provide a natural language description of the report options
313315 what = []
@@ -339,9 +341,80 @@ def description(
339341 d += " in manifest keys '%s'" % filter_keys
340342 else :
341343 d += " in any part of manifest entry"
342- d += " as of %s." % datetime .datetime .now ().strftime ("%Y-%m-%d %H:%M" )
344+ d += ", including historical run-time data for the last "
345+
346+ start = datetime .datetime .strptime (start_date , "%Y-%m-%d" )
347+ end = datetime .datetime .strptime (end_date , "%Y-%m-%d" )
348+ d += "%s days on trunk (autoland/m-c)" % ((end - start ).days )
349+ d += " as of %s." % end_date
343350 return d
344351
352+ # TODO: this is hacked for now and very limited
353+ def parse_test (self , summary ):
354+ if summary .endswith ("single tracking bug" ):
355+ name_part = summary .split ("|" )[0 ] # remove 'single tracking bug'
356+ name_part .strip ()
357+ return name_part .split ()[- 1 ] # get just the test name, not extra words
358+ return None
359+
360+ def get_intermittent_failure_data (self , start , end ):
361+ retVal = {}
362+
363+ # get IFV bug list
364+ # i.e. https://th.m.o/api/failures/?startday=2022-06-22&endday=2022-06-29&tree=all
365+ url = (
366+ "https://treeherder.mozilla.org/api/failures/?startday=%s&endday=%s&tree=trunk"
367+ % (start , end )
368+ )
369+ r = requests .get (url , headers = {"User-agent" : "mach-test-info/1.0" })
370+ if_data = r .json ()
371+ buglist = [x ["bug_id" ] for x in if_data ]
372+
373+ # get bug data for summary, 800 bugs at a time
374+ # i.e. https://b.m.o/rest/bug?include_fields=id,product,component,summary&id=1,2,3...
375+ max_bugs = 800
376+ bug_data = []
377+ fields = ["id" , "product" , "component" , "summary" ]
378+ for bug_index in range (0 , len (buglist ), max_bugs ):
379+ bugs = [str (x ) for x in buglist [bug_index :max_bugs ]]
380+ url = "https://bugzilla.mozilla.org/rest/bug?include_fields=%s&id=%s" % (
381+ "," .join (fields ),
382+ "," .join (bugs ),
383+ )
384+ r = requests .get (url , headers = {"User-agent" : "mach-test-info/1.0" })
385+ data = r .json ()
386+ if data and "bugs" in data .keys ():
387+ bug_data .extend (data ["bugs" ])
388+
389+ # for each summary, parse filename, store component
390+ # IF we find >1 bug with same testname, for now summarize as one
391+ for bug in bug_data :
392+ test_name = self .parse_test (bug ["summary" ])
393+ if not test_name :
394+ continue
395+
396+ c = int ([x ["bug_count" ] for x in if_data if x ["bug_id" ] == bug ["id" ]][0 ])
397+ if test_name not in retVal .keys ():
398+ retVal [test_name ] = {
399+ "id" : bug ["id" ],
400+ "count" : 0 ,
401+ "product" : bug ["product" ],
402+ "component" : bug ["component" ],
403+ }
404+ retVal [test_name ]["count" ] += c
405+
406+ if bug ["product" ] != retVal [test_name ]["product" ]:
407+ print (
408+ "ERROR | %s | mismatched bugzilla product, bugzilla (%s) != repo (%s)"
409+ % (bug ["id" ], bug ["product" ], retVal [test_name ]["product" ])
410+ )
411+ if bug ["component" ] != retVal [test_name ]["component" ]:
412+ print (
413+ "ERROR | %s | mismatched bugzilla component, bugzilla (%s) != repo (%s)"
414+ % (bug ["id" ], bug ["component" ], retVal [test_name ]["component" ])
415+ )
416+ return retVal
417+
345418 def report (
346419 self ,
347420 components ,
@@ -356,6 +429,8 @@ def report(
356429 filter_keys ,
357430 show_components ,
358431 output_file ,
432+ start ,
433+ end ,
359434 ):
360435 def matches_filters (test ):
361436 """
@@ -396,6 +471,7 @@ def matches_filters(test):
396471 filter_values = []
397472 display_keys = (filter_keys or []) + ["skip-if" , "fail-if" , "fails-if" ]
398473 display_keys = set (display_keys )
474+ ifd = self .get_intermittent_failure_data (start , end )
399475
400476 print ("Finding tests..." )
401477 here = os .path .abspath (os .path .dirname (__file__ ))
@@ -537,6 +613,12 @@ def matches_filters(test):
537613 failed_count += 1
538614 if t .get ("skip-if" ):
539615 skipped_count += 1
616+
617+ # add in intermittent failure data
618+ if ifd .get (relpath ):
619+ if_data = ifd .get (relpath )
620+ test_info ["failure_count" ] = if_data ["count" ]
621+
540622 if show_tests :
541623 rkey = key if show_components else "all"
542624 if rkey in by_component ["tests" ]:
@@ -566,6 +648,8 @@ def matches_filters(test):
566648 show_annotations ,
567649 filter_values ,
568650 filter_keys ,
651+ start ,
652+ end ,
569653 )
570654
571655 if show_summary :
0 commit comments