Beispiel #1
0
 def test_notify_from_person_override_with_unicode_names(self):
     # notify() takes an optional from_person to override the calculated
     # From: address in announcement emails. Non-ASCII real names should be
     # correctly encoded in the From heade.
     spr = self.factory.makeSourcePackageRelease()
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     from_person = self.factory.makePerson(email="*****@*****.**",
                                           displayname=u"Loïc Motörhead")
     notify(blamer,
            spr, [], [],
            archive,
            distroseries,
            pocket,
            action='accepted',
            announce_from_person=from_person)
     notifications = pop_notifications()
     self.assertEqual(2, len(notifications))
     # The first notification is to the blamer, the second notification is
     # to the announce list, which is the one that gets the overridden
     # From:
     self.assertEqual(
         "=?utf-8?q?Lo=C3=AFc_Mot=C3=B6rhead?= <*****@*****.**>",
         notifications[1]["From"])
Beispiel #2
0
 def test_notify_from_person_override(self):
     # notify() takes an optional from_person to override the calculated
     # From: address in announcement emails.
     spr = self.factory.makeSourcePackageRelease()
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     from_person = self.factory.makePerson(email="*****@*****.**",
                                           displayname="Lemmy Kilmister")
     notify(blamer,
            spr, [], [],
            archive,
            distroseries,
            pocket,
            action='accepted',
            announce_from_person=from_person)
     notifications = pop_notifications()
     self.assertEqual(2, len(notifications))
     # The first notification is to the blamer, the second notification is
     # to the announce list, which is the one that gets the overridden
     # From:
     self.assertEqual("Lemmy Kilmister <*****@*****.**>",
                      notifications[1]["From"])
Beispiel #3
0
 def test_reject_with_no_changes(self):
     # If we don't have any files and no changes content, nothing happens.
     archive = self.factory.makeArchive()
     distroseries = self.factory.makeDistroSeries()
     pocket = self.factory.getAnyPocket()
     notify(None, None, (), (), archive, distroseries, pocket)
     notifications = pop_notifications()
     self.assertEqual(0, len(notifications))
 def test_reject_with_no_changes(self):
     # If we don't have any files and no changes content, nothing happens.
     archive = self.factory.makeArchive()
     distroseries = self.factory.makeDistroSeries()
     pocket = self.factory.getAnyPocket()
     notify(None, None, (), (), archive, distroseries, pocket)
     notifications = pop_notifications()
     self.assertEqual(0, len(notifications))
 def test_notify_bpr(self):
     # If we notify about an accepted bpr with no source, it is from a
     # build, and no notification is sent.
     bpr = self.factory.makeBinaryPackageRelease()
     archive = self.factory.makeArchive()
     pocket = self.factory.getAnyPocket()
     distroseries = self.factory.makeDistroSeries()
     person = self.factory.makePerson()
     notify(
         person, None, [bpr], [], archive, distroseries, pocket,
         action='accepted')
     notifications = pop_notifications()
     self.assertEqual(0, len(notifications))
Beispiel #6
0
 def test_notify_bpr(self):
     # If we notify about an accepted bpr with no source, it is from a
     # build, and no notification is sent.
     bpr = self.factory.makeBinaryPackageRelease()
     archive = self.factory.makeArchive()
     pocket = self.factory.getAnyPocket()
     distroseries = self.factory.makeDistroSeries()
     person = self.factory.makePerson()
     notify(person,
            None, [bpr], [],
            archive,
            distroseries,
            pocket,
            action='accepted')
     notifications = pop_notifications()
     self.assertEqual(0, len(notifications))
 def _setup_notification(self, from_person=None, distroseries=None,
                         spr=None):
     if spr is None:
         spr = self.factory.makeSourcePackageRelease()
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     if distroseries is None:
         distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     if from_person is None:
         from_person = self.factory.makePerson()
     notify(
         blamer, spr, [], [], archive, distroseries, pocket,
         action='accepted', announce_from_person=from_person)
