$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: dgregor_at_[hidden]
Date: 2007-12-13 14:20:24
Author: dgregor
Date: 2007-12-13 14:20:23 EST (Thu, 13 Dec 2007)
New Revision: 42013
URL: http://svn.boost.org/trac/boost/changeset/42013
Log:
Send information about broken platforms to platform maintainers and the Boost testing list
Text files modified: 
   trunk/tools/regression/xsl_reports/email_maintainers.py |   207 +++++++++++++++++++++++++++++++++++++++ 
   1 files changed, 205 insertions(+), 2 deletions(-)
Modified: trunk/tools/regression/xsl_reports/email_maintainers.py
==============================================================================
--- trunk/tools/regression/xsl_reports/email_maintainers.py	(original)
+++ trunk/tools/regression/xsl_reports/email_maintainers.py	2007-12-13 14:20:23 EST (Thu, 13 Dec 2007)
@@ -16,6 +16,7 @@
 
 report_author = "Douglas Gregor <dgregor_at_[hidden]>"
 boost_dev_list = "Boost Developer List <boost_at_[hidden]>"
+boost_testing_list = "Boost Testing List <boost-testing_at_[hidden]>"
 
 def sorted_keys( dict ):
     result = dict.keys()
@@ -30,6 +31,7 @@
     def __init__(self, name):
         self.name = name
         self.failures = list()
+        self.maintainers = list()
         return
 
     def addFailure(self, failure):
@@ -39,6 +41,13 @@
     def isBroken(self):
         return len(self.failures) > 300
 
+    def addMaintainer(self, maintainer):
+        """
+        Add a new maintainer for this platform.
+        """
+        self.maintainers.append(maintainer)
+        return
+
 class Failure:
     """
     A single test case failure in the report.
@@ -200,6 +209,67 @@
 
         return message
 
+class PlatformMaintainer:
+    """
+    Information about the platform maintainer of a library
+    """
+    def __init__(self, name, email):
+        self.name = name
+        self.email = email
+        self.platforms = list()
+        return
+
+    def addPlatform(self, runner, platform):
+        self.platforms.append(platform)
+        return
+
+    def composeEmail(self, report):
+        """
+        Composes an e-mail to this platform maintainer if one or more of
+        the platforms s/he maintains has a large number of failures.
+        Returns the e-mail text if a message needs to be sent, or None
+        otherwise.
+        """
+
+        # Determine if we need to send a message to this developer.
+        requires_message = False
+        for platform in self.platforms:
+            if platform.isBroken():
+                requires_message = True
+                break
+
+        if not requires_message:
+            return None
+
+        # Build the message header
+        message = """From: Douglas Gregor <dgregor_at_[hidden]>
+To: """
+        message += self.name + ' <' + self.email + '>'
+        message += """
+Reply-To: boost_at_[hidden]
+Subject: Large number of Boost failures on a platform you maintain as of """
+        message += str(datetime.date.today()) + " [" + report.branch + "]"
+        message += """
+
+You are receiving this report because one or more of the testing
+platforms that you maintain has a large number of Boost failures that
+are not accounted for. A full version of the report is sent to the
+Boost developer's mailing list.
+
+Detailed report:
+"""
+        message += '  ' + report.url + """
+
+The following platforms have a large number of failures:
+"""
+
+        for platform in self.platforms:
+            if platform.isBroken():
+                message += ('  ' + platform.name + ' ('
+                            + str(len(platform.failures))  + ' failures)\n')
+
+        return message
+    
 class Report:
     """
     The complete report of all failing test cases.
@@ -211,6 +281,7 @@
         self.libraries = dict()
         self.platforms = dict()
         self.maintainers = dict()
+        self.platform_maintainers = dict()
         return
 
     def getPlatform(self, name):
@@ -233,6 +304,17 @@
             self.maintainers[name] = Maintainer(name, email)
             return self.maintainers[name]
 
+    def getPlatformMaintainer(self, name, email):
+        """
+        Retrieve the platform maintainer with the given name and
+        e-mail address.
+        """
+        if self.platform_maintainers.has_key(name):
+            return self.platform_maintainers[name]
+        else:
+            self.platform_maintainers[name] = PlatformMaintainer(name, email)
+            return self.platform_maintainers[name]
+
     def parseIssuesEmail(self):
         """
         Try to parse the issues e-mail file. Returns True if everything was
@@ -317,7 +399,7 @@
             time.sleep (30)
 
         return False
-        
+
     # Parses the file $BOOST_ROOT/libs/maintainers.txt to create a hash
     # mapping from the library name to the list of maintainers.
     def parseLibraryMaintainersFile(self):
@@ -329,6 +411,8 @@
         name_email_regex = re.compile('\s*(\w*(\s*\w+)+)\s*<\s*(\S*(\s*\S+)+)\S*>')
         at_regex = re.compile('\s*-\s*at\s*-\s*')
         for line in file('../../../libs/maintainers.txt', 'r'):
+            if line.startswith('#'):
+                continue
             m = lib_maintainer_regex.match (line)
             if m:
                 libname = m.group(1)
@@ -350,6 +434,41 @@
             pass
         pass
 
+    # Parses the file $BOOST_ROOT/libs/platform_maintainers.txt to
+    # create a hash mapping from the platform name to the list of
+    # maintainers.
+    def parsePlatformMaintainersFile(self):
+        """
+        Parse the platform maintainers file in
+        ../../../libs/platform_maintainers.txt to collect information
+        about the maintainers of the various platforms.
+        """
+        platform_maintainer_regex = re.compile('([A-Za-z0-9_.-]*|"[^"]*")\s+(\S+)\s+(.*)')
+        name_email_regex = re.compile('\s*(\w*(\s*\w+)+)\s*<\s*(\S*(\s*\S+)+)\S*>')
+        at_regex = re.compile('\s*-\s*at\s*-\s*')
+        for line in file('../../../libs/platform_maintainers.txt', 'r'):
+            if line.startswith('#'):
+                continue
+            m = platform_maintainer_regex.match (line)
+            if m:
+                platformname = m.group(2)
+                if self.platforms.has_key(platformname):
+                    platform = self.platforms[platformname]
+                    for person in re.split('\s*,\s*', m.group(3)):
+                        nmm = name_email_regex.match(person)
+                        if nmm:
+                            name = nmm.group(1)
+                            email = nmm.group(3)
+                            email = at_regex.sub('@', email)
+                            maintainer = self.getPlatformMaintainer(name, email)
+                            maintainer.addPlatform(m.group(1), platform)
+                            platform.addMaintainer(maintainer)
+                            pass
+                        pass
+                    pass
+                pass
+        pass
+
     def numFailures(self):
         count = 0
         for library in self.libraries:
@@ -374,6 +493,8 @@
 Reply-To: boost_at_[hidden]
 Subject: [Report] """
         message += str(self.numFailures()) + " failures on " + branch
