launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #03960
[Merge] lp:~bac/launchpad/bug-519857 into lp:launchpad
Brad Crittenden has proposed merging lp:~bac/launchpad/bug-519857 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #519857 in Launchpad itself: "Upload processor OOPSes with bad email addresses"
https://bugs.launchpad.net/launchpad/+bug/519857
For more details, see:
https://code.launchpad.net/~bac/launchpad/bug-519857/+merge/64606
= Summary =
If a malformed email address appeared in an uploaded package's changes
file then an OOPS was thrown.
== Proposed fix ==
Catch the ParseMaintError and simply don't include the bad address in
the recipients list.
== Pre-implementation notes ==
Chatted with Julian.
== Tests ==
New unit tests for get_repients:
bin/test -vvm lp.soyuz -t test_get_recipients
== Demo and Q/A ==
Upload a package with a bad email address in it.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/archiveuploader/utils.py
lib/lp/soyuz/adapters/notification.py
lib/lp/soyuz/adapters/tests/test_notification.py
--
https://code.launchpad.net/~bac/launchpad/bug-519857/+merge/64606
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/launchpad/bug-519857 into lp:launchpad.
=== modified file 'lib/lp/archiveuploader/utils.py'
--- lib/lp/archiveuploader/utils.py 2011-03-21 12:55:50 +0000
+++ lib/lp/archiveuploader/utils.py 2011-06-14 20:26:07 +0000
@@ -257,7 +257,7 @@
"""Wrapper for fix_maintainer() to handle unicode and string argument.
It verifies the content type and transform it in a unicode with guess()
- before call ascii_smash(). Then we can safelly call fix_maintainer().
+ before call ascii_smash(). Then we can safely call fix_maintainer().
"""
if type(content) != unicode:
content = guess_encoding(content)
=== modified file 'lib/lp/soyuz/adapters/notification.py'
--- lib/lp/soyuz/adapters/notification.py 2011-06-14 10:11:12 +0000
+++ lib/lp/soyuz/adapters/notification.py 2011-06-14 20:26:07 +0000
@@ -6,6 +6,7 @@
__metaclass__ = type
__all__ = [
+ 'get_recipients', # Available for testing only.
'notify',
]
@@ -18,22 +19,25 @@
from canonical.config import config
from canonical.launchpad.helpers import get_email_template
-from canonical.launchpad.mail import (
- format_address,
- sendmail,
- )
from canonical.launchpad.webapp import canonical_url
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.archivepublisher.utils import get_ppa_reference
from lp.archiveuploader.changesfile import ChangesFile
-from lp.archiveuploader.utils import safe_fix_maintainer
+from lp.archiveuploader.utils import (
+ ParseMaintError,
+ safe_fix_maintainer,
+ )
from lp.registry.interfaces.person import IPersonSet
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.services.encoding import (
ascii_smash,
guess as guess_encoding,
)
-from lp.services.mail.sendmail import format_address_for_person
+from lp.services.mail.sendmail import (
+ format_address,
+ format_address_for_person,
+ sendmail,
+ )
def reject_changes_file(blamer, changes_file_path, changes, archive,
@@ -92,7 +96,7 @@
'unapproved': 'Waiting for approval',
'rejected': 'Rejected',
'accepted': 'Accepted',
- 'announcement': 'Accepted'
+ 'announcement': 'Accepted',
}
@@ -122,7 +126,7 @@
def notify(blamer, spr, bprs, customfiles, archive, distroseries, pocket,
summary_text=None, changes=None, changesfile_content=None,
changesfile_object=None, action=None, dry_run=False, logger=None):
- """Notify about
+ """Notify about
:param blamer: The `IPerson` who is to blame for this notification.
:param spr: The `ISourcePackageRelease` that was created.
@@ -353,8 +357,8 @@
debug(logger, " Subject: %s" % subject)
debug(logger, " Sender: %s" % from_addr)
debug(logger, " Recipients: %s" % recipients)
- if extra_headers.has_key('Bcc'):
- debug(logger, " Bcc: %s" % extra_headers['Bcc'])
+ if 'Bcc' in extra_headers:
+ debug(logger, " Bcc: %s" % extra_headers['Bcc'])
debug(logger, " Body:")
for line in mail_text.splitlines():
debug(logger, line)
@@ -423,12 +427,20 @@
debug(logger, "Building recipients list.")
(changesfile, date, changedby, maint) = fetch_information(
spr, bprs, changes)
+
if changedby:
- changer = email_to_person(changedby)
+ try:
+ changer = email_to_person(changedby)
+ except ParseMaintError:
+ changer = None
else:
changer = None
+
if maint:
- maintainer = email_to_person(maint)
+ try:
+ maintainer = email_to_person(maint)
+ except ParseMaintError:
+ maintainer = None
else:
maintainer = None
@@ -450,7 +462,7 @@
candidate_recipients.extend(uploaders)
# If this is not a PPA, we also consider maintainer and changed-by.
- if blamer and not archive.is_ppa:
+ elif blamer is not None:
if (maintainer and maintainer != blamer and
maintainer.isUploader(distroseries.distribution)):
debug(logger, "Adding maintainer to recipients")
@@ -467,8 +479,7 @@
for person in candidate_recipients:
if person is None or person.preferredemail is None:
continue
- recipient = format_address(person.displayname,
- person.preferredemail.email)
+ recipient = format_address_for_person(person)
debug(logger, "Adding recipient: '%s'" % recipient)
recipients.append(recipient)
@@ -572,6 +583,8 @@
date = spr.dateuploaded
changedby = person_to_email(spr.creator)
maintainer = person_to_email(spr.maintainer)
+ else:
+ changesfile = date = None
return (changesfile, date, changedby, maintainer)
=== modified file 'lib/lp/soyuz/adapters/tests/test_notification.py'
--- lib/lp/soyuz/adapters/tests/test_notification.py 2011-06-14 10:07:54 +0000
+++ lib/lp/soyuz/adapters/tests/test_notification.py 2011-06-14 20:26:07 +0000
@@ -1,6 +1,8 @@
# Copyright 2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
+from storm.store import Store
+from zope.component import getUtility
from zope.security.proxy import removeSecurityProxy
from canonical.testing.layers import LaunchpadZopelessLayer
@@ -9,12 +11,18 @@
from lp.services.log.logger import BufferLogger
from lp.soyuz.adapters.notification import (
calculate_subject,
+ get_recipients,
fetch_information,
reject_changes_file,
person_to_email,
notify,
)
-from lp.soyuz.enums import PackageUploadCustomFormat
+from lp.soyuz.interfaces.component import IComponentSet
+from lp.soyuz.model.component import ComponentSelection
+from lp.soyuz.enums import (
+ ArchivePurpose,
+ PackageUploadCustomFormat,
+ )
from lp.testing import TestCaseWithFactory
from lp.testing.mail_helpers import pop_notifications
@@ -28,7 +36,7 @@
'Date': '2001-01-01',
'Changed-By': 'Foo Bar <foo.bar@xxxxxxxxxxxxx>',
'Maintainer': 'Foo Bar <foo.bar@xxxxxxxxxxxxx>',
- 'Changes': ' * Foo!'
+ 'Changes': ' * Foo!',
}
(changesfile, date, changedby, maintainer) = fetch_information(
None, None, changes)
@@ -65,7 +73,7 @@
distroseries = self.factory.makeDistroSeries()
expected_subject = '[PPA %s] [%s/%s] %s %s (Accepted)' % (
get_ppa_reference(archive), distroseries.distribution.name,
- distroseries.getSuite(pocket), spr.name, spr.version)
+ distroseries.getSuite(pocket), spr.name, spr.version)
subject = calculate_subject(
spr, [], [], archive, distroseries, pocket, 'accepted')
self.assertEqual(expected_subject, subject)
@@ -130,6 +138,7 @@
body = notification.as_string()
self.assertEqual(person_to_email(person), notification['To'])
self.assertIn('Rejected by archive administrator.\n\n* Foo!\n', body)
+<<<<<<< TREE
def test_reject_changes_file_no_email(self):
# If we are rejecting a mail, and the person to notify has no
@@ -146,3 +155,79 @@
logger=logger)
self.assertIn(
'No recipients have a preferred email.', logger.getLogBuffer())
+=======
+
+ def _run_recipients_test(self, changes, blamer, maintainer, changer):
+ distribution = self.factory.makeDistribution()
+ archive = self.factory.makeArchive(
+ distribution=distribution, purpose=ArchivePurpose.PRIMARY)
+ distroseries = self.factory.makeDistroSeries(
+ distribution=distribution)
+ # Now set the uploaders.
+ component = getUtility(IComponentSet).ensure('main')
+ if component not in distroseries.components:
+ store = Store.of(distroseries)
+ store.add(
+ ComponentSelection(
+ distroseries=distroseries, component=component))
+ archive.newComponentUploader(maintainer, component)
+ archive.newComponentUploader(changer, component)
+ return get_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)
+>>>>>>> MERGE-SOURCE