Beispiel #8
0
    def test_notify_bpr_rejected(self):
        # If we notify about a rejected bpr with no source, a notification is
        # sent.
        bpr = self.factory.makeBinaryPackageRelease()
        changelog = self.factory.makeChangelog(spn="foo", versions=["1.1"])
        removeSecurityProxy(
            bpr.build.source_package_release).changelog = changelog
        self.layer.txn.commit()
        person = self.factory.makePerson(name='archiver')
        archive = self.factory.makeArchive(owner=person, name='ppa')
        pocket = self.factory.getAnyPocket()
        distroseries = self.factory.makeDistroSeries()
        person = self.factory.makePerson()
        notify(person,
               None, [bpr], [],
               archive,
               distroseries,
               pocket,
               summary_text="Rejected by archive administrator.",
               action='rejected')
        [notification] = pop_notifications()
        body = notification.get_payload()[0].get_payload()
        self.assertEqual(person_to_email(person), notification['To'])
        expected_body = dedent("""\
            Rejected:
            Rejected by archive administrator.

            foo (1.1) unstable; urgency=3Dlow

              * 1.1.

            =3D=3D=3D

            If you don't understand why your files were rejected please send an email
            to [email protected] for help (requires membership).

            --
            http://launchpad.dev/~archiver/+archive/ppa
            You are receiving this email because you are the uploader of the above
            PPA package.
            """)
        self.assertEqual(expected_body, body)
 def test_notify_from_unicode_names(self):
     # People with unicode in their names should appear correctly in the
     # email and not get smashed to ASCII or otherwise transliterated.
     RANDOM_UNICODE = u"Loïc"
     creator = self.factory.makePerson(displayname=RANDOM_UNICODE)
     spr = self.factory.makeSourcePackageRelease(creator=creator)
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     notify(
         blamer, spr, [], [], archive, distroseries, pocket,
         action='accepted')
     notifications = pop_notifications()
     self.assertEqual(2, len(notifications))
     msg = notifications[1].get_payload(0)
     body = msg.get_payload(decode=True)
     self.assertIn("Loïc", body)
Beispiel #10
0
 def _setup_notification(self,
                         from_person=None,
                         distroseries=None,
                         spr=None):
     if spr is None:
         spr = self.factory.makeSourcePackageRelease()
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     if distroseries is None:
         distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     if from_person is None:
         from_person = self.factory.makePerson()
     notify(blamer,
            spr, [], [],
            archive,
            distroseries,
            pocket,
            action='accepted',
            announce_from_person=from_person)
    def test_notify_bpr_rejected(self):
        # If we notify about a rejected bpr with no source, a notification is
        # sent.
        bpr = self.factory.makeBinaryPackageRelease()
        changelog = self.factory.makeChangelog(spn="foo", versions=["1.1"])
        removeSecurityProxy(
            bpr.build.source_package_release).changelog = changelog
        self.layer.txn.commit()
        person = self.factory.makePerson(name='archiver')
        archive = self.factory.makeArchive(owner=person, name='ppa')
        pocket = self.factory.getAnyPocket()
        distroseries = self.factory.makeDistroSeries()
        person = self.factory.makePerson()
        notify(
            person, None, [bpr], [], archive, distroseries, pocket,
            summary_text="Rejected by archive administrator.",
            action='rejected')
        [notification] = pop_notifications()
        body = notification.get_payload()[0].get_payload()
        self.assertEqual(person_to_email(person), notification['To'])
        expected_body = dedent("""\
            Rejected:
            Rejected by archive administrator.

            foo (1.1) unstable; urgency=3Dlow

              * 1.1.

            =3D=3D=3D

            If you don't understand why your files were rejected please send an email
            to [email protected] for help (requires membership).

            --
            http://launchpad.dev/~archiver/+archive/ppa
            You are receiving this email because you are the uploader of the above
            PPA package.
            """)
        self.assertEqual(expected_body, body)
 def test_notify_from_person_override(self):
     # notify() takes an optional from_person to override the calculated
     # From: address in announcement emails.
     spr = self.factory.makeSourcePackageRelease()
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     from_person = self.factory.makePerson(
         email="*****@*****.**", displayname="Lemmy Kilmister")
     notify(
         blamer, spr, [], [], archive, distroseries, pocket,
         action='accepted', announce_from_person=from_person)
     notifications = pop_notifications()
     self.assertEqual(2, len(notifications))
     # The first notification is to the blamer, the second notification is
     # to the announce list, which is the one that gets the overridden
     # From:
     self.assertEqual(
         "Lemmy Kilmister <*****@*****.**>", notifications[1]["From"])