+        if branch != 'trunk':
+            message += ' branch'
         message += " (" + str(datetime.date.today()) + ")"
         message += """
 
@@ -455,6 +576,54 @@
 
         return message
 
+    def composeTestingSummaryEmail(self):
+        """
+        Compose a message to send to the Boost Testing list. Returns
+        the message text if a message is needed, returns None
+        otherwise.
+        """
+        brokenPlatforms = 0
+        for platform in sorted_keys( self.platforms ):
+            if self.platforms[platform].isBroken():
+                brokenPlatforms = brokenPlatforms + 1
+
+        if brokenPlatforms == 0:
+            return None;
+        
+        message = """From: Douglas Gregor <dgregor_at_[hidden]>
+To: boost-testing_at_[hidden]
+Reply-To: boost-testing_at_[hidden]
+Subject: [Report] """
+        message += str(brokenPlatforms) + " potentially broken platforms on " + branch
+        if branch != 'trunk':
+            message += ' branch'
+        message += " (" + str(datetime.date.today()) + ")"
+        message += """
+
+Potentially broken platforms for Boost regression testing
+"""
+        message += "Report time: " + self.date + """
+
+This report lists the high-priority platforms that are exhibiting a
+large number of regresson test failures, which might indicate a problem
+with the test machines or testing harness.
+
+Detailed report:
+"""
+
+        message += '  ' + self.url + '\n'
+
+        message += """
+Platforms with a large number of failures:
+"""
+        for platform in sorted_keys( self.platforms ):
+            if self.platforms[platform].isBroken():
+                message += ('  ' + platform + ' ('
+                            + str(len(self.platforms[platform].failures))
+                            + ' failures)\n')
+
+        return message
+
 # Send a message to "person" (a maintainer of a library that is
 # failing).
 # maintainers is the result of get_library_maintainers()
@@ -599,7 +768,9 @@
 
 # Try to parse maintainers information
 report.parseLibraryMaintainersFile()
+report.parsePlatformMaintainersFile()
 
+# Generate individualized e-mail for library maintainers
 for maintainer_name in report.maintainers:
     maintainer = report.maintainers[maintainer_name]
 
@@ -618,7 +789,27 @@
         if '--debug' in sys.argv:
             print ('Message text for ' + maintainer.name + ':\n')
             print email
-            
+
+# Generate individualized e-mail for platform maintainers
+for maintainer_name in report.platform_maintainers:
+    maintainer = report.platform_maintainers[maintainer_name]
+
+    email = maintainer.composeEmail(report)
+    if email:
+        if '--send' in sys.argv:
+            print ('Sending notification email to ' + maintainer.name + '...')
+            smtp = smtplib.SMTP('milliways.osl.iu.edu')
+            smtp.sendmail(from_addr = report_author, 
+                          to_addrs = maintainer.email,
+                          msg = email)
+            print 'done.\n'
+        else:
+            print 'Would send a notification e-mail to',maintainer.name
+
+        if '--debug' in sys.argv:
+            print ('Message text for ' + maintainer.name + ':\n')
+            print email
+
 email = report.composeSummaryEmail()
 if '--send' in sys.argv:
     print 'Sending summary email to Boost developer list...'
@@ -631,6 +822,18 @@
     print 'Message text for summary:\n'
     print email
 
+email = report.composeTestingSummaryEmail()
+if '--send' in sys.argv:
+    print 'Sending summary email to Boost testing list...'
+    smtp = smtplib.SMTP('milliways.osl.iu.edu')
+    smtp.sendmail(from_addr = report_author, 
+                  to_addrs = boost_testing_list,
+                  msg = email)
+    print 'done.\n'
+if '--debug' in sys.argv:
+    print 'Message text for testing summary:\n'
+    print email
+
 if not ('--send' in sys.argv):
     print 'Chickening out and not sending any e-mail.'
     print 'Use --send to actually send e-mail, --debug to see e-mails.'