summaryrefslogtreecommitdiff
path: root/tools/regression/xsl_reports/email_maintainers.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/regression/xsl_reports/email_maintainers.py')
-rw-r--r--tools/regression/xsl_reports/email_maintainers.py840
1 files changed, 0 insertions, 840 deletions
diff --git a/tools/regression/xsl_reports/email_maintainers.py b/tools/regression/xsl_reports/email_maintainers.py
deleted file mode 100644
index 308ab688f..000000000
--- a/tools/regression/xsl_reports/email_maintainers.py
+++ /dev/null
@@ -1,840 +0,0 @@
-#
-# Copyright (C) 2005, 2007 The Trustees of Indiana University
-# Author: Douglas Gregor
-#
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
-# http://www.boost.org/LICENSE_1_0.txt)
-#
-import re
-import smtplib
-import os
-import time
-import string
-import datetime
-import sys
-
-report_author = "Douglas Gregor <dgregor@osl.iu.edu>"
-boost_dev_list = "Boost Developer List <boost@lists.boost.org>"
-boost_testing_list = "Boost Testing List <boost-testing@lists.boost.org>"
-
-def sorted_keys( dict ):
- result = dict.keys()
- result.sort()
- return result
-
-
-class Platform:
- """
- All of the failures for a particular platform.
- """
- def __init__(self, name):
- self.name = name
- self.failures = list()
- self.maintainers = list()
- return
-
- def addFailure(self, failure):
- self.failures.append(failure)
- return
-
- 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.
- """
- def __init__(self, test, platform):
- self.test = test
- self.platform = platform
- return
-
-class Test:
- """
- All of the failures for a single test name within a library.
- """
- def __init__(self, library, name):
- self.library = library
- self.name = name
- self.failures = list()
- return
-
- def addFailure(self, failure):
- self.failures.append(failure)
- return
-
- def numFailures(self):
- return len(self.failures)
-
- def numReportableFailures(self):
- """
- Returns the number of failures that we will report to the
- maintainers of the library. This doesn't count failures on
- broken platforms.
- """
- count = 0
- for failure in self.failures:
- if not failure.platform.isBroken():
- count += 1
- pass
- pass
- return count
-
-class Library:
- """
- All of the information about the failures in a single library.
- """
- def __init__(self, name):
- self.name = name
- self.maintainers = list()
- self.tests = list()
- return
-
- def addTest(self, test):
- """
- Add another test to the library.
- """
- self.tests.append(test)
- return
-
- def addMaintainer(self, maintainer):
- """
- Add a new maintainer for this library.
- """
- self.maintainers.append(maintainer)
- return
-
- def numFailures(self):
- count = 0
- for test in self.tests:
- count += test.numFailures()
- pass
- return count
-
- def numReportableFailures(self):
- count = 0
- for test in self.tests:
- count += test.numReportableFailures()
- pass
- return count
-
-class Maintainer:
- """
- Information about the maintainer of a library
- """
- def __init__(self, name, email):
- self.name = name
- self.email = email
- self.libraries = list()
- return
-
- def addLibrary(self, library):
- self.libraries.append(library)
- return
-
- def composeEmail(self, report):
- """
- Composes an e-mail to this maintainer with information about
- the failures in his or her libraries, omitting those that come
- from "broken" platforms. 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 library in self.libraries:
- if library.numReportableFailures() > 0:
- requires_message = True
- break
-
- if not requires_message:
- return None
-
- # Build the message header
- message = """From: Douglas Gregor <dgregor@osl.iu.edu>
-To: """
- message += self.name + ' <' + self.email + '>'
- message += """
-Reply-To: boost@lists.boost.org
-Subject: Failures in your Boost libraries as of """
- message += str(datetime.date.today()) + " [" + report.branch + "]"
- message += """
-
-You are receiving this report because one or more of the libraries you
-maintain has regression test 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 + """
-
-There are failures in these libraries you maintain:
-"""
-
- # List the libraries this maintainer is responsible for and
- # the number of reportable failures in that library.
- for library in self.libraries:
- num_failures = library.numReportableFailures()
- if num_failures > 0:
- message += ' ' + library.name + ' (' + str(num_failures) + ')\n'
- pass
- pass
-
- # Provide the details for the failures in each library.
- for library in self.libraries:
- if library.numReportableFailures() > 0:
- message += '\n|' + library.name + '|\n'
- for test in library.tests:
- if test.numReportableFailures() > 0:
- message += ' ' + test.name + ':'
- for failure in test.failures:
- if not failure.platform.isBroken():
- message += ' ' + failure.platform.name
- pass
- pass
- message += '\n'
- pass
- pass
- pass
- pass
-
- 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@osl.iu.edu>
-To: """
- message += self.name + ' <' + self.email + '>'
- message += """
-Reply-To: boost@lists.boost.org
-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.
- """
- def __init__(self, branch = 'trunk'):
- self.branch = branch
- self.date = None
- self.url = None
- self.libraries = dict()
- self.platforms = dict()
- self.maintainers = dict()
- self.platform_maintainers = dict()
- return
-
- def getPlatform(self, name):
- """
- Retrieve the platform with the given name.
- """
- if self.platforms.has_key(name):
- return self.platforms[name]
- else:
- self.platforms[name] = Platform(name)
- return self.platforms[name]
-
- def getMaintainer(self, name, email):
- """
- Retrieve the maintainer with the given name and e-mail address.
- """
- if self.maintainers.has_key(name):
- return self.maintainers[name]
- else:
- 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
- successful, false otherwise.
- """
- # See if we actually got the file
- if not os.path.isfile('issues-email.txt'):
- return False
-
- # Determine the set of libraries that have unresolved failures
- date_regex = re.compile('Report time: (.*)')
- url_regex = re.compile(' (http://.*)')
- library_regex = re.compile('\|(.*)\|')
- failure_regex = re.compile(' ([^:]*): (.*)')
- current_library = None
- for line in file('issues-email.txt', 'r'):
- # Check for the report time line
- m = date_regex.match(line)
- if m:
- self.date = m.group(1)
- continue
-
- # Check for the detailed report URL
- m = url_regex.match(line)
- if m:
- self.url = m.group(1)
- continue
-
- # Check for a library header
- m = library_regex.match(line)
- if m:
- current_library = Library(m.group(1))
- self.libraries[m.group(1)] = current_library
- continue
-
- # Check for a library test and its failures
- m = failure_regex.match(line)
- if m:
- test = Test(current_library, m.group(1))
- for platform_name in re.split('\s*', m.group(2)):
- if platform_name != '':
- platform = self.getPlatform(platform_name)
- failure = Failure(test, platform)
- test.addFailure(failure)
- platform.addFailure(failure)
- pass
- current_library.addTest(test)
- continue
- pass
-
- return True
-
- def getIssuesEmail(self):
- """
- Retrieve the issues email from beta.boost.org, trying a few
- times in case something wonky is happening. If we can retrieve
- the file, calls parseIssuesEmail and return True; otherwise,
- return False.
- """
- base_url = "http://beta.boost.org/development/tests/"
- base_url += self.branch
- base_url += "/developer/";
- got_issues = False
-
- # Ping the server by looking for an HTML file
- print "Pinging the server to initiate extraction..."
- ping_url = base_url + "issues.html"
- os.system('curl -O ' + ping_url)
- os.system('rm -f issues.html')
-
- for x in range(30):
- # Update issues-email.txt
- url = base_url + "issues-email.txt"
- print 'Retrieving issues email from ' + url
- os.system('rm -f issues-email.txt')
- os.system('curl -O ' + url)
-
- if self.parseIssuesEmail():
- return True
-
- print 'Failed to fetch issues email. '
- 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):
- """
- Parse the maintainers file in ../../../libs/maintainers.txt to
- collect information about the maintainers of broken libraries.
- """
- lib_maintainer_regex = re.compile('(\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/maintainers.txt', 'r'):
- if line.startswith('#'):
- continue
- m = lib_maintainer_regex.match (line)
- if m:
- libname = m.group(1)
- if self.libraries.has_key(m.group(1)):
- library = self.libraries[m.group(1)]
- for person in re.split('\s*,\s*', m.group(2)):
- nmm = name_email_regex.match(person)
- if nmm:
- name = nmm.group(1)
- email = nmm.group(3)
- email = at_regex.sub('@', email)
- maintainer = self.getMaintainer(name, email)
- maintainer.addLibrary(library)
- library.addMaintainer(maintainer)
- pass
- pass
- pass
- pass
- 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:
- count += self.libraries[library].numFailures()
- pass
- return count
-
- def numReportableFailures(self):
- count = 0
- for library in self.libraries:
- count += self.libraries[library].numReportableFailures()
- pass
- return count
-
- def composeSummaryEmail(self):
- """
- Compose a message to send to the Boost developer's
- list. Return the message and return it.
- """
- message = """From: Douglas Gregor <dgregor@osl.iu.edu>
-To: boost@lists.boost.org
-Reply-To: boost@lists.boost.org
-Subject: [Report] """
- message += str(self.numFailures()) + " failures on " + branch
- if branch != 'trunk':
- message += ' branch'
- message += " (" + str(datetime.date.today()) + ")"
- message += """
-
-Boost regression test failures
-"""
- message += "Report time: " + self.date + """
-
-This report lists all regression test failures on high-priority platforms.
-
-Detailed report:
-"""
-
- message += ' ' + self.url + '\n\n'
-
- if self.numFailures() == 0:
- message += "No failures! Yay!\n"
- return message
-
- # List the platforms that are broken
- any_broken_platforms = self.numReportableFailures() < self.numFailures()
- if any_broken_platforms:
- message += """The following platforms have 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')
-
- message += """
-Failures on these "broken" platforms will be omitted from the results below.
-Please see the full report for information about these failures.
-
-"""
-
- # Display the number of failures
- message += (str(self.numReportableFailures()) + ' failures in ' +
- str(len(self.libraries)) + ' libraries')
- if any_broken_platforms:
- message += (' (plus ' + str(self.numFailures() - self.numReportableFailures())
- + ' from broken platforms)')
-
- message += '\n'
-
- # Display the number of failures per library
- for k in sorted_keys( self.libraries ):
- library = self.libraries[k]
- num_failures = library.numFailures()
- message += ' ' + library.name + ' ('
-
- if library.numReportableFailures() > 0:
- message += (str(library.numReportableFailures())
- + " failures")
-
- if library.numReportableFailures() < num_failures:
- if library.numReportableFailures() > 0:
- message += ', plus '
-
- message += (str(num_failures-library.numReportableFailures())
- + ' failures on broken platforms')
- message += ')\n'
- pass
-
- message += '\n'
-
- # Provide the details for the failures in each library.
- for k in sorted_keys( self.libraries ):
- library = self.libraries[k]
- if library.numReportableFailures() > 0:
- message += '\n|' + library.name + '|\n'
- for test in library.tests:
- if test.numReportableFailures() > 0:
- message += ' ' + test.name + ':'
- for failure in test.failures:
- platform = failure.platform
- if not platform.isBroken():
- message += ' ' + platform.name
- message += '\n'
-
- 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@osl.iu.edu>
-To: boost-testing@lists.boost.org
-Reply-To: boost-testing@lists.boost.org
-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 regression 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()
-def send_individualized_message (branch, person, maintainers):
- # There are several states we could be in:
- # 0 Initial state. Eat everything up to the "NNN failures in MMM
- # libraries" line
- # 1 Suppress output within this library
- # 2 Forward output within this library
- state = 0
-
- failures_in_lib_regex = re.compile('\d+ failur.*\d+ librar')
- lib_failures_regex = re.compile(' (\S+) \((\d+)\)')
- lib_start_regex = re.compile('\|(\S+)\|')
- general_pass_regex = re.compile(' http://')
- for line in file('issues-email.txt', 'r'):
- if state == 0:
- lfm = lib_failures_regex.match(line)
- if lfm:
- # Pass the line through if the current person is a
- # maintainer of this library
- if lfm.group(1) in maintainers and person in maintainers[lfm.group(1)]:
- message += line
- print line,
-
- elif failures_in_lib_regex.match(line):
- message += "\nThere are failures in these libraries you maintain:\n"
- elif general_pass_regex.match(line):
- message += line
-
- lib_start = lib_start_regex.match(line)
- if lib_start:
- if state == 0:
- message += '\n'
-
- if lib_start.group(1) in maintainers and person in maintainers[lib_start.group(1)]:
- message += line
- state = 2
- else:
- state = 1
- else:
- if state == 1:
- pass
- elif state == 2:
- message += line
-
- if '--debug' in sys.argv:
- print '-----------------Message text----------------'
- print message
- else:
- print
-
- if '--send' in sys.argv:
- print "Sending..."
- smtp = smtplib.SMTP('milliways.osl.iu.edu')
- smtp.sendmail(from_addr = 'Douglas Gregor <dgregor@osl.iu.edu>',
- to_addrs = person[1],
- msg = message)
- print "Done."
-
-
-# Send a message to the developer's list
-def send_boost_developers_message(branch, maintainers, failing_libraries):
- to_line = 'boost@lists.boost.org'
- from_line = 'Douglas Gregor <dgregor@osl.iu.edu>'
-
- message = """From: Douglas Gregor <dgregor@osl.iu.edu>
-To: boost@lists.boost.org
-Reply-To: boost@lists.boost.org
-Subject: Boost regression testing notification ("""
-
- message += str(datetime.date.today()) + " [" + branch + "]"
- message += ")"
-
- message += """
-
-"""
-
- for line in file('issues-email.txt', 'r'):
- # Right before the detailed report, put out a warning message if
- # any libraries with failures to not have maintainers listed.
- if line.startswith('Detailed report:'):
- missing_maintainers = False
- for lib in failing_libraries:
- if not(lib in maintainers) or maintainers[lib] == list():
- missing_maintainers = True
-
- if missing_maintainers:
- message += """WARNING: The following libraries have failing regression tests but do
-not have a maintainer on file. Once a maintainer is found, add an
-entry to libs/maintainers.txt to eliminate this message.
-"""
-
- for lib in failing_libraries:
- if not(lib in maintainers) or maintainers[lib] == list():
- message += ' ' + lib + '\n'
- message += '\n'
-
- message += line
-
- if '--send' in sys.argv:
- print 'Sending notification email...'
- smtp = smtplib.SMTP('milliways.osl.iu.edu')
- smtp.sendmail(from_addr = from_line, to_addrs = to_line, msg = message)
- print 'Done.'
-
- if '--debug' in sys.argv:
- print "----------Boost developer's message text----------"
- print message
-
-###############################################################################
-# Main program #
-###############################################################################
-
-# Parse command-line options
-branch = "trunk"
-for arg in sys.argv:
- if arg.startswith("--branch="):
- branch = arg[len("--branch="):]
-
-report = Report(branch)
-
-# Try to parse the issues e-mail
-if '--no-get' in sys.argv:
- okay = report.parseIssuesEmail()
-else:
- okay = report.getIssuesEmail()
-
-if not okay:
- print 'Aborting.'
- if '--send' in sys.argv:
- message = """From: Douglas Gregor <dgregor@osl.iu.edu>
- To: Douglas Gregor <dgregor@osl.iu.edu>
- Reply-To: boost@lists.boost.org
- Subject: Regression status script failed on """
- message += str(datetime.date.today()) + " [" + branch + "]"
- smtp = smtplib.SMTP('milliways.osl.iu.edu')
- smtp.sendmail(from_addr = 'Douglas Gregor <dgregor@osl.iu.edu>',
- to_addrs = 'dgregor@osl.iu.edu',
- msg = message)
- sys.exit(1)
-
-# 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]
-
- 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
-
-# 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...'
- smtp = smtplib.SMTP('milliways.osl.iu.edu')
- smtp.sendmail(from_addr = report_author,
- to_addrs = boost_dev_list,
- msg = email)
- print 'done.\n'
-if '--debug' in sys.argv:
- print 'Message text for summary:\n'
- print email
-
-email = report.composeTestingSummaryEmail()
-if email:
- 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.'