Beispiel #13
0
 def test_notify_from_unicode_names(self):
     # People with unicode in their names should appear correctly in the
     # email and not get smashed to ASCII or otherwise transliterated.
     RANDOM_UNICODE = u"Loïc"
     creator = self.factory.makePerson(displayname=RANDOM_UNICODE)
     spr = self.factory.makeSourcePackageRelease(creator=creator)
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     notify(blamer,
            spr, [], [],
            archive,
            distroseries,
            pocket,
            action='accepted')
     notifications = pop_notifications()
     self.assertEqual(2, len(notifications))
     msg = notifications[1].get_payload(0)
     body = msg.get_payload(decode=True)
     self.assertIn("Loïc", body)
 def test_notify_from_person_override_with_unicode_names(self):
     # notify() takes an optional from_person to override the calculated
     # From: address in announcement emails. Non-ASCII real names should be
     # correctly encoded in the From heade.
     spr = self.factory.makeSourcePackageRelease()
     self.factory.makeSourcePackageReleaseFile(sourcepackagerelease=spr)
     archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
     pocket = PackagePublishingPocket.RELEASE
     distroseries = self.factory.makeDistroSeries()
     distroseries.changeslist = "*****@*****.**"
     blamer = self.factory.makePerson()
     from_person = self.factory.makePerson(
         email="*****@*****.**", displayname=u"Loïc Motörhead")
     notify(
         blamer, spr, [], [], archive, distroseries, pocket,
         action='accepted', announce_from_person=from_person)
     notifications = pop_notifications()
     self.assertEqual(2, len(notifications))
     # The first notification is to the blamer, the second notification is
     # to the announce list, which is the one that gets the overridden
     # From:
     self.assertEqual(
         "=?utf-8?q?Lo=C3=AFc_Mot=C3=B6rhead?= <*****@*****.**>",
         notifications[1]["From"])
