launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #05330
[Merge] lp:~jtv/launchpad/lint-distroseriesqueue-notify into lp:launchpad
Jeroen T. Vermeulen has proposed merging lp:~jtv/launchpad/lint-distroseriesqueue-notify into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~jtv/launchpad/lint-distroseriesqueue-notify/+merge/80541
= Summary =
Clean up some pre-existing lint in a doctest that I touched in the pre-cleanup for bug 876594. I promised in the MP.
I ran the formatdoctest tool (with the -f option) and also cleaned up a bit by hand.
= Launchpad lint =
None left in this file.
--
https://code.launchpad.net/~jtv/launchpad/lint-distroseriesqueue-notify/+merge/80541
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~jtv/launchpad/lint-distroseriesqueue-notify into lp:launchpad.
=== modified file 'lib/lp/archiveuploader/tests/nascentupload-announcements.txt'
--- lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2011-08-22 04:38:02 +0000
+++ lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2011-10-27 08:29:29 +0000
@@ -46,8 +46,8 @@
... return cmp(a[1], b[1])
>>> def print_addrlist(field):
- ... for entry in field.split(','):
- ... print entry.strip()
+ ... for entry in sorted([addr.strip() for addr in field.split(',')]):
+ ... print entry
Import the test keys to use 'insecure' policy.
@@ -443,8 +443,8 @@
'Launchpad actually'
>>> print_addrlist(notification['To'])
+ Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
Foo Bar <foo.bar@xxxxxxxxxxxxx>
- Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
>>> notification['Subject']
'[ubuntu/hoary-updates] bar 1.0-2 (Waiting for approval)'
@@ -479,8 +479,8 @@
'Launchpad actually'
>>> print_addrlist(notification['To'])
+ Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
Foo Bar <foo.bar@xxxxxxxxxxxxx>
- Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
>>> notification['Subject']
'[ubuntu/hoary-backports] bar 1.0-3 (Waiting for approval)'
=== modified file 'lib/lp/soyuz/adapters/notification.py'
--- lib/lp/soyuz/adapters/notification.py 2011-08-31 05:06:54 +0000
+++ lib/lp/soyuz/adapters/notification.py 2011-10-27 08:29:29 +0000
@@ -6,7 +6,6 @@
__metaclass__ = type
__all__ = [
- 'get_recipients', # Available for testing only.
'notify',
]
@@ -68,7 +67,7 @@
}
template = get_template(archive, 'rejected')
body = template % information
- to_addrs = get_recipients(
+ to_addrs = get_upload_notification_recipients(
blamer, archive, distroseries, logger, changes=changes)
debug(logger, "Sending rejection email.")
if not to_addrs:
@@ -128,7 +127,7 @@
summary_text=None, changes=None, changesfile_content=None,
changesfile_object=None, action=None, dry_run=False,
logger=None, announce_from_person=None, previous_version=None):
- """Notify about
+ """Notify about an upload or package copy.
:param blamer: The `IPerson` who is to blame for this notification.
:param spr: The `ISourcePackageRelease` that was created.
@@ -187,7 +186,7 @@
if not files and action != 'rejected':
return
- recipients = get_recipients(
+ recipients = get_upload_notification_recipients(
blamer, archive, distroseries, logger, changes=changes, spr=spr,
bprs=bprs)
@@ -304,13 +303,12 @@
if distroseries.changeslist:
information['ANNOUNCE'] = "Announcing to %s" % (
distroseries.changeslist)
- try:
- changedby_person = email_to_person(info['changedby'])
- except ParseMaintError:
- # Some syncs (e.g. from Debian) will involve packages whose
- # changed-by person was auto-created in LP and hence does not
- # have a preferred email address set.
- changedby_person = None
+
+ # Some syncs (e.g. from Debian) will involve packages whose
+ # changed-by person was auto-created in LP and hence does not have a
+ # preferred email address set. We'll get a None here.
+ changedby_person = email_to_person(info['changedby'])
+
if blamer is not None and blamer != changedby_person:
signer_signature = person_to_email(blamer)
if signer_signature != info['changedby']:
@@ -448,73 +446,69 @@
return guess_encoding(s)
-def debug(logger, msg):
+def debug(logger, msg, *args, **kwargs):
"""Shorthand debug notation for publish() methods."""
if logger is not None:
- logger.debug(msg)
-
-
-def get_recipients(blamer, archive, distroseries, logger, changes=None,
- spr=None, bprs=None):
+ logger.debug(msg, *args, **kwargs)
+
+
+def is_valid_uploader(person, distribution):
+ """Is `person` an uploader for `distribution`?
+
+ A `None` person is not an uploader.
+ """
+ if person is None:
+ return None
+ else:
+ return person.isUploader(distribution)
+
+
+def get_upload_notification_recipients(blamer, archive, distroseries,
+ logger=None, changes=None, spr=None,
+ bprs=None):
"""Return a list of recipients for notification emails."""
- candidate_recipients = []
debug(logger, "Building recipients list.")
+ candidate_recipients = [
+ blamer,
+ ]
info = fetch_information(spr, bprs, changes)
- if info['changedby']:
- try:
- changer = email_to_person(info['changedby'])
- except ParseMaintError:
- changer = None
- else:
- changer = None
-
- if info['maintainer']:
- try:
- maintainer = email_to_person(info['maintainer'])
- except ParseMaintError:
- maintainer = None
- else:
- maintainer = None
-
- if blamer:
- # This is a signed upload.
- candidate_recipients.append(blamer)
- else:
- debug(logger,
- "Changes file is unsigned, adding changer as recipient")
+ changer = email_to_person(info['changedby'])
+ maintainer = email_to_person(info['maintainer'])
+
+ if blamer is None:
+ debug(
+ logger, "Changes file is unsigned; adding changer as recipient.")
candidate_recipients.append(changer)
if archive.is_ppa:
# For PPAs, any person or team mentioned explicitly in the
# ArchivePermissions as uploaders for the archive will also
# get emailed.
- uploaders = [
- permission.person for permission in
- archive.getUploadersForComponent()]
- candidate_recipients.extend(uploaders)
-
- # If this is not a PPA, we also consider maintainer and changed-by.
- elif blamer is not None:
- if (maintainer and maintainer != blamer and
- maintainer.isUploader(distroseries.distribution)):
- debug(logger, "Adding maintainer to recipients")
- candidate_recipients.append(maintainer)
-
- if (changer and changer != blamer and
- changer.isUploader(distroseries.distribution)):
- debug(logger, "Adding changed-by to recipients")
- candidate_recipients.append(changer)
-
- # Now filter list of recipients for persons only registered in
- # Launchpad to avoid spamming the innocent.
- recipients = []
- for person in candidate_recipients:
- if person is None or person.preferredemail is None:
- continue
- recipient = format_address_for_person(person)
- debug(logger, "Adding recipient: '%s'" % recipient)
- recipients.append(recipient)
+ candidate_recipients.extend([
+ permission.person
+ for permission in archive.getUploadersForComponent()])
+ else:
+ # If this is not a PPA, we also consider maintainer and changed-by.
+ if blamer is not None:
+ if is_valid_uploader(maintainer, distroseries.distribution):
+ debug(logger, "Adding maintainer to recipients")
+ candidate_recipients.append(maintainer)
+
+ if is_valid_uploader(changer, distroseries.distribution):
+ debug(logger, "Adding changed-by to recipients")
+ candidate_recipients.append(changer)
+
+ # Collect email addresses to notify. Skip persons who do not have a
+ # preferredemail set, such as people who have not activated their
+ # Launchpad accounts (and are therefore not expecting this email).
+ recipients = [
+ format_address_for_person(person)
+ for person in filter(None, set(candidate_recipients))
+ if person.preferredemail is not None]
+
+ for recipient in recipients:
+ debug(logger, "Adding recipient: '%s'", recipient)
return recipients
@@ -572,18 +566,29 @@
def email_to_person(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)
+ """Return an `IPerson` given an RFC2047 email address.
+
+ :param fullemail: Potential email address.
+ :return: `IPerson` with the given email address. None if there
+ isn't one, or if `fullemail` isn't a proper email address.
+ """
+ if not fullemail:
+ return None
+
+ try:
+ # 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)
+ except ParseMaintError:
+ return None
def person_to_email(person):
"""Return a string of full name <e-mail address> given an IPerson."""
- # This will use email.Header to encode any unicode.
if person and person.preferredemail:
+ # This will use email.Header to encode any non-ASCII characters.
return format_address_for_person(person)
@@ -595,12 +600,11 @@
user (archive@xxxxxxxxxx).
"""
katie = getUtility(ILaunchpadCelebrities).katie
- try:
- changed_by = email_to_person(changed_by_email)
- except ParseMaintError:
- return False
+ changed_by = email_to_person(changed_by_email)
return (
- spr and not bprs and changed_by == katie and
+ spr and
+ not bprs and
+ changed_by == katie and
pocket != PackagePublishingPocket.SECURITY)
=== modified file 'lib/lp/soyuz/adapters/tests/test_notification.py'
--- lib/lp/soyuz/adapters/tests/test_notification.py 2011-08-31 05:06:54 +0000
+++ lib/lp/soyuz/adapters/tests/test_notification.py 2011-10-27 08:29:29 +0000
@@ -6,8 +6,9 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
from email.utils import formataddr
+from textwrap import dedent
+
from storm.store import Store
-from textwrap import dedent
from zope.component import getUtility
from zope.security.proxy import removeSecurityProxy
@@ -18,24 +19,24 @@
)
from lp.archivepublisher.utils import get_ppa_reference
from lp.registry.interfaces.pocket import PackagePublishingPocket
+from lp.services.log.logger import BufferLogger
from lp.services.mail.sendmail import format_address_for_person
-from lp.services.log.logger import BufferLogger
from lp.soyuz.adapters.notification import (
assemble_body,
calculate_subject,
- get_recipients,
fetch_information,
+ get_upload_notification_recipients,
is_auto_sync_upload,
+ notify,
+ person_to_email,
reject_changes_file,
- person_to_email,
- notify,
)
-from lp.soyuz.interfaces.component import IComponentSet
-from lp.soyuz.model.component import ComponentSelection
from lp.soyuz.enums import (
ArchivePurpose,
PackageUploadCustomFormat,
)
+from lp.soyuz.interfaces.component import IComponentSet
+from lp.soyuz.model.component import ComponentSelection
from lp.soyuz.model.distroseriessourcepackagerelease import (
DistroSeriesSourcePackageRelease,
)
@@ -231,8 +232,8 @@
def test_fetch_information_changes(self):
changes = {
'Date': '2001-01-01',
- 'Changed-By': 'Foo Bar <foo.bar@xxxxxxxxxxxxx>',
- 'Maintainer': 'Foo Bar <foo.bar@xxxxxxxxxxxxx>',
+ 'Changed-By': 'Foo Bar <foo.bar@xxxxxxxxxxx>',
+ 'Maintainer': 'Foo Bar <foo.bar@xxxxxxxxxxx>',
'Changes': ' * Foo!',
}
info = fetch_information(
@@ -246,7 +247,7 @@
info['maintainer_displayname'],
]
for field in fields:
- self.assertEqual('Foo Bar <foo.bar@xxxxxxxxxxxxx>', field)
+ self.assertEqual('Foo Bar <foo.bar@xxxxxxxxxxx>', field)
def test_fetch_information_spr(self):
creator = self.factory.makePerson(displayname=u"foø")
@@ -365,64 +366,67 @@
distroseries=distroseries, component=component))
archive.newComponentUploader(maintainer, component)
archive.newComponentUploader(changer, component)
- return get_recipients(
+ return get_upload_notification_recipients(
blamer, archive, distroseries, logger=None, changes=changes)
- def test_get_recipients_good_emails(self):
- # Test get_recipients with good email addresses..
- blamer = self.factory.makePerson()
- maintainer = self.factory.makePerson(
- 'maintainer@xxxxxxxxxxxxx', displayname='Maintainer')
- changer = self.factory.makePerson(
- 'changer@xxxxxxxxxxxxx', displayname='Changer')
- changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxxxx>',
- 'Changes': ' * Foo!',
- }
- recipients = self._run_recipients_test(
- changes, blamer, maintainer, changer)
- expected = [format_address_for_person(p)
- for p in (blamer, maintainer, changer)]
- self.assertEqual(expected, recipients)
-
- def test_get_recipients_bad_maintainer_email(self):
- blamer = self.factory.makePerson()
- maintainer = self.factory.makePerson(
- 'maintainer@xxxxxxxxxxxxx', displayname='Maintainer')
- changer = self.factory.makePerson(
- 'changer@xxxxxxxxxxxxx', displayname='Changer')
- changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer@xxxxxxxxxxxxx>',
- 'Maintainer': 'Maintainer <maintainer at canonical.com>',
- 'Changes': ' * Foo!',
- }
- recipients = self._run_recipients_test(
- changes, blamer, maintainer, changer)
- expected = [format_address_for_person(p)
- for p in (blamer, changer)]
- self.assertEqual(expected, recipients)
-
- def test_get_recipients_bad_changedby_email(self):
- # Test get_recipients with invalid changedby email address.
- blamer = self.factory.makePerson()
- maintainer = self.factory.makePerson(
- 'maintainer@xxxxxxxxxxxxx', displayname='Maintainer')
- changer = self.factory.makePerson(
- 'changer@xxxxxxxxxxxxx', displayname='Changer')
- changes = {
- 'Date': '2001-01-01',
- 'Changed-By': 'Changer <changer at canonical.com>',
- 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxxxx>',
- 'Changes': ' * Foo!',
- }
- recipients = self._run_recipients_test(
- changes, blamer, maintainer, changer)
- expected = [format_address_for_person(p)
- for p in (blamer, maintainer)]
- self.assertEqual(expected, recipients)
+ def test_get_upload_notification_recipients_good_emails(self):
+ # Test get_upload_notification_recipients with good email addresses..
+ blamer = self.factory.makePerson()
+ maintainer = self.factory.makePerson(
+ 'maintainer@xxxxxxxxxxx', displayname='Maintainer')
+ changer = self.factory.makePerson(
+ 'changer@xxxxxxxxxxx', displayname='Changer')
+ changes = {
+ 'Date': '2001-01-01',
+ 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': ' * Foo!',
+ }
+ recipients = self._run_recipients_test(
+ changes, blamer, maintainer, changer)
+ expected = [
+ format_address_for_person(person)
+ for person in (blamer, maintainer, changer)]
+ self.assertContentEqual(expected, recipients)
+
+ def test_get_upload_notification_recipients_bad_maintainer_email(self):
+ blamer = self.factory.makePerson()
+ maintainer = self.factory.makePerson(
+ 'maintainer@xxxxxxxxxxx', displayname='Maintainer')
+ changer = self.factory.makePerson(
+ 'changer@xxxxxxxxxxx', displayname='Changer')
+ changes = {
+ 'Date': '2001-01-01',
+ 'Changed-By': 'Changer <changer@xxxxxxxxxxx>',
+ 'Maintainer': 'Maintainer <maintainer at example.com>',
+ 'Changes': ' * Foo!',
+ }
+ recipients = self._run_recipients_test(
+ changes, blamer, maintainer, changer)
+ expected = [
+ format_address_for_person(person) for person in (blamer, changer)]
+ self.assertContentEqual(expected, recipients)
+
+ def test_get_upload_notification_recipients_bad_changedby_email(self):
+ # Test get_upload_notification_recipients with invalid changedby
+ # email address.
+ blamer = self.factory.makePerson()
+ maintainer = self.factory.makePerson(
+ 'maintainer@xxxxxxxxxxx', displayname='Maintainer')
+ changer = self.factory.makePerson(
+ 'changer@xxxxxxxxxxx', displayname='Changer')
+ changes = {
+ 'Date': '2001-01-01',
+ 'Changed-By': 'Changer <changer at example.com>',
+ 'Maintainer': 'Maintainer <maintainer@xxxxxxxxxxx>',
+ 'Changes': ' * Foo!',
+ }
+ recipients = self._run_recipients_test(
+ changes, blamer, maintainer, changer)
+ expected = [
+ format_address_for_person(person)
+ for person in (blamer, maintainer)]
+ self.assertContentEqual(expected, recipients)
def test_assemble_body_handles_no_preferred_email_for_changer(self):
# If changer has no preferred email address,
=== modified file 'lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt'
--- lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt 2011-07-21 23:10:26 +0000
+++ lib/lp/soyuz/doc/distroseriesqueue-dist-upgrader.txt 2011-10-27 08:29:29 +0000
@@ -60,6 +60,7 @@
DEBUG Creating queue entry
DEBUG Setting it to ACCEPTED
DEBUG Building recipients list.
+ ...
DEBUG Adding recipient: 'Foo Bar <foo.bar@xxxxxxxxxxxxx>'
DEBUG Sent a mail:
...
@@ -235,6 +236,7 @@
DEBUG Creating queue entry
DEBUG Setting it to ACCEPTED
DEBUG Building recipients list.
+ ...
DEBUG Adding recipient: 'Foo Bar <foo.bar@xxxxxxxxxxxxx>'
DEBUG Sent a mail:
...
=== modified file 'lib/lp/soyuz/doc/distroseriesqueue-notify.txt'
--- lib/lp/soyuz/doc/distroseriesqueue-notify.txt 2011-06-01 04:57:27 +0000
+++ lib/lp/soyuz/doc/distroseriesqueue-notify.txt 2011-10-27 08:29:29 +0000
@@ -1,263 +1,291 @@
-= Queue Notify =
-
-PackageUpload has a notify() method to send emails.
-We need to be logged into the security model in order to get any further.
-
- >>> login('foo.bar@xxxxxxxxxxxxx')
+Queue Notify
+============
+
+PackageUpload has a notify() method to send emails. We need to be logged
+into the security model in order to get any further.
+
+ >>> login('foo.bar@xxxxxxxxxxxxx')
Get a packageupload object for netapplet, which has a relatively intact
-set of supporting sample data. It has rows in distribution, distroseries,
-sourcepackagerelease, person and a librarian entry for the changes file
-which are all needed for successful operation of notify().
-
- >>> from lp.soyuz.interfaces.queue import IPackageUploadSet
- >>> netapplet_upload = getUtility(IPackageUploadSet)[3]
- >>> print netapplet_upload.displayname
- netapplet
-
-Set up some library files for the netapplet source package. These are not
-already present in the sample data.
-
- >>> from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
- >>> from lp.archiveuploader.tests import datadir
- >>> import os
- >>> netapplet_spr = netapplet_upload.sources[0].sourcepackagerelease
- >>> librarian = getUtility(ILibraryFileAliasSet)
- >>> files = ['netapplet_1.0-1.dsc', 'netapplet_1.0.orig.tar.gz',
- ... 'netapplet_1.0-1.diff.gz']
- >>> for file in files:
- ... filepath = datadir('suite/netapplet_1.0-1/%s' % file)
- ... fileobj = open(filepath, 'rb')
- ... filesize = os.stat(filepath).st_size
- ... lfa = librarian.create(file, filesize, fileobj, 'dummytype')
- ... sprf = netapplet_spr.addFile(lfa)
- ... fileobj.close()
-
-The notify() method generates one email here on this unsigned package. It
-requires an announcement list email address, a "changes_file_object" that is
-just an open file object for the original changes file, and a special
-logger object that will extract tracebacks for the purposes of this doctest.
-
- >>> changes_file_path = datadir(
- ... 'suite/netapplet_1.0-1/netapplet_1.0-1_source.changes')
- >>> changes_file = open(changes_file_path,'r')
- >>> from lp.services.log.logger import FakeLogger
- >>> netapplet_upload.notify(
- ... changes_file_object=changes_file, logger=FakeLogger())
- DEBUG Building recipients list.
- DEBUG Changes file is unsigned, adding changer as recipient
- ...
- DEBUG Sent a mail:
- ...
- DEBUG Recipients: Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
- ...
- DEBUG above if files already exist in other distroseries.
- ...
- DEBUG signer of the above package.
+set of supporting sample data. It has rows in distribution,
+distroseries, sourcepackagerelease, person and a librarian entry for the
+changes file which are all needed for successful operation of notify().
+
+ >>> from lp.soyuz.interfaces.queue import IPackageUploadSet
+ >>> netapplet_upload = getUtility(IPackageUploadSet)[3]
+ >>> print netapplet_upload.displayname
+ netapplet
+
+Set up some library files for the netapplet source package. These are
+not already present in the sample data.
+
+ >>> from canonical.launchpad.interfaces.librarian import (
+ ... ILibraryFileAliasSet)
+ >>> from lp.archiveuploader.tests import datadir
+ >>> import os
+ >>> netapplet_spr = netapplet_upload.sources[0].sourcepackagerelease
+ >>> librarian = getUtility(ILibraryFileAliasSet)
+ >>> files = [
+ ... 'netapplet_1.0-1.dsc',
+ ... 'netapplet_1.0.orig.tar.gz',
+ ... 'netapplet_1.0-1.diff.gz',
+ ... ]
+ >>> for file in files:
+ ... filepath = datadir('suite/netapplet_1.0-1/%s' % file)
+ ... fileobj = open(filepath, 'rb')
+ ... filesize = os.stat(filepath).st_size
+ ... lfa = librarian.create(file, filesize, fileobj, 'dummytype')
+ ... sprf = netapplet_spr.addFile(lfa)
+ ... fileobj.close()
+
+The notify() method generates one email here on this unsigned package.
+It requires an announcement list email address, a "changes_file_object"
+that is just an open file object for the original changes file, and a
+special logger object that will extract tracebacks for the purposes of
+this doctest.
+
+ >>> changes_file_path = datadir(
+ ... 'suite/netapplet_1.0-1/netapplet_1.0-1_source.changes')
+ >>> changes_file = open(changes_file_path,'r')
+ >>> from lp.services.log.logger import FakeLogger
+ >>> netapplet_upload.notify(
+ ... changes_file_object=changes_file, logger=FakeLogger())
+ DEBUG Building recipients list.
+ DEBUG Changes file is unsigned; adding changer as recipient.
+ ...
+ DEBUG Sent a mail:
+ ...
+ DEBUG Recipients: ... Silverstone ...
+ ...
+ DEBUG above if files already exist in other distroseries.
+ ...
+ DEBUG signer of the above package.
Helper functions to examine emails that were sent:
- >>> from lp.services.mail import stub
- >>> from lp.testing.mail_helpers import pop_notifications
- >>> def by_to_addrs(a, b):
- ... return cmp(a[1], b[1])
+ >>> from lp.services.mail import stub
+ >>> from lp.testing.mail_helpers import pop_notifications
There's only one email generated from the preceding upload:
- >>> [notification] = pop_notifications()
+ >>> [notification] = pop_notifications()
The mail headers contain our To: as set on the notify() call. The
-subject contains "Accepted", the package name, its version and whether it's
-source or binary. The Bcc field also always contains the uploader's email
-address.
-
- >>> notification['To']
- 'Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>'
- >>> notification['Bcc']
- 'Root <root@localhost>'
-
- >>> notification['Subject']
- '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
+subject contains "Accepted", the package name, its version and whether
+it's source or binary. The Bcc field also always contains the
+uploader's email address.
+
+ >>> notification['To']
+ 'Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>'
+
+ >>> notification['Bcc']
+ 'Root <root@localhost>'
+
+ >>> notification['Subject']
+ '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
The mail body contains a list of files that were accepted:
- >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
- From nobody ...
- ...
- NEW: netapplet_1.0-1.dsc
- NEW: netapplet_1.0.orig.tar.gz
- NEW: netapplet_1.0-1.diff.gz
- <BLANKLINE>
- ...
- You may have gotten the distroseries wrong. If so, you may get warnings
- above if files already exist in other distroseries.
- <BLANKLINE>
- -- =
- <BLANKLINE>
- You are receiving this email because you are the uploader, maintainer or
- signer of the above package.
- <BLANKLINE>
-
-Now we will process a signed package. Signed packages will potentially have
-a different recipient list to unsigned ones; recipients for signed package
-uploads can be the signer, the maintainer and the changer, where these people
-are different. Unsigned packages only send notifications to the changer.
-
- >>> from zope.security.proxy import removeSecurityProxy
- >>> from lp.registry.interfaces.gpg import IGPGKeySet
- >>> gpgkey = getUtility(IGPGKeySet).get(1)
- >>> removeSecurityProxy(netapplet_upload).signing_key = gpgkey
+ >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
+ From nobody ...
+ ...
+ NEW: netapplet_1.0-1.dsc
+ NEW: netapplet_1.0.orig.tar.gz
+ NEW: netapplet_1.0-1.diff.gz
+ <BLANKLINE>
+ ...
+ You may have gotten the distroseries wrong. If so, you may get warnings
+ above if files already exist in other distroseries.
+ <BLANKLINE>
+ -- =
+ <BLANKLINE>
+ You are receiving this email because you are the uploader, maintainer or
+ signer of the above package.
+ <BLANKLINE>
+
+Now we will process a signed package. Signed packages will potentially
+have a different recipient list to unsigned ones; recipients for signed
+package uploads can be the signer, the maintainer and the changer, where
+these people are different. Unsigned packages only send notifications
+to the changer.
+
+ >>> from zope.security.proxy import removeSecurityProxy
+ >>> from lp.registry.interfaces.gpg import IGPGKeySet
+ >>> gpgkey = getUtility(IGPGKeySet).get(1)
+ >>> removeSecurityProxy(netapplet_upload).signing_key = gpgkey
Now request the email:
- >>> changes_file_path = datadir(
- ... 'suite/netapplet_1.0-1-signed/netapplet_1.0-1_source.changes')
- >>> changes_file = open(changes_file_path,'r')
- >>> netapplet_upload.setAccepted()
- >>> netapplet_upload.notify(
- ... changes_file_object=changes_file, logger=FakeLogger())
- DEBUG Building recipients list.
- ...
- DEBUG Sent a mail:
- ...
- DEBUG Recipients: Foo Bar <foo.bar@xxxxxxxxxxxxx>, Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
- ...
- DEBUG Announcing to autotest_changes@xxxxxxxxxx
- ...
- DEBUG Sent a mail:
- ...
-
-There are two emails, the upload acknowledgement and the announcement, because
-this upload is already accepted.
-
- >>> msgs = pop_notifications()
- >>> len(msgs)
- 2
-
-The mail 'To:' addresses contain the signer and the changer's email. The
-announcement email contains the serieses changeslist.
-
- >>> [msg['To'] for msg in msgs]
- ['Foo Bar <foo.bar@xxxxxxxxxxxxx>,\n\tDaniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>', 'autotest_changes@xxxxxxxxxx']
-
-The mail 'Bcc:' address is the uploader. The announcement has the uploader
-and the Debian derivatives address for the package uploaded.
-
- >>> [msg['Bcc'] for msg in msgs]
- ['Root <root@localhost>', 'Root <root@localhost>, netapplet_derivatives@xxxxxxxxxxxxxxxxxxxxxx']
+ >>> changes_file_path = datadir(
+ ... 'suite/netapplet_1.0-1-signed/netapplet_1.0-1_source.changes')
+ >>> changes_file = open(changes_file_path,'r')
+ >>> netapplet_upload.setAccepted()
+ >>> netapplet_upload.notify(
+ ... changes_file_object=changes_file, logger=FakeLogger())
+ DEBUG Building recipients list.
+ ...
+ DEBUG Sent a mail:
+ ...
+ DEBUG Recipients: ... Bar ...
+ ...
+ DEBUG Announcing to autotest_changes@xxxxxxxxxx
+ ...
+ DEBUG Sent a mail:
+ ...
+
+There are two emails, the upload acknowledgement and the announcement,
+because this upload is already accepted.
+
+ >>> msgs = pop_notifications()
+ >>> len(msgs)
+ 2
+
+The mail 'To:' addresses contain the signer and the changer's email.
+The announcement email contains the serieses changeslist.
+
+ >>> def to_lower(address):
+ ... """Return lower-case version of email address."""
+ ... return address.lower()
+
+ >>> def extract_addresses(header_field):
+ ... """Extract and sort addresses from an email header field."""
+ ... return sorted(
+ ... [addr.strip() for addr in header_field.split(',')],
+ ... key=to_lower)
+
+ >>> for addr in extract_addresses(msgs[0]['To']):
+ ... print addr
+ Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
+ Foo Bar <foo.bar@xxxxxxxxxxxxx>
+
+ >>> print msgs[1]['To']
+ autotest_changes@xxxxxxxxxx
+
+The mail 'Bcc:' address is the uploader. The announcement has the
+uploader and the Debian derivatives address for the package uploaded.
+
+ >>> for msg in msgs:
+ ... print extract_addresses(msg['Bcc'])
+ ['Root <root@localhost>']
+ ['netapplet_derivatives@xxxxxxxxxxxxxxxxxxxxxx', 'Root <root@localhost>']
The mail 'From:' addresses are the uploader and the changer.
- >>> [msg['From'] for msg in msgs]
- ['Root <root@localhost>', 'Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>']
+ >>> for msg in msgs:
+ ... print msg['From']
+ Root <root@localhost>
+ Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
- >>> notification['Subject']
- '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
+ >>> print notification['Subject']
+ [ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)
The mail body contains the same list of files again:
- >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
- From nobody ...
- ...
- NEW: netapplet_1.0-1.dsc
- NEW: netapplet_1.0.orig.tar.gz
- NEW: netapplet_1.0-1.diff.gz
- <BLANKLINE>
- ...
- You may have gotten the distroseries wrong. If so, you may get warnings
- above if files already exist in other distroseries.
- <BLANKLINE>
- -- =
- <BLANKLINE>
- You are receiving this email because you are the uploader, maintainer or
- signer of the above package.
- <BLANKLINE>
-
-
-notify() will also work without passing the changes_file_object parameter
-provided that everything is already committed to the database (which is not
-the case when nascent upload runs). This example demonstrates this usage:
-
- >>> from canonical.librarian.testing.server import fillLibrarianFile
- >>> changes_file = open(changes_file_path,"r")
- >>> fillLibrarianFile(1, content=changes_file.read())
- >>> changes_file.close()
- >>> netapplet_upload.setNew()
- >>> netapplet_upload.notify(logger=FakeLogger())
- DEBUG Building recipients list.
- ...
- DEBUG Sent a mail:
- ...
- DEBUG Recipients: Foo Bar <foo.bar@xxxxxxxxxxxxx>, Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
- ...
- DEBUG above if files already exist in other distroseries.
- ...
- DEBUG signer of the above package.
+ >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
+ From nobody ...
+ ...
+ NEW: netapplet_1.0-1.dsc
+ NEW: netapplet_1.0.orig.tar.gz
+ NEW: netapplet_1.0-1.diff.gz
+ <BLANKLINE>
+ ...
+ You may have gotten the distroseries wrong. If so, you may get warnings
+ above if files already exist in other distroseries.
+ <BLANKLINE>
+ -- =
+ <BLANKLINE>
+ You are receiving this email because you are the uploader, maintainer or
+ signer of the above package.
+ <BLANKLINE>
+
+notify() will also work without passing the changes_file_object
+parameter provided that everything is already committed to the database
+(which is not the case when nascent upload runs). This example
+demonstrates this usage:
+
+ >>> from canonical.librarian.testing.server import fillLibrarianFile
+ >>> changes_file = open(changes_file_path,"r")
+ >>> fillLibrarianFile(1, content=changes_file.read())
+ >>> changes_file.close()
+ >>> netapplet_upload.setNew()
+ >>> netapplet_upload.notify(logger=FakeLogger())
+ DEBUG Building recipients list.
+ ...
+ DEBUG Sent a mail:
+ ...
+ DEBUG Recipients: ... Silverstone ...
+ ...
+ DEBUG above if files already exist in other distroseries.
+ ...
+ DEBUG signer of the above package.
Only one email is generated:
- >>> [notification] = pop_notifications()
+ >>> [notification] = pop_notifications()
The mail headers are the same as before:
- >>> notification['To']
- 'Foo Bar <foo.bar@xxxxxxxxxxxxx>,\n\tDaniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>'
- >>> notification['Bcc']
- 'Root <root@localhost>'
-
- >>> notification['Subject']
- '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
+ >>> for addr in extract_addresses(notification['To']):
+ ... print addr
+ Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
+ Foo Bar <foo.bar@xxxxxxxxxxxxx>
+
+ >>> print notification['Bcc']
+ Root <root@localhost>
+
+ >>> print notification['Subject']
+ [ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)
The mail body contains the same list of files again:
- >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
- From nobody ...
- ...
- NEW: netapplet_1.0-1.dsc
- NEW: netapplet_1.0.orig.tar.gz
- NEW: netapplet_1.0-1.diff.gz
- <BLANKLINE>
- ...
- You may have gotten the distroseries wrong. If so, you may get warnings
- above if files already exist in other distroseries.
- <BLANKLINE>
- -- =
- <BLANKLINE>
- You are receiving this email because you are the uploader, maintainer or
- signer of the above package.
- <BLANKLINE>
-
+ >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
+ From nobody ...
+ ...
+ NEW: netapplet_1.0-1.dsc
+ NEW: netapplet_1.0.orig.tar.gz
+ NEW: netapplet_1.0-1.diff.gz
+ <BLANKLINE>
+ ...
+ You may have gotten the distroseries wrong. If so, you may get warnings
+ above if files already exist in other distroseries.
+ <BLANKLINE>
+ -- =
+ <BLANKLINE>
+ You are receiving this email because you are the uploader, maintainer or
+ signer of the above package.
+ <BLANKLINE>
notify() will also generate rejection notices if the upload failed. The
-summary_text argument is text that is appended to any auto-generated text for
-the summary. Rejections don't currently auto-generate anything.
+summary_text argument is text that is appended to any auto-generated
+text for the summary. Rejections don't currently auto-generate
+anything.
- >>> netapplet_upload.setRejected()
- >>> netapplet_upload.notify(summary_text="Testing rejection message",
- ... logger=FakeLogger())
- DEBUG Building recipients list.
- ...
- DEBUG Sending rejection email.
- ...
- DEBUG Subject: [ubuntu/breezy-autotest] netapplet 0.99.6-1 (Rejected)
- DEBUG Sender: Root <root@localhost>
- DEBUG Recipients: Foo Bar <foo.bar@xxxxxxxxxxxxx>, Daniel Silverstone <daniel.silverstone@xxxxxxxxxxxxx>
- DEBUG Bcc: Root <root@localhost>
- DEBUG Body:
- DEBUG Rejected:
- DEBUG Testing rejection message
- ...
- DEBUG If you don't understand why your files were rejected, or if the
- ...
- DEBUG signer of the above package.
+ >>> netapplet_upload.setRejected()
+ >>> netapplet_upload.notify(
+ ... summary_text="Testing rejection message", logger=FakeLogger())
+ DEBUG Building recipients list.
+ ...
+ DEBUG Sending rejection email.
+ ...
+ DEBUG Subject: [ubuntu/breezy-autotest] netapplet 0.99.6-1 (Rejected)
+ DEBUG Sender: Root <root@localhost>
+ DEBUG Recipients: ... Foo Bar ...
+ DEBUG Bcc: Root <root@localhost>
+ DEBUG Body:
+ DEBUG Rejected:
+ DEBUG Testing rejection message
+ ...
+ DEBUG If you don't understand why your files were rejected, or if the
+ ...
+ DEBUG signer of the above package.
Only one email is generated:
- >>> transaction.commit()
- >>> len(stub.test_emails)
- 1
+ >>> transaction.commit()
+ >>> len(stub.test_emails)
+ 1
Clean up, otherwise stuff is left lying around in /var/tmp.
- >>> from canonical.testing.layers import LibrarianLayer
- >>> LibrarianLayer.librarian_fixture.clear()
+ >>> from canonical.testing.layers import LibrarianLayer
+ >>> LibrarianLayer.librarian_fixture.clear()
=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py 2011-08-25 08:29:37 +0000
+++ lib/lp/soyuz/model/queue.py 2011-10-27 08:29:29 +0000
@@ -868,7 +868,7 @@
signer, self.sourcepackagerelease, self.builds, self.customfiles,
self.archive, self.distroseries, self.pocket, summary_text,
changes, changesfile_content, changes_file_object,
- status_action[self.status], dry_run, logger)
+ status_action[self.status], dry_run=dry_run, logger=logger)
def _isPersonUploader(self, person):
"""Return True if person is an uploader to the package's distro."""
=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
--- lib/lp/soyuz/scripts/packagecopier.py 2011-09-26 06:30:07 +0000
+++ lib/lp/soyuz/scripts/packagecopier.py 2011-10-27 08:29:29 +0000
@@ -533,8 +533,8 @@
Verifies if each copy can be performed using `CopyChecker` and
raises `CannotCopy` if one or more copies could not be performed.
- When `CannotCopy`is raised call sites are in charge to rollback the
- transaction or performed copies will be commited.
+ When `CannotCopy` is raised, call sites are responsible for rolling
+ back the transaction. Otherwise, performed copies will be commited.
Wrapper for `do_direct_copy`.
@@ -611,8 +611,7 @@
# In zopeless mode this email will be sent immediately.
notify(
person, source.sourcepackagerelease, [], [], archive,
- series, pocket, summary_text=error_text,
- action='rejected')
+ series, pocket, summary_text=error_text, action='rejected')
raise CannotCopy(error_text)
overrides_index = 0
@@ -648,8 +647,7 @@
if send_email:
notify(
person, source.sourcepackagerelease, [], [], archive,
- destination_series, pocket, changes=None,
- action='accepted',
+ destination_series, pocket, action='accepted',
announce_from_person=announce_from_person,
previous_version=old_version)