launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #03704
[Merge] lp:~stevenk/launchpad/refactor-notification into lp:launchpad
Steve Kowalik has proposed merging lp:~stevenk/launchpad/refactor-notification into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #786852 in Launchpad itself: "Package copies should be able to trigger notifications"
https://bugs.launchpad.net/launchpad/+bug/786852
For more details, see:
https://code.launchpad.net/~stevenk/launchpad/refactor-notification/+merge/61919
Building on the work started in https://code.launchpad.net/~stevenk/launchpad/announcements-copies/+merge/61516, this branch starts on disassociating package upload notifications with the PackageUpload class. The eventual plan is external call sites use the first function (def notification) shown in notification.py -- which is why it is there, and empty, and pass it a SourcePackageRelease, along with other information -- so that other places, most notably package copies can use the same infrastructure.
--
https://code.launchpad.net/~stevenk/launchpad/refactor-notification/+merge/61919
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~stevenk/launchpad/refactor-notification into lp:launchpad.
=== modified file 'lib/lp/archiveuploader/tests/nascentupload-announcements.txt'
--- lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2011-01-26 22:19:55 +0000
+++ lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2011-05-23 06:45:59 +0000
@@ -652,7 +652,7 @@
...
INFO bar (1.0-6) breezy; urgency=low
...
- INFO No announcement sent
+ INFO Announcing to hoary-announce@xxxxxxxxxxxxxxxx
...
INFO You are receiving this email because you are the uploader, maintainer
or
@@ -814,9 +814,6 @@
>>> bar_src.logger = FakeLogger()
>>> result = bar_src.do_accept()
- DEBUG Building recipients list.
- ...
- DEBUG Sending rejection email.
DEBUG Sent a mail:
...
DEBUG Rejected:
=== modified file 'lib/lp/soyuz/adapters/notification.py'
--- lib/lp/soyuz/adapters/notification.py 2011-05-19 09:07:30 +0000
+++ lib/lp/soyuz/adapters/notification.py 2011-05-23 06:45:59 +0000
@@ -12,6 +12,8 @@
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
+import os
+from zope.component import getUtility
from canonical.config import config
from canonical.launchpad.helpers import get_email_template
@@ -22,6 +24,8 @@
from canonical.launchpad.webapp import canonical_url
from lp.archivepublisher.utils import get_ppa_reference
from lp.archiveuploader.changesfile import ChangesFile
+from lp.archiveuploader.utils import safe_fix_maintainer
+from lp.registry.interfaces.person import IPersonSet
from lp.registry.interfaces.pocket import (
PackagePublishingPocket,
pocketsuffix,
@@ -33,13 +37,81 @@
from lp.soyuz.enums import PackageUploadStatus
-def notification(blamer, changesfile, archive, distroseries, pocket, action,
+def notification(blamer, spr, archive, distroseries, pocket, action,
actor=None, reason=None):
pass
-def notify_spr_less(blamer, upload_path, changesfiles, reason):
- pass
+def notify_spr_less(blamer, changes_file_path, changes, reason, logger=None):
+ ignored, filename = os.path.split(changes_file_path)
+ subject = '%s rejected' % filename
+ information = {
+ 'SUMMARY': reason,
+ 'CHANGESFILE': '',
+ 'DATE': '',
+ 'CHANGEDBY': '',
+ 'MAINTAINER': '',
+ 'SIGNER': '',
+ 'ORIGIN': '',
+ }
+ template = get_email_template('upload-rejection.txt')
+ body = template % information
+ from_addr = format_address(
+ config.uploader.default_sender_name,
+ config.uploader.default_sender_address)
+ changedby = changes.get('Changed-By')
+ recipients = ''
+ if changedby is not None:
+ changedby_person = _emailToPerson(changedby)
+ if (
+ changedby_person is not None and
+ changedby_person.preferredemail is not None):
+ recipients = format_address(changedby_person.displayname,
+ changedby_person.preferredemail.email)
+ if recipients == '':
+ recipients = "%s <%s>" % (
+ config.uploader.default_recipient_name,
+ config.uploader.default_recipient_address)
+ extra_headers = {'X-Katie': 'Launchpad actually'}
+ sendMessage(
+ subject, from_addr, recipients, extra_headers, body,
+ attach_changes=False, logger=logger)
+
+
+def get_template(archive, action):
+ """Return the appropriate e-mail template."""
+ template_name = 'upload-'
+ if action in ('new', 'accepted', 'announcement'):
+ template_name += action
+ elif action == 'unapproved':
+ template_name += 'accepted'
+ elif action == 'rejected':
+ template_name += 'rejection'
+ if archive.is_ppa:
+ template_name = 'ppa-%s' % template_name
+ template_name += '.txt'
+ return get_email_template(template_name)
+
+
+def get_status(action):
+ status = {
+ 'new': 'New', 'unapproved': 'Waiting for approval',
+ 'rejected': 'Rejected', 'accepted': 'Accepted',
+ 'announcement': 'Accepted'}
+ return status[action]
+
+
+def calculate_subject(spr, archive, distroseries, pocket, action):
+ """Return the e-mail subject for the notification."""
+ suite = distroseries.name
+ if pocket != PackagePublishingPocket.RELEASE:
+ suite += pocketsuffix[pocket]
+ subject = '[%s/%s] %s %s (%s)' % (
+ distroseries.distribution.name, suite, spr.sourcepackagename.name,
+ spr.version, get_status(action))
+ if archive.is_ppa:
+ subject = '[%s] %s' % (get_ppa_reference(archive), subject)
+ return subject
def notify(packageupload, announce_list=None, summary_text=None,
@@ -47,16 +119,13 @@
allow_unsigned=None):
"""See `IPackageUpload`."""
- packageupload.logger = logger
-
# If this is a binary or mixed upload, we don't send *any* emails
# provided it's not a rejection or a security upload:
- if(packageupload.from_build and
- packageupload.status != PackageUploadStatus.REJECTED and
- packageupload.pocket != PackagePublishingPocket.SECURITY):
- debug(
- packageupload.logger,
- "Not sending email; upload is from a build.")
+ if (
+ packageupload.from_build and
+ packageupload.status != PackageUploadStatus.REJECTED and
+ packageupload.pocket != PackagePublishingPocket.SECURITY):
+ debug(logger, "Not sending email; upload is from a build.")
return
# XXX julian 2007-05-11:
@@ -71,11 +140,21 @@
changes, changes_lines = packageupload._getChangesDict(
changes_file_object, allow_unsigned=allow_unsigned)
+ spr = packageupload.sourcepackagerelease
+
+ if spr == None:
+ # The sourcepackagerelease object that PackageUpload has fed us is
+ # fake.
+ notify_spr_less(
+ None, changes_file_object.name, changes, summary_text,
+ logger=logger)
+ return
+
# "files" will contain a list of tuples of filename,component,section.
# If files is empty, we don't need to send an email if this is not
# a rejection.
try:
- files = _buildUploadedFilesList(packageupload)
+ files = _buildUploadedFilesList(spr, logger)
except LanguagePackEncountered:
# Don't send emails for language packs.
return
@@ -83,17 +162,17 @@
if not files and packageupload.status != PackageUploadStatus.REJECTED:
return
- summary = _buildSummary(packageupload, files)
+ summary = _buildSummary(spr, files)
if summary_text:
summary.append(summary_text)
summarystring = "\n".join(summary)
- recipients = _getRecipients(packageupload, changes)
+ recipients = _getRecipients(packageupload, changes, logger)
# There can be no recipients if none of the emails are registered
# in LP.
if not recipients:
- debug(packageupload.logger, "No recipients on email, not sending.")
+ debug(logger, "No recipients on email, not sending.")
return
# Make the content of the actual changes file available to the
@@ -107,156 +186,114 @@
if packageupload.status == PackageUploadStatus.REJECTED:
_sendRejectionNotification(
packageupload, recipients, changes_lines, changes, summary_text,
- dry_run, changesfile_content)
+ dry_run, changesfile_content, logger)
return
_sendSuccessNotification(
packageupload, recipients, announce_list, changes_lines, changes,
- summarystring, dry_run, changesfile_content)
+ summarystring, dry_run, changesfile_content, logger)
+
+
+def getFieldFromChanges(changes, field):
+ if changes.get(field):
+ return guess_encoding(changes.get(field))
+ else:
+ return ''
+
+
+def assembleBody(spr, archive, distroseries, summary, changes, action):
+ information = {
+ 'STATUS': get_status(action),
+ 'SUMMARY': summary,
+ 'DATE': 'Date: %s' % changes['Date'],
+ 'CHANGESFILE': ChangesFile.formatChangesComment(
+ getFieldFromChanges(changes, 'Changes')),
+ 'DISTRO': distroseries.distribution.title,
+ 'ANNOUNCE': 'No announcement sent',
+ 'CHANGEDBY': '\nChanged-By: %s' % (
+ getFieldFromChanges(changes, 'Changed-By')),
+ 'ORIGIN': '',
+ 'SIGNER': '',
+ 'SPR_URL': canonical_url(spr),
+ 'USERS_ADDRESS': config.launchpad.users_address,
+ }
+ origin = getFieldFromChanges(changes, 'Origin')
+ if origin:
+ information['ORIGIN'] = '\nOrigin: %s' % origin
+ if action == 'unapproved':
+ information['SUMMARY'] += (
+ "\nThis upload awaits approval by a distro manager\n")
+ if distroseries.changeslist:
+ information['ANNOUNCE'] = "Announcing to %s" % (
+ distroseries.changeslist)
+ if spr.package_upload.signing_key is not None:
+ signer = spr.package_upload.signing_key.owner
+ signer_signature = '%s <%s>' % (
+ signer.displayname, signer.preferredemail.email)
+ if signer_signature != information['CHANGEDBY']:
+ information['SIGNER'] = '\nSigned-By: %s' % signer_signature
+ # Add maintainer if present and different from changed-by.
+ maintainer = getFieldFromChanges(changes, 'Maintainer')
+ if maintainer != information['CHANGEDBY']:
+ information['MAINTAINER'] = '\nMaintainer: %s' % maintainer
+ return get_template(archive, action) % information
+
+
+def sendMail(packageupload, summary_text, changes, recipients, dry_run,
+ action, changesfile_content=None, from_addr=None, bcc=None,
+ announce_list=None, logger=None):
+ spr = packageupload.sourcepackagerelease
+ archive = packageupload.archive
+ distroseries = packageupload.distroseries
+ pocket = packageupload.pocket
+ attach_changes = not archive.is_ppa
+
+ subject = calculate_subject(spr, archive, distroseries, pocket, action)
+ body = assembleBody(
+ spr, archive, distroseries, summary_text, changes, action)
+
+ _sendMail(
+ packageupload, archive, recipients, subject, body, dry_run,
+ changesfile_content=changesfile_content,
+ attach_changes=attach_changes, from_addr=from_addr, bcc=bcc,
+ logger=logger)
def _sendSuccessNotification(
packageupload, recipients, announce_list, changes_lines, changes,
- summarystring, dry_run, changesfile_content):
+ summarystring, dry_run, changesfile_content, logger):
"""Send a success email."""
- def do_sendmail(message, recipients=recipients, from_addr=None,
- bcc=None):
- """Perform substitutions on a template and send the email."""
- _handleCommonBodyContent(packageupload, message, changes)
- body = message.template % message.__dict__
-
- # Weed out duplicate name entries.
- names = ', '.join(set(packageupload.displayname.split(', ')))
-
- # Construct the suite name according to Launchpad/Soyuz
- # convention.
- pocket_suffix = pocketsuffix[packageupload.pocket]
- if pocket_suffix:
- suite = '%s%s' % (packageupload.distroseries.name, pocket_suffix)
- else:
- suite = packageupload.distroseries.name
-
- subject = '[%s/%s] %s %s (%s)' % (
- packageupload.distroseries.distribution.name, suite, names,
- packageupload.displayversion, message.STATUS)
-
- if packageupload.isPPA():
- subject = "[PPA %s] %s" % (
- get_ppa_reference(packageupload.archive), subject)
- attach_changes = False
- else:
- attach_changes = True
-
- _sendMail(
- packageupload, recipients, subject, body, dry_run,
- from_addr=from_addr, bcc=bcc,
- changesfile_content=changesfile_content,
- attach_changes=attach_changes)
-
- class NewMessage:
- """New message."""
- template = get_email_template('upload-new.txt')
-
- STATUS = "New"
- SUMMARY = summarystring
- CHANGESFILE = sanitize_string(
- ChangesFile.formatChangesComment(changes['Changes']))
- DISTRO = packageupload.distroseries.distribution.title
- if announce_list:
- ANNOUNCE = 'Announcing to %s' % announce_list
- else:
- ANNOUNCE = 'No announcement sent'
-
- class UnapprovedMessage:
- """Unapproved message."""
- template = get_email_template('upload-accepted.txt')
-
- STATUS = "Waiting for approval"
- SUMMARY = summarystring + (
- "\nThis upload awaits approval by a distro manager\n")
- CHANGESFILE = sanitize_string(
- ChangesFile.formatChangesComment(changes['Changes']))
- DISTRO = packageupload.distroseries.distribution.title
- if announce_list:
- ANNOUNCE = 'Announcing to %s' % announce_list
- else:
- ANNOUNCE = 'No announcement sent'
- CHANGEDBY = ''
- ORIGIN = ''
- SIGNER = ''
- MAINTAINER = ''
- SPR_URL = ''
-
- class AcceptedMessage:
- """Accepted message."""
- template = get_email_template('upload-accepted.txt')
-
- STATUS = "Accepted"
- SUMMARY = summarystring
- CHANGESFILE = sanitize_string(
- ChangesFile.formatChangesComment(changes['Changes']))
- DISTRO = packageupload.distroseries.distribution.title
- if announce_list:
- ANNOUNCE = 'Announcing to %s' % announce_list
- else:
- ANNOUNCE = 'No announcement sent'
- CHANGEDBY = ''
- ORIGIN = ''
- SIGNER = ''
- MAINTAINER = ''
- SPR_URL = ''
-
- class PPAAcceptedMessage:
- """PPA accepted message."""
- template = get_email_template('ppa-upload-accepted.txt')
-
- STATUS = "Accepted"
- SUMMARY = summarystring
- CHANGESFILE = guess_encoding(
- ChangesFile.formatChangesComment("".join(changes_lines)))
-
- class AnnouncementMessage:
- template = get_email_template('upload-announcement.txt')
-
- STATUS = "Accepted"
- SUMMARY = summarystring
- CHANGESFILE = sanitize_string(
- ChangesFile.formatChangesComment(changes['Changes']))
- CHANGEDBY = ''
- ORIGIN = ''
- SIGNER = ''
- MAINTAINER = ''
- SPR_URL = ''
-
- # The template is ready. The remainder of this function deals with
- # whether to send a 'new' message, an acceptance message and/or an
- # announcement message.
-
if packageupload.status == PackageUploadStatus.NEW:
# This is an unknown upload.
- do_sendmail(NewMessage)
+ sendMail(packageupload, summarystring, changes, recipients, dry_run,
+ 'new', changesfile_content=changesfile_content, logger=logger)
return
# Unapproved uploads coming from an insecure policy only send
# an acceptance message.
if packageupload.status == PackageUploadStatus.UNAPPROVED:
# Only send an acceptance message.
- do_sendmail(UnapprovedMessage)
+ sendMail(packageupload, summarystring, changes, recipients, dry_run,
+ 'unapproved', changesfile_content=changesfile_content,
+ logger=logger)
return
if packageupload.isPPA():
# PPA uploads receive an acceptance message.
- do_sendmail(PPAAcceptedMessage)
+ sendMail(packageupload, summarystring, changes, recipients, dry_run,
+ 'accepted', changesfile_content=changesfile_content,
+ logger=logger)
return
# Auto-approved uploads to backports skips the announcement,
# they are usually processed with the sync policy.
if packageupload.pocket == PackagePublishingPocket.BACKPORTS:
- debug(
- packageupload.logger, "Skipping announcement, it is a BACKPORT.")
+ debug(logger, "Skipping announcement, it is a BACKPORT.")
- do_sendmail(AcceptedMessage)
+ sendMail(packageupload, summarystring, changes, recipients, dry_run,
+ 'accepted', changesfile_content=changesfile_content,
+ logger=logger)
return
# Auto-approved binary-only uploads to security skip the
@@ -264,14 +301,18 @@
if (packageupload.pocket == PackagePublishingPocket.SECURITY
and not packageupload.contains_source):
# We only send announcements if there is any source in the upload.
- debug(packageupload.logger,
+ debug(
+ logger,
"Skipping announcement, it is a binary upload to SECURITY.")
- do_sendmail(AcceptedMessage)
+ sendMail(packageupload, summarystring, changes, recipients, dry_run,
+ 'accepted', changesfile_content=changesfile_content,
+ logger=logger)
return
# Fallback, all the rest coming from insecure, secure and sync
# policies should send an acceptance and an announcement message.
- do_sendmail(AcceptedMessage)
+ sendMail(packageupload, summarystring, changes, recipients, dry_run,
+ 'accepted', changesfile_content=changesfile_content, logger=logger)
# Don't send announcements for Debian auto sync uploads.
if packageupload.isAutoSyncUpload(changed_by_email=changes['Changed-By']):
@@ -283,74 +324,33 @@
else:
from_addr = guess_encoding(changes['Changed-By'])
- do_sendmail(
- AnnouncementMessage,
- recipients=[str(announce_list)],
+ sendMail(packageupload, summarystring, changes, [str(announce_list)],
+ dry_run, 'announcement', changesfile_content=changesfile_content,
from_addr=from_addr,
- bcc="%s_derivatives@xxxxxxxxxxxxxxxxxxxxxx" %
- packageupload.displayname)
+ bcc="%s_derivatives@xxxxxxxxxxxxxxxxxxxxxx" % (
+ packageupload.displayname), logger=logger)
def _sendRejectionNotification(
packageupload, recipients, changes_lines, changes, summary_text, dry_run,
- changesfile_content):
+ changesfile_content, logger):
"""Send a rejection email."""
- class PPARejectedMessage:
- """PPA rejected message."""
- template = get_email_template('ppa-upload-rejection.txt')
- SUMMARY = sanitize_string(summary_text)
- CHANGESFILE = sanitize_string(
- ChangesFile.formatChangesComment("".join(changes_lines)))
- USERS_ADDRESS = config.launchpad.users_address
-
- class RejectedMessage:
- """Rejected message."""
- template = get_email_template('upload-rejection.txt')
- SUMMARY = sanitize_string(summary_text)
- CHANGESFILE = sanitize_string(
- ChangesFile.formatChangesComment(changes['Changes']))
- CHANGEDBY = ''
- ORIGIN = ''
- SIGNER = ''
- MAINTAINER = ''
- SPR_URL = ''
- USERS_ADDRESS = config.launchpad.users_address,
-
default_recipient = "%s <%s>" % (
config.uploader.default_recipient_name,
config.uploader.default_recipient_address)
if not recipients:
recipients = [default_recipient]
- debug(packageupload.logger, "Sending rejection email.")
- if packageupload.isPPA():
- message = PPARejectedMessage
- attach_changes = False
- else:
- message = RejectedMessage
- attach_changes = True
-
- _handleCommonBodyContent(packageupload, message, changes)
- if summary_text is None:
- message.SUMMARY = 'Rejected by archive administrator.'
-
- body = message.template % message.__dict__
-
- subject = "%s rejected" % packageupload.changesfile.filename
- if packageupload.isPPA():
- subject = "[PPA %s] %s" % (
- get_ppa_reference(packageupload.archive), subject)
-
- _sendMail(
- packageupload, recipients, subject, body, dry_run,
- changesfile_content=changesfile_content,
- attach_changes=attach_changes)
+ debug(logger, "Sending rejection email.")
+ sendMail(packageupload, summary_text, changes, recipients, dry_run,
+ 'rejected', changesfile_content=changesfile_content, logger=logger)
def _sendMail(
- packageupload, to_addrs, subject, mail_text, dry_run, from_addr=None,
- bcc=None, changesfile_content=None, attach_changes=False):
+ packageupload, archive, to_addrs, subject, mail_text, dry_run,
+ from_addr=None, bcc=None, changesfile_content=None,
+ attach_changes=False, logger=None):
"""Send an email to to_addrs with the given text and subject.
:to_addrs: A list of email addresses to be used as recipients. Each
@@ -370,28 +370,18 @@
"""
extra_headers = {'X-Katie': 'Launchpad actually'}
- # XXX cprov 20071212: ideally we only need to check archive.purpose,
- # however the current code in uploadprocessor.py (around line 259)
- # temporarily transforms the primary-archive into a PPA one (w/o
- # setting a proper owner) in order to allow processing of a upload
- # to unknown PPA and subsequent rejection notification.
-
# Include the 'X-Launchpad-PPA' header for PPA upload notfications
# containing the PPA owner name.
- if (
- packageupload.archive.is_ppa and
- packageupload.archive.owner is not None):
- extra_headers['X-Launchpad-PPA'] = get_ppa_reference(
- packageupload.archive)
+ if archive.is_ppa:
+ extra_headers['X-Launchpad-PPA'] = get_ppa_reference(archive)
# Include a 'X-Launchpad-Component' header with the component and
# the section of the source package uploaded in order to facilitate
# filtering on the part of the email recipients.
- if packageupload.sources:
- spr = packageupload.my_source_package_release
- xlp_component_header = 'component=%s, section=%s' % (
- spr.component.name, spr.section.name)
- extra_headers['X-Launchpad-Component'] = xlp_component_header
+ spr = packageupload.sourcepackagerelease
+ xlp_component_header = 'component=%s, section=%s' % (
+ spr.component.name, spr.section.name)
+ extra_headers['X-Launchpad-Component'] = xlp_component_header
if from_addr is None:
from_addr = format_address(
@@ -417,22 +407,31 @@
else:
from_addr.encode('ascii')
- if dry_run and packageupload.logger is not None:
- packageupload.logger.info("Would have sent a mail:")
- packageupload.logger.info(" Subject: %s" % subject)
- packageupload.logger.info(" Sender: %s" % from_addr)
- packageupload.logger.info(" Recipients: %s" % recipients)
- packageupload.logger.info(" Bcc: %s" % extra_headers['Bcc'])
- packageupload.logger.info(" Body:")
+ sendMessage(
+ subject, from_addr, recipients, extra_headers, mail_text,
+ dry_run=dry_run, attach_changes=attach_changes,
+ changesfile_content=changesfile_content, logger=logger)
+
+
+def sendMessage(subject, from_addr, recipients, extra_headers, mail_text,
+ dry_run=None, attach_changes=None, changesfile_content=None,
+ logger=None):
+ if dry_run and logger is not None:
+ logger.info("Would have sent a mail:")
+ logger.info(" Subject: %s" % subject)
+ logger.info(" Sender: %s" % from_addr)
+ logger.info(" Recipients: %s" % recipients)
+ logger.info(" Bcc: %s" % extra_headers['Bcc'])
+ logger.info(" Body:")
for line in mail_text.splitlines():
- packageupload.logger.info(line)
+ logger.info(line)
else:
- debug(packageupload.logger, "Sent a mail:")
- debug(packageupload.logger, " Subject: %s" % subject)
- debug(packageupload.logger, " Recipients: %s" % recipients)
- debug(packageupload.logger, " Body:")
+ debug(logger, "Sent a mail:")
+ debug(logger, " Subject: %s" % subject)
+ debug(logger, " Recipients: %s" % recipients)
+ debug(logger, " Body:")
for line in mail_text.splitlines():
- debug(packageupload.logger, line)
+ debug(logger, line)
# Since we need to send the original changesfile as an
# attachment the sendmail() method will be used as opposed to
@@ -447,13 +446,12 @@
message.add_header(key, value)
# Add the email body.
- message.attach(MIMEText(
- sanitize_string(mail_text).encode('utf-8'), 'plain', 'utf-8'))
+ message.attach(MIMEText(mail_text.encode('utf-8'), 'plain', 'utf-8'))
if attach_changes:
# Add the original changesfile as an attachment.
if changesfile_content is not None:
- changesfile_text = sanitize_string(changesfile_content)
+ changesfile_text = guess_encoding(changesfile_content)
else:
changesfile_text = ("Sorry, changesfile not available.")
@@ -468,88 +466,24 @@
sendmail(message)
-def _handleCommonBodyContent(packageupload, message, changes):
- """Put together pieces of the body common to all emails.
-
- Sets the date, changed-by, maintainer, signer and origin properties on
- the message as appropriate.
-
- :message: An object containing the various pieces of the notification
- email.
- :changes: A dictionary with the changes file content.
- """
- # Add the date field.
- message.DATE = 'Date: %s' % changes['Date']
-
- # Add the debian 'Changed-By:' field.
- changed_by = changes.get('Changed-By')
- if changed_by is not None:
- changed_by = sanitize_string(changed_by)
- message.CHANGEDBY = '\nChanged-By: %s' % changed_by
-
- # Add maintainer if present and different from changed-by.
- maintainer = changes.get('Maintainer')
- if maintainer is not None:
- maintainer = sanitize_string(maintainer)
- if maintainer != changed_by:
- message.MAINTAINER = '\nMaintainer: %s' % maintainer
-
- # Add a 'Signed-By:' line if this is a signed upload and the
- # signer/sponsor differs from the changed-by.
- if packageupload.signing_key is not None:
- # This is a signed upload.
- signer = packageupload.signing_key.owner
-
- signer_name = sanitize_string(signer.displayname)
- signer_email = sanitize_string(signer.preferredemail.email)
-
- signer_signature = '%s <%s>' % (signer_name, signer_email)
-
- if changed_by != signer_signature:
- message.SIGNER = '\nSigned-By: %s' % signer_signature
-
- # Add the debian 'Origin:' field if present.
- if changes.get('Origin') is not None:
- message.ORIGIN = '\nOrigin: %s' % changes['Origin']
-
- if packageupload.sources or packageupload.builds:
- message.SPR_URL = canonical_url(
- packageupload.my_source_package_release)
-
-
-def sanitize_string(s):
- """Make sure string does not trigger 'ascii' codec errors.
-
- Convert string to unicode if needed so that characters outside
- the (7-bit) ASCII range do not cause errors like these:
-
- 'ascii' codec can't decode byte 0xc4 in position 21: ordinal
- not in range(128)
- """
- if isinstance(s, unicode):
- return s
- else:
- return guess_encoding(s)
-
-
def debug(logger, msg):
"""Shorthand debug notation for publish() methods."""
if logger is not None:
logger.debug(msg)
-def _getRecipients(packageupload, changes):
+def _getRecipients(packageupload, changes, logger):
"""Return a list of recipients for notification emails."""
candidate_recipients = []
- debug(packageupload.logger, "Building recipients list.")
- changer = packageupload._emailToPerson(changes['Changed-By'])
+ debug(logger, "Building recipients list.")
+ changer = _emailToPerson(changes['Changed-By'])
if packageupload.signing_key:
# This is a signed upload.
signer = packageupload.signing_key.owner
candidate_recipients.append(signer)
else:
- debug(packageupload.logger,
+ debug(logger,
"Changes file is unsigned, adding changer as recipient")
candidate_recipients.append(changer)
@@ -564,16 +498,16 @@
# If this is not a PPA, we also consider maintainer and changed-by.
if packageupload.signing_key and not packageupload.isPPA():
- maintainer = packageupload._emailToPerson(changes['Maintainer'])
+ maintainer = _emailToPerson(changes['Maintainer'])
if (maintainer and maintainer != signer and
maintainer.isUploader(
packageupload.distroseries.distribution)):
- debug(packageupload.logger, "Adding maintainer to recipients")
+ debug(logger, "Adding maintainer to recipients")
candidate_recipients.append(maintainer)
if (changer and changer != signer and
changer.isUploader(packageupload.distroseries.distribution)):
- debug(packageupload.logger, "Adding changed-by to recipients")
+ debug(logger, "Adding changed-by to recipients")
candidate_recipients.append(changer)
# Now filter list of recipients for persons only registered in
@@ -584,13 +518,13 @@
continue
recipient = format_address(person.displayname,
person.preferredemail.email)
- debug(packageupload.logger, "Adding recipient: '%s'" % recipient)
+ debug(logger, "Adding recipient: '%s'" % recipient)
recipients.append(recipient)
return recipients
-def _buildUploadedFilesList(packageupload):
+def _buildUploadedFilesList(spr, logger):
"""Return a list of tuples of (filename, component, section).
Component and section are only set where the file is a source upload.
@@ -599,39 +533,24 @@
No emails should be sent for language packs.
"""
files = []
- if packageupload.contains_source:
- [source] = packageupload.sources
- spr = source.sourcepackagerelease
- # Bail out early if this is an upload for the translations
- # section.
- if spr.section.name == 'translations':
- debug(packageupload.logger,
- "Skipping acceptance and announcement, it is a "
- "language-package upload.")
- raise LanguagePackEncountered
- for sprfile in spr.files:
- files.append(
- (sprfile.libraryfile.filename, spr.component.name,
- spr.section.name))
-
- # Component and section don't get set for builds and custom, since
- # this information is only used in the summary string for source
- # uploads.
- for build in packageupload.builds:
- for bpr in build.build.binarypackages:
- files.extend([
- (bpf.libraryfile.filename, '', '') for bpf in bpr.files])
-
- if packageupload.customfiles:
- files.extend(
- [(file.libraryfilealias.filename, '', '')
- for file in packageupload.customfiles])
+ # Bail out early if this is an upload for the translations
+ # section.
+ if spr.section.name == 'translations':
+ debug(logger,
+ "Skipping acceptance and announcement, it is a "
+ "language-package upload.")
+ raise LanguagePackEncountered
+ for sprfile in spr.files:
+ files.append(
+ (sprfile.libraryfile.filename, spr.component.name,
+ spr.section.name))
return files
-def _buildSummary(packageupload, files):
+def _buildSummary(spr, files):
"""Build a summary string based on the files present in the upload."""
+ packageupload = spr.package_upload
summary = []
for filename, component, section in files:
if packageupload.status == PackageUploadStatus.NEW:
@@ -644,5 +563,14 @@
return summary
+def _emailToPerson(fullemail):
+ """Return an IPerson given an RFC2047 email address."""
+ # The 2nd arg to s_f_m() doesn't matter as it won't fail since every-
+ # thing will have already parsed at this point.
+ (rfc822, rfc2047, name, email) = safe_fix_maintainer(
+ fullemail, "email")
+ return getUtility(IPersonSet).getByEmail(email)
+
+
class LanguagePackEncountered(Exception):
"""Thrown when not wanting to email notifications for language packs."""