Beispiel #15
0
def do_copy(sources,
            archive,
            series,
            pocket,
            include_binaries=False,
            person=None,
            check_permissions=True,
            overrides=None,
            send_email=False,
            strict_binaries=True,
            close_bugs=True,
            create_dsd_job=True,
            announce_from_person=None,
            sponsored=None,
            packageupload=None,
            unembargo=False,
            phased_update_percentage=None,
            logger=None):
    """Perform the complete copy of the given sources incrementally.

    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 responsible for rolling
    back the transaction.  Otherwise, performed copies will be commited.

    Wrapper for `do_direct_copy`.

    :param sources: a list of `ISourcePackagePublishingHistory`.
    :param archive: the target `IArchive`.
    :param series: the target `IDistroSeries`, if None is given the same
        current source distroseries will be used as destination.
    :param pocket: the target `PackagePublishingPocket`.
    :param include_binaries: optional boolean, controls whether or
        not the published binaries for each given source should be also
        copied along with the source.
    :param person: the requester `IPerson`.
    :param check_permissions: boolean indicating whether or not the
        requester's permissions to copy should be checked.
    :param overrides: A list of `IOverride` as returned from one of the copy
        policies which will be used as a manual override insyead of using the
        default override returned by IArchive.getOverridePolicy().  There
        must be the same number of overrides as there are sources and each
        override must be for the corresponding source in the sources list.
    :param send_email: Should we notify for the copy performed?
        NOTE: If running in zopeless mode, the email is sent even if the
        transaction is later aborted. (See bug 29744)
    :param announce_from_person: If send_email is True,
        then send announcement emails with this person as the From:
    :param strict_binaries: If 'include_binaries' is True then setting this
        to True will make the copy fail if binaries cannot be also copied.
    :param close_bugs: A boolean indicating whether or not bugs on the
        copied publications should be closed.
    :param create_dsd_job: A boolean indicating whether or not a dsd job
         should be created for the new source publication.
    :param sponsored: An `IPerson` representing the person who is
        being sponsored for this copy. May be None, but if present will
        affect the "From:" address on notifications and the creator of the
        publishing record will be set to this person.
    :param packageupload: The `IPackageUpload` that caused this publication
        to be created.
    :param unembargo: If True, allow copying restricted files from a private
        archive to a public archive, and unrestrict their library files when
        doing so.
    :param phased_update_percentage: The phased update percentage to apply
        to the copied publication.
    :param logger: An optional logger.

    :raise CannotCopy when one or more copies were not allowed. The error
        will contain the reason why each copy was denied.

    :return: a list of `ISourcePackagePublishingHistory` and
        `BinaryPackagePublishingHistory` corresponding to the copied
        publications.
    """
    copies = []
    errors = []
    copy_checker = CopyChecker(archive,
                               include_binaries,
                               strict_binaries=strict_binaries,
                               unembargo=unembargo)

    for source in sources:
        if series is None:
            destination_series = source.distroseries
        else:
            destination_series = series
        try:
            copy_checker.checkCopy(source, destination_series, pocket, person,
                                   check_permissions)
        except CannotCopy as reason:
            errors.append("%s (%s)" % (source.displayname, reason))
            continue

    if len(errors) != 0:
        error_text = "\n".join(errors)
        if send_email:
            source = sources[0]
            # Although the interface allows multiple sources to be copied
            # at once, we can only send rejection email if a single source
            # is specified for now.  This is only relied on by packagecopyjob
            # which will only process one package at a time.  We need to
            # make the notification code handle atomic rejections such that
            # it notifies about multiple packages.
            if series is None:
                series = source.distroseries
            # In zopeless mode this email will be sent immediately.
            notify(person,
                   source.sourcepackagerelease, [], [],
                   archive,
                   series,
                   pocket,
                   summary_text=error_text,
                   action='rejected')
        raise CannotCopy(error_text)

    overrides_index = 0
    for source in copy_checker.getCheckedCopies():
        if series is None:
            destination_series = source.distroseries
        else:
            destination_series = series
        override = None
        if overrides:
            override = overrides[overrides_index]
        # Make a note of the destination source's version for use in sending
        # the email notification and closing bugs.
        existing = archive.getPublishedSources(
            name=source.sourcepackagerelease.name,
            exact_match=True,
            status=active_publishing_status,
            distroseries=series,
            pocket=pocket).first()
        if existing:
            old_version = existing.sourcepackagerelease.version
        else:
            old_version = None
        if sponsored is not None:
            announce_from_person = sponsored
            creator = sponsored
            sponsor = person
        else:
            creator = person
            sponsor = None
        sub_copies = _do_direct_copy(
            source,
            archive,
            destination_series,
            pocket,
            include_binaries,
            override,
            close_bugs=close_bugs,
            create_dsd_job=create_dsd_job,
            close_bugs_since_version=old_version,
            creator=creator,
            sponsor=sponsor,
            packageupload=packageupload,
            phased_update_percentage=phased_update_percentage,
            logger=logger)
        if send_email:
            notify(person,
                   source.sourcepackagerelease, [], [],
                   archive,
                   destination_series,
                   pocket,
                   action='accepted',
                   announce_from_person=announce_from_person,
                   previous_version=old_version)
        if not archive.private and has_restricted_files(source):
            # Fix copies by unrestricting files with privacy mismatch.
            # We must do this *after* calling notify (which only
            # actually sends mail on commit), because otherwise the new
            # changelog LFA won't be visible without a commit, which may
            # not be safe here.
            for pub_record in sub_copies:
                for changed_file in update_files_privacy(pub_record):
                    if logger is not None:
                        logger.info("Made %s public" % changed_file.filename)

        overrides_index += 1
        copies.extend(sub_copies)

    return copies
