Mercurial > treepkg
changeset 99:7888fe374e11
Add support for notification mails in case of build errors
This involves a new status field notification_mail to keep track of
whether a notification has been sent for a particular build attempt and
two programs to list the pending notifications and to send the pending
notifications (similar to how the static web pages are published) as
well as the corresponding configuration files.
author | Bernhard Herzog <bh@intevation.de> |
---|---|
date | Tue, 19 Feb 2008 19:19:23 +0000 |
parents | f7b9c7113c46 |
children | aea6b97e7c68 |
files | bin/listpendingnotifications.py bin/sendnotificationmails.py demonotification.cfg notification-template.txt treepkg/packager.py treepkg/status.py |
diffstat | 6 files changed, 175 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/listpendingnotifications.py Tue Feb 19 19:19:23 2008 +0000 @@ -0,0 +1,32 @@ +#! /usr/bin/python2.4 +# Copyright (C) 2008 by Intevation GmbH +# Authors: +# Bernhard Herzog <bh@intevation.de> +# +# This program is free software under the GPL (>=v2) +# Read the file COPYING coming with the software for details. + +"""List tracks and revisions where notifications are pending""" + +import treepkgcmd +from treepkg.options import create_parser +from treepkg.report import get_packager_group + +def parse_commandline(): + return create_parser().parse_args() + +def list_notifications(config_file): + group = get_packager_group(config_file) + for track in group.get_package_tracks(): + for revision in track.get_revisions(): + if revision.status.notification_mail.name == "notification_pending": + print "%s %s %d" % (revision.status.status.name, + track.name, revision.revision) + revision.status.notification_sent() + + +def main(): + options, args = parse_commandline() + list_notifications(options.config_file) + +main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/sendnotificationmails.py Tue Feb 19 19:19:23 2008 +0000 @@ -0,0 +1,75 @@ +#! /usr/bin/python2.4 +# Copyright (C) 2008 by Intevation GmbH +# Authors: +# Bernhard Herzog <bh@intevation.de> +# +# This program is free software under the GPL (>=v2) +# Read the file COPYING coming with the software for details. + +"""Send pending notification mails""" + +import os +import smtplib +import email +import email.Utils +from optparse import OptionParser +from ConfigParser import SafeConfigParser + +import treepkgcmd +from treepkg.readconfig import read_config_section +from treepkg.run import capture_output +from treepkg.cmdexpand import cmdexpand + +notification_desc = ["build_user", "build_host", "build_listpending", + "notification_template", "base_url", + "smtp_host", ("smtp_port", int), + ] + +def read_config(filename): + parser = SafeConfigParser() + parser.read([filename]) + return read_config_section(parser, "notification", notification_desc) + +def parse_commandline(): + parser = OptionParser() + parser.set_defaults(config_file=os.path.join(treepkgcmd.topdir, + "notification.cfg")) + parser.add_option("--config-file", + help=("The configuration file." + " Default notification.cfg")) + return parser.parse_args() + + +def send_mail(config, raw_message): + msg = email.message_from_string(raw_message) + sender = email.Utils.parseaddr(msg["From"])[1] + recipients = [addr[1] for addr + in email.Utils.getaddresses(msg.get_all("To", []) + + msg.get_all("Cc", []))] + server = smtplib.SMTP(config["smtp_host"], config["smtp_port"]) + server.sendmail(sender, recipients, raw_message) + server.quit() + + +def send_notification_mails(config_filename): + config = read_config(config_filename) + + template = open(config["notification_template"]).read() + + lines = capture_output(cmdexpand("ssh $build_user$@$build_host" + " $build_listpending", + **config)) + for line in lines.splitlines(): + words = line.split() + if len(words) == 3: + status, track, revision = words + values = config.copy() + values.update(locals()) + send_mail(config, template % values) + + +def main(): + options, args = parse_commandline() + send_notification_mails(options.config_file) + +main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demonotification.cfg Tue Feb 19 19:19:23 2008 +0000 @@ -0,0 +1,38 @@ +# Demo config file for sendnotificationmails.py. The default config +# file used by sendnotificationmails.py is notification.cfg, so to use +# this file as the basis for your configuration, copy or rename this +# file and adapt it to your needs. + +[notification] + +# Username and host on which the treepackager runs. +# sendnotificationmails.py has to be able to connect to that host as the +# builduser via ssh without knowning the password. This is best +# achieved with the ssh-agent. +build_user: builder +build_host: localhost + +# the program to run on build_host to list the pending notifications +# currently sendnotificationmails.py assumes that the default +# configuration for that program works. +build_listpending: ~/treepkg/bin/listpendingnotifications.py + + +# Template of the notification email. The expanded text is sent as the +# entire email. This means that the file should contain both the +# headers and the body of the email. The recipients of the mail are +# taken from the expanded template's To: and CC: headers. The smtp +# envelope sender is taken from the From: header. +# +# Substitutions have the form %(NAME)s where NAME can be one of these: +# +# track The name of the package track +# +# revision The revision number for which the notification has to be sent +# +# +notification_template: notification_template.txt + +# host/port of the smtp server to use +smtp_host: localhost +smtp_port: 25
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/notification-template.txt Tue Feb 19 19:19:23 2008 +0000 @@ -0,0 +1,16 @@ +From: TreePackager <treepkg@example.com> +To: Project Developemen List <project-devel@example.com> +Subject: TreePackager: error builder %(track)s rev. %(revision)s +MIME-Version: 1.0 +Content-type: text/plain + +Hello, + +an error occurred while building the %(track)s packages for revision +%(revision)s. Details are available in the build log: + + http://example.com/treepkg/%(track)s/%(revision)s/build_log.txt + +General information about the status of the packages is available at + + http://example.com/treepkg/
--- a/treepkg/packager.py Mon Nov 26 15:17:04 2007 +0000 +++ b/treepkg/packager.py Tue Feb 19 19:19:23 2008 +0000 @@ -1,4 +1,4 @@ -# Copyright (C) 2007 by Intevation GmbH +# Copyright (C) 2007, 2008 by Intevation GmbH # Authors: # Bernhard Herzog <bh@intevation.de> # @@ -264,6 +264,12 @@ except: self.status.error() self.status.stop = datetime.datetime.utcnow() + # set the notification status last to avoid race conditions. + # The pending notification is for now the only situation + # where another process might modify the status file (the + # listpendingnotifications program will set it to + # "notification_sent") + self.status.notification_pending() raise def remove_package_dir(self):
--- a/treepkg/status.py Mon Nov 26 15:17:04 2007 +0000 +++ b/treepkg/status.py Tue Feb 19 19:19:23 2008 +0000 @@ -1,4 +1,4 @@ -# Copyright (C) 2007 by Intevation GmbH +# Copyright (C) 2007, 2008 by Intevation GmbH # Authors: # Bernhard Herzog <bh@intevation.de> # @@ -187,3 +187,9 @@ start = DateFieldDesc(default=None) stop = DateFieldDesc(default=None) + + notification_mail = EnumFieldDesc() + notification_mail.add("notification_sent", + "notification mail has been sent", default=True) + notification_mail.add("notification_pending", + "notification mail still needs to be sent")