def do_copy(sources, archive, series, pocket, include_binaries=False,
            person=None, check_permissions=True, overrides=None,
            send_email=False, strict_binaries=True, close_bugs=True,
            create_dsd_job=True, announce_from_person=None, sponsored=None,
            packageupload=None, unembargo=False, phased_update_percentage=None,
            logger=None):
    """Perform the complete copy of the given sources incrementally.

    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 responsible for rolling
    back the transaction.  Otherwise, performed copies will be commited.

    Wrapper for `do_direct_copy`.

    :param sources: a list of `ISourcePackagePublishingHistory`.
    :param archive: the target `IArchive`.
    :param series: the target `IDistroSeries`, if None is given the same
        current source distroseries will be used as destination.
    :param pocket: the target `PackagePublishingPocket`.
    :param include_binaries: optional boolean, controls whether or
        not the published binaries for each given source should be also
        copied along with the source.
    :param person: the requester `IPerson`.
    :param check_permissions: boolean indicating whether or not the
        requester's permissions to copy should be checked.
    :param overrides: A list of `IOverride` as returned from one of the copy
        policies which will be used as a manual override insyead of using the
        default override returned by IArchive.getOverridePolicy().  There
        must be the same number of overrides as there are sources and each
        override must be for the corresponding source in the sources list.
    :param send_email: Should we notify for the copy performed?
        NOTE: If running in zopeless mode, the email is sent even if the
        transaction is later aborted. (See bug 29744)
    :param announce_from_person: If send_email is True,
        then send announcement emails with this person as the From:
    :param strict_binaries: If 'include_binaries' is True then setting this
        to True will make the copy fail if binaries cannot be also copied.
    :param close_bugs: A boolean indicating whether or not bugs on the
        copied publications should be closed.
    :param create_dsd_job: A boolean indicating whether or not a dsd job
         should be created for the new source publication.
    :param sponsored: An `IPerson` representing the person who is
        being sponsored for this copy. May be None, but if present will
        affect the "From:" address on notifications and the creator of the
        publishing record will be set to this person.
    :param packageupload: The `IPackageUpload` that caused this publication
        to be created.
    :param unembargo: If True, allow copying restricted files from a private
        archive to a public archive, and unrestrict their library files when
        doing so.
    :param phased_update_percentage: The phased update percentage to apply
        to the copied publication.
    :param logger: An optional logger.

    :raise CannotCopy when one or more copies were not allowed. The error
        will contain the reason why each copy was denied.

    :return: a list of `ISourcePackagePublishingHistory` and
        `BinaryPackagePublishingHistory` corresponding to the copied
        publications.
    """
    copies = []
    errors = []
    copy_checker = CopyChecker(
        archive, include_binaries, strict_binaries=strict_binaries,
        unembargo=unembargo)

    for source in sources:
        if series is None:
            destination_series = source.distroseries
        else:
            destination_series = series
        try:
            copy_checker.checkCopy(
                source, destination_series, pocket, person, check_permissions)
        except CannotCopy as reason:
            errors.append("%s (%s)" % (source.displayname, reason))
            continue

    if len(errors) != 0:
        error_text = "\n".join(errors)
        if send_email:
            source = sources[0]
            # Although the interface allows multiple sources to be copied
            # at once, we can only send rejection email if a single source
            # is specified for now.  This is only relied on by packagecopyjob
            # which will only process one package at a time.  We need to
            # make the notification code handle atomic rejections such that
            # it notifies about multiple packages.
            if series is None:
                series = source.distroseries
            # In zopeless mode this email will be sent immediately.
            notify(
                person, source.sourcepackagerelease, [], [], archive,
                series, pocket, summary_text=error_text, action='rejected')
        raise CannotCopy(error_text)

    overrides_index = 0
    for source in copy_checker.getCheckedCopies():
        if series is None:
            destination_series = source.distroseries
        else:
            destination_series = series
        override = None
        if overrides:
            override = overrides[overrides_index]
        # Make a note of the destination source's version for use in sending
        # the email notification and closing bugs.
        existing = archive.getPublishedSources(
            name=source.sourcepackagerelease.name, exact_match=True,
            status=active_publishing_status, distroseries=series,
            pocket=pocket).first()
        if existing:
            old_version = existing.sourcepackagerelease.version
        else:
            old_version = None
        if sponsored is not None:
            announce_from_person = sponsored
            creator = sponsored
            sponsor = person
        else:
            creator = person
            sponsor = None
        sub_copies = _do_direct_copy(
            source, archive, destination_series, pocket, include_binaries,
            override, close_bugs=close_bugs, create_dsd_job=create_dsd_job,
            close_bugs_since_version=old_version, creator=creator,
            sponsor=sponsor, packageupload=packageupload,
            phased_update_percentage=phased_update_percentage, logger=logger)
        if send_email:
            notify(
                person, source.sourcepackagerelease, [], [], archive,
                destination_series, pocket, action='accepted',
                announce_from_person=announce_from_person,
                previous_version=old_version)
        if not archive.private and has_restricted_files(source):
            # Fix copies by unrestricting files with privacy mismatch.
            # We must do this *after* calling notify (which only
            # actually sends mail on commit), because otherwise the new
            # changelog LFA won't be visible without a commit, which may
            # not be safe here.
            for pub_record in sub_copies:
                for changed_file in update_files_privacy(pub_record):
                    if logger is not None:
                        logger.info("Made %s public" % changed_file.filename)

        overrides_index += 1
        copies.extend(sub_copies)

    return copies