[Launchpad-reviewers] [Merge] ~pappacena/launchpad:oci-project-of-project-git-namespace into launchpad:master

2020-12-09 Thread Thiago F. Pappacena
Thiago F. Pappacena has proposed merging 
~pappacena/launchpad:oci-project-of-project-git-namespace into launchpad:master.

Commit message:
Adding support for GitNamespace of OCIProjects based on projects (not only 
distribution)

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/395110
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
~pappacena/launchpad:oci-project-of-project-git-namespace into launchpad:master.
diff --git a/lib/lp/code/model/gitlookup.py b/lib/lp/code/model/gitlookup.py
index a59134d..d4641ca 100644
--- a/lib/lp/code/model/gitlookup.py
+++ b/lib/lp/code/model/gitlookup.py
@@ -142,6 +142,19 @@ class ProjectGitTraversable(_BaseGitTraversable):
 From here, you can traverse to a named project repository.
 """
 
+def traverse(self, owner, name, segments):
+if name == "+oci":
+try:
+spn_name = next(segments)
+except StopIteration:
+raise InvalidNamespace("/".join(segments.traversed))
+oci_project = self.context.getOCIProject(spn_name)
+if oci_project is None:
+raise NoSuchOCIProjectName(spn_name)
+return owner, oci_project, None
+return super(ProjectGitTraversable, self).traverse(
+owner, name, segments)
+
 def getNamespace(self, owner):
 return getUtility(IGitNamespaceSet).get(owner, project=self.context)
 
diff --git a/lib/lp/code/model/tests/test_gitlookup.py b/lib/lp/code/model/tests/test_gitlookup.py
index d527b06..69f209b 100644
--- a/lib/lp/code/model/tests/test_gitlookup.py
+++ b/lib/lp/code/model/tests/test_gitlookup.py
@@ -1,4 +1,4 @@
-# Copyright 2015-2018 Canonical Ltd.  This software is licensed under the
+# Copyright 2015-2020 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Tests for the IGitLookup implementation."""
@@ -242,8 +242,8 @@ class TestGetByUrl(TestCaseWithFactory):
 def test_getByUrl_with_trailing_segments(self):
 # URLs with trailing segments beyond the repository are rejected.
 self.makeProjectRepository()
-self.assertIsNone(
-self.lookup.getByUrl("git://git.launchpad.test/~aa/bb/+git/cc/foo"))
+self.assertIsNone(self.lookup.getByUrl(
+"git://git.launchpad.test/~aa/bb/+git/cc/foo"))
 
 def test_getByUrl_with_git(self):
 # getByUrl recognises LP repositories for git URLs.
@@ -410,6 +410,16 @@ class TestGitTraverser(TestCaseWithFactory):
 path = "%s/+oci/%s" % (oci_project.pillar.name, oci_project.name)
 self.assertTraverses(path, None, oci_project)
 
+def test_ociproject_based_on_project(self):
+# `traverse_path` resolves '~person/product/+oci/ociproject' to the OCI
+# project.
+project = self.factory.makeProduct()
+oci_project = self.factory.makeOCIProject(pillar=project)
+path = "~%s/%s/+oci/%s" % (
+oci_project.registrant.name, oci_project.pillar.name,
+oci_project.name)
+self.assertTraverses(path, oci_project.registrant, oci_project)
+
 def test_ociproject_no_named_repositories(self):
 # OCI projects do not have named repositories without an owner
 # context, so trying to traverse to them raises `InvalidNamespace`.
___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


[Launchpad-reviewers] [Merge] ~pappacena/launchpad:stormify-announcement into launchpad:master

2020-12-09 Thread Thiago F. Pappacena
Thiago F. Pappacena has proposed merging 
~pappacena/launchpad:stormify-announcement into launchpad:master.

Commit message:
Converting Announcements to Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/395106
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
~pappacena/launchpad:stormify-announcement into launchpad:master.
diff --git a/lib/lp/registry/model/announcement.py b/lib/lp/registry/model/announcement.py
index 45b5740..a2c9ac9 100644
--- a/lib/lp/registry/model/announcement.py
+++ b/lib/lp/registry/model/announcement.py
@@ -11,12 +11,21 @@ __all__ = [
 'MakesAnnouncements',
 ]
 
-from sqlobject import (
-BoolCol,
-ForeignKey,
-SQLObjectNotFound,
-StringCol,
+import pytz
+import six
+from storm.expr import (
+And,
+LeftJoin,
+Or,
+Select,
 )
+from storm.properties import (
+Bool,
+DateTime,
+Int,
+Unicode,
+)
+from storm.references import Reference
 from zope.interface import implementer
 
 from lp.registry.interfaces.announcement import (
@@ -28,40 +37,72 @@ from lp.registry.interfaces.person import validate_public_person
 from lp.registry.interfaces.product import IProduct
 from lp.registry.interfaces.projectgroup import IProjectGroup
 from lp.services.database.constants import UTC_NOW
-from lp.services.database.datetimecol import UtcDateTimeCol
-from lp.services.database.sqlbase import (
-SQLBase,
-sqlvalues,
+from lp.services.database.interfaces import (
+IMasterStore,
+IStore,
 )
+from lp.services.database.stormbase import StormBase
 from lp.services.utils import utc_now
 
 
 @implementer(IAnnouncement)
-class Announcement(SQLBase):
+class Announcement(StormBase):
 """A news item. These allow us to generate lists of recent news for
 project groups, products and distributions.
 """
 
-_defaultOrder = ['-date_announced', '-date_created']
-
-date_created = UtcDateTimeCol(
-dbName='date_created', notNull=True, default=UTC_NOW)
-date_announced = UtcDateTimeCol(default=None)
-date_last_modified = UtcDateTimeCol(
-dbName='date_updated', default=None)
-registrant = ForeignKey(
-dbName='registrant', foreignKey='Person',
-storm_validator=validate_public_person, notNull=True)
-product = ForeignKey(dbName='product', foreignKey='Product')
-projectgroup = ForeignKey(dbName='project', foreignKey='ProjectGroup')
-distribution = ForeignKey(
-dbName='distribution', foreignKey='Distribution')
-title = StringCol(notNull=True)
-summary = StringCol(default=None)
-url = StringCol(default=None)
-active = BoolCol(notNull=True, default=True)
+__storm_table__ = 'Announcement'
+
+__storm_order__ = ('-date_announced', '-date_created')
+
+id = Int(primary=True)
+
+date_created = DateTime(allow_none=False, default=UTC_NOW, tzinfo=pytz.UTC)
+date_announced = DateTime(allow_none=True, default=None, tzinfo=pytz.UTC)
+date_last_modified = DateTime(
+name='date_updated', allow_none=True, default=None, tzinfo=pytz.UTC)
+
+registrant_id = Int(
+name="registrant", allow_none=False, validator=validate_public_person)
+registrant = Reference(registrant_id, "Person.id")
+
+product_id = Int(name="product", allow_none=True, default=None)
+product = Reference(product_id, "Product.id")
+
+projectgroup_id = Int(name="project", allow_none=True, default=None)
+projectgroup = Reference(projectgroup_id, "ProjectGroup.id")
+
+distribution_id = Int(name="distribution", allow_none=True, default=None)
+distribution = Reference(distribution_id, "Distribution.id")
+
+title = Unicode(allow_none=False)
+summary = Unicode(allow_none=True, default=None)
+url = Unicode(allow_none=True, default=None)
+active = Bool(allow_none=False, default=True)
+
+def __init__(self, registrant, title, summary=None, url=None,
+ active=True, date_created=UTC_NOW, date_announced=None,
+ date_last_modified=None, product=None, projectgroup=None,
+ distribution=None):
+self.registrant = registrant
+self.title = title
+self.summary = summary
+self.url = url
+self.active = active
+self.date_created = date_created
+self.date_announced = date_announced
+self.date_last_modified = date_last_modified
+self.product = product
+self.projectgroup = projectgroup
+self.distribution = distribution
+
+def destroySelf(self):
+IMasterStore(self).remove(self)
 
 def modify(self, title, summary, url):
+title = six.text_type(title) if title is not None else None
+summary = six.text_type(summary) if summary is not None else None
+url = six.text_type(url) if url is not None else None
 if 

Re: [Launchpad-reviewers] [Merge] ~pappacena/launchpad:bugtask-oci-project into launchpad:master

2020-12-09 Thread Colin Watson
Review: Approve

Looks mostly good to me, aside from the possible BugSummary issue I mentioned 
in https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/393460.

Diff comments:

> diff --git a/lib/lp/registry/interfaces/ociproject.py 
> b/lib/lp/registry/interfaces/ociproject.py
> index 82ba8ad..a189654 100644
> --- a/lib/lp/registry/interfaces/ociproject.py
> +++ b/lib/lp/registry/interfaces/ociproject.py
> @@ -189,7 +202,8 @@ class IOCIProjectLegitimate(Interface):
>  @exported_as_webservice_entry(
>  publish_web_link=True, as_of="devel", singular_name="oci_project")
>  class IOCIProject(IOCIProjectView, IOCIProjectEdit,
> -  IOCIProjectEditableAttributes, IOCIProjectLegitimate):
> +  IOCIProjectEditableAttributes, IOCIProjectLegitimate,
> +  IHasBugSupervisor, IHasExpirableBugs):

I'm not sure IHasExpirableBugs is quite right yet - you haven't edited 
lp.bugs.browser.buglisting.target_has_expirable_bugs_listing, at least.  Maybe 
that belongs in a separate MP?

>  """A project containing Open Container Initiative recipes."""
>  
>  


-- 
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/393570
Your team Launchpad code reviewers is subscribed to branch 
~pappacena/launchpad:stormify-bug-task.

___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


Re: [Launchpad-reviewers] [Merge] ~pappacena/launchpad:oci-bug-add-oci-columns into launchpad:db-devel

2020-12-09 Thread Colin Watson



Diff comments:

> diff --git a/database/schema/patch-2210-22-0.sql 
> b/database/schema/patch-2210-22-0.sql
> new file mode 100644
> index 000..e1dd712
> --- /dev/null
> +++ b/database/schema/patch-2210-22-0.sql
> @@ -0,0 +1,488 @@
> +-- Copyright 2020 Canonical Ltd.  This software is licensed under the
> +-- GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +SET client_min_messages=ERROR;
> +
> +-- This patch can be applied "cold", in a "fast-downtime" way. It basically
> +-- adds the new OCI database columns, and rename current indexes so they can 
> be
> +-- removed and replaced with new ones that includes the new columns.
> +
> +ALTER TABLE BugTask
> +ADD COLUMN ociproject integer REFERENCES ociproject,
> +ADD COLUMN ociprojectseries integer REFERENCES ociprojectseries,
> +DROP CONSTRAINT bugtask_assignment_checks,
> +ADD CONSTRAINT bugtask_assignment_checks CHECK (
> +CASE
> +WHEN product IS NOT NULL THEN productseries IS NULL AND 
> distribution IS NULL AND distroseries IS NULL AND sourcepackagename IS NULL
> +WHEN productseries IS NOT NULL THEN distribution IS NULL AND 
> distroseries IS NULL AND sourcepackagename IS NULL AND ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN distribution IS NOT NULL THEN distroseries IS NULL
> +WHEN distroseries IS NOT NULL THEN ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN ociproject IS NOT NULL THEN ociprojectseries IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +WHEN ociprojectseries IS NOT NULL THEN ociproject IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +ELSE false
> +END) NOT VALID;
> +
> +ALTER INDEX bugtask_distinct_sourcepackage_assignment
> +RENAME TO old__bugtask_distinct_sourcepackage_assignment;
> +
> +ALTER INDEX bugtask__product__bug__key
> +RENAME TO old__bugtask__product__bug__key;
> +
> +ALTER TABLE BugTaskFlat
> +ADD COLUMN ociproject integer,
> +ADD COLUMN ociprojectseries integer;
> +
> +ALTER TABLE BugSummary
> +ADD COLUMN ociproject integer REFERENCES ociproject,
> +ADD COLUMN ociprojectseries integer REFERENCES ociprojectseries,
> +DROP CONSTRAINT bugtask_assignment_checks,
> +ADD CONSTRAINT bugtask_assignment_checks CHECK (
> +CASE
> +WHEN product IS NOT NULL THEN productseries IS NULL AND 
> distribution IS NULL AND distroseries IS NULL AND sourcepackagename IS NULL
> +WHEN productseries IS NOT NULL THEN distribution IS NULL AND 
> distroseries IS NULL AND sourcepackagename IS NULL AND ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN distribution IS NOT NULL THEN distroseries IS NULL
> +WHEN distroseries IS NOT NULL THEN ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN ociproject IS NOT NULL THEN ociprojectseries IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +WHEN ociprojectseries IS NOT NULL THEN ociproject IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +ELSE false
> +END) NOT VALID;
> +
> +ALTER INDEX bugsummary__unique
> +RENAME TO old__bugsummary__unique;
> +
> +ALTER TABLE BugSummaryJournal
> +ADD COLUMN ociproject integer,
> +ADD COLUMN ociprojectseries integer;
> +
> +-- Functions
> +
> +CREATE OR REPLACE FUNCTION bugtask_flatten(task_id integer, check_only 
> boolean)
> +RETURNS boolean
> +LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
> +AS $$
> +DECLARE
> +bug_row Bug%ROWTYPE;
> +task_row BugTask%ROWTYPE;
> +old_flat_row BugTaskFlat%ROWTYPE;
> +new_flat_row BugTaskFlat%ROWTYPE;
> +_product_active boolean;
> +_access_policies integer[];
> +_access_grants integer[];
> +BEGIN
> +-- This is the master function to update BugTaskFlat, but there are
> +-- maintenance triggers and jobs on the involved tables that update
> +-- it directly. Any changes here probably require a corresponding
> +-- change in other trigger functions.
> +
> +SELECT * INTO task_row FROM BugTask WHERE id = task_id;
> +SELECT * INTO old_flat_row FROM BugTaskFlat WHERE bugtask = task_id;
> +
> +-- If the task doesn't exist, ensure that there's no flat row.
> +IF task_row.id IS NULL THEN
> +IF old_flat_row.bugtask IS NOT NULL THEN
> +IF NOT check_only THEN
> +DELETE FROM BugTaskFlat WHERE bugtask = task_id;
> +END IF;
> +RETURN FALSE;
> +ELSE
> +RETURN TRUE;
> +END IF;
> +END IF;
> +
> +SELECT * FROM bug INTO bug_row WHERE id = task_row.bug;
> +
> +-- If it's a product(series) task, we must consult the active flag.
> +IF task_row.product IS NOT NULL THEN
> +SELECT product.active INTO _product_active
> +FROM product WHERE product.id = task_row.product 

Re: [Launchpad-reviewers] [Merge] ~pappacena/launchpad:oci-bug-add-oci-columns into launchpad:db-devel

2020-12-09 Thread Colin Watson



Diff comments:

> diff --git a/database/schema/patch-2210-22-0.sql 
> b/database/schema/patch-2210-22-0.sql
> new file mode 100644
> index 000..e1dd712
> --- /dev/null
> +++ b/database/schema/patch-2210-22-0.sql
> @@ -0,0 +1,488 @@
> +-- Copyright 2020 Canonical Ltd.  This software is licensed under the
> +-- GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +SET client_min_messages=ERROR;
> +
> +-- This patch can be applied "cold", in a "fast-downtime" way. It basically
> +-- adds the new OCI database columns, and rename current indexes so they can 
> be
> +-- removed and replaced with new ones that includes the new columns.
> +
> +ALTER TABLE BugTask
> +ADD COLUMN ociproject integer REFERENCES ociproject,
> +ADD COLUMN ociprojectseries integer REFERENCES ociprojectseries,
> +DROP CONSTRAINT bugtask_assignment_checks,
> +ADD CONSTRAINT bugtask_assignment_checks CHECK (
> +CASE
> +WHEN product IS NOT NULL THEN productseries IS NULL AND 
> distribution IS NULL AND distroseries IS NULL AND sourcepackagename IS NULL
> +WHEN productseries IS NOT NULL THEN distribution IS NULL AND 
> distroseries IS NULL AND sourcepackagename IS NULL AND ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN distribution IS NOT NULL THEN distroseries IS NULL
> +WHEN distroseries IS NOT NULL THEN ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN ociproject IS NOT NULL THEN ociprojectseries IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +WHEN ociprojectseries IS NOT NULL THEN ociproject IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +ELSE false
> +END) NOT VALID;
> +
> +ALTER INDEX bugtask_distinct_sourcepackage_assignment
> +RENAME TO old__bugtask_distinct_sourcepackage_assignment;
> +
> +ALTER INDEX bugtask__product__bug__key
> +RENAME TO old__bugtask__product__bug__key;
> +
> +ALTER TABLE BugTaskFlat
> +ADD COLUMN ociproject integer,
> +ADD COLUMN ociprojectseries integer;
> +
> +ALTER TABLE BugSummary
> +ADD COLUMN ociproject integer REFERENCES ociproject,
> +ADD COLUMN ociprojectseries integer REFERENCES ociprojectseries,
> +DROP CONSTRAINT bugtask_assignment_checks,
> +ADD CONSTRAINT bugtask_assignment_checks CHECK (
> +CASE
> +WHEN product IS NOT NULL THEN productseries IS NULL AND 
> distribution IS NULL AND distroseries IS NULL AND sourcepackagename IS NULL
> +WHEN productseries IS NOT NULL THEN distribution IS NULL AND 
> distroseries IS NULL AND sourcepackagename IS NULL AND ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN distribution IS NOT NULL THEN distroseries IS NULL
> +WHEN distroseries IS NOT NULL THEN ociproject IS NULL AND 
> ociprojectseries IS NULL
> +WHEN ociproject IS NOT NULL THEN ociprojectseries IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +WHEN ociprojectseries IS NOT NULL THEN ociproject IS NULL AND 
> (distribution IS NOT NULL OR product IS NOT NULL)
> +ELSE false
> +END) NOT VALID;
> +
> +ALTER INDEX bugsummary__unique
> +RENAME TO old__bugsummary__unique;
> +
> +ALTER TABLE BugSummaryJournal
> +ADD COLUMN ociproject integer,
> +ADD COLUMN ociprojectseries integer;
> +
> +-- Functions
> +
> +CREATE OR REPLACE FUNCTION bugtask_flatten(task_id integer, check_only 
> boolean)
> +RETURNS boolean
> +LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
> +AS $$
> +DECLARE
> +bug_row Bug%ROWTYPE;
> +task_row BugTask%ROWTYPE;
> +old_flat_row BugTaskFlat%ROWTYPE;
> +new_flat_row BugTaskFlat%ROWTYPE;
> +_product_active boolean;
> +_access_policies integer[];
> +_access_grants integer[];
> +BEGIN
> +-- This is the master function to update BugTaskFlat, but there are
> +-- maintenance triggers and jobs on the involved tables that update
> +-- it directly. Any changes here probably require a corresponding
> +-- change in other trigger functions.
> +
> +SELECT * INTO task_row FROM BugTask WHERE id = task_id;
> +SELECT * INTO old_flat_row FROM BugTaskFlat WHERE bugtask = task_id;
> +
> +-- If the task doesn't exist, ensure that there's no flat row.
> +IF task_row.id IS NULL THEN
> +IF old_flat_row.bugtask IS NOT NULL THEN
> +IF NOT check_only THEN
> +DELETE FROM BugTaskFlat WHERE bugtask = task_id;
> +END IF;
> +RETURN FALSE;
> +ELSE
> +RETURN TRUE;
> +END IF;
> +END IF;
> +
> +SELECT * FROM bug INTO bug_row WHERE id = task_row.bug;
> +
> +-- If it's a product(series) task, we must consult the active flag.
> +IF task_row.product IS NOT NULL THEN
> +SELECT product.active INTO _product_active
> +FROM product WHERE product.id = task_row.product 

[Launchpad-reviewers] [Merge] ~pappacena/launchpad:bugfix-email-change-error-msg-1907173 into launchpad:master

2020-12-09 Thread Otto Co-Pilot
The proposal to merge 
~pappacena/launchpad:bugfix-email-change-error-msg-1907173 into 
launchpad:master has been updated.

Status: Approved => Merged

For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/395036
-- 
Your team Launchpad code reviewers is subscribed to branch 
~pappacena/launchpad:bugfix-email-change-error-msg-1907173.

___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


[Launchpad-reviewers] [Merge] ~pappacena/launchpad:bugfix-email-change-error-msg-1907173 into launchpad:master

2020-12-09 Thread Thiago F. Pappacena
The proposal to merge 
~pappacena/launchpad:bugfix-email-change-error-msg-1907173 into 
launchpad:master has been updated.

Status: Needs review => Approved

For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/395036
-- 
Your team Launchpad code reviewers is subscribed to branch 
~pappacena/launchpad:bugfix-email-change-error-msg-1907173.

___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


Re: [Launchpad-reviewers] [Merge] ~pappacena/launchpad:bugfix-email-change-error-msg-1907173 into launchpad:master

2020-12-09 Thread Thiago F. Pappacena



Diff comments:

> diff --git a/lib/lp/registry/browser/team.py b/lib/lp/registry/browser/team.py
> index c309d57..d10af5a 100644
> --- a/lib/lp/registry/browser/team.py
> +++ b/lib/lp/registry/browser/team.py
> @@ -520,8 +521,10 @@ class TeamContactAddressView(MailingListTeamBaseView):
>  # We need to wrap this in structured, so that the
>  # markup is preserved.  Note that this puts the
>  # responsibility for security on the exception thrower.
> -self.setFieldError('contact_address',
> -   structured(str(error)))
> +msg = error.args[0]
> +if not isinstance(msg, structured):

Ok!

> +msg = structured(six.text_type(msg))
> +self.setFieldError('contact_address', msg)
>  elif data['contact_method'] == TeamContactMethod.HOSTED_LIST:
>  mailing_list = getUtility(IMailingListSet).get(self.context.name)
>  if mailing_list is None or not mailing_list.is_usable:
> diff --git a/lib/lp/registry/browser/tests/test_team.py 
> b/lib/lp/registry/browser/tests/test_team.py
> index 672c59d..44a1d63 100644
> --- a/lib/lp/registry/browser/tests/test_team.py
> +++ b/lib/lp/registry/browser/tests/test_team.py
> @@ -967,3 +970,28 @@ class TestPersonIndexVisibilityView(TestCaseWithFactory):
>  'private team link', 'a',
>  attrs={'href': '/~private-team', 'class': 'sprite team private'},
>  text='Private Team'))
> +
> +
> +class TestTeamContactAddressView(TestCaseWithFactory):
> +
> +layer = DatabaseFunctionalLayer
> +
> +def test_team_change_contact_address_to_existing_address(self):
> +# Test that a team can change the contact address.

Ok!

> +someone_email = "some...@canonical.com"
> +someone = self.factory.makePerson(
> +displayname="Unicode Person \xc9", email=someone_email)
> +someone_url = canonical_url(someone)
> +team = self.factory.makeTeam(email="t...@canonical.com")
> +with admin_logged_in():
> +form = {
> +'field.contact_method': 'EXTERNAL_ADDRESS',
> +'field.contact_address': 'some...@canonical.com',
> +'field.actions.change': 'Change',
> +}
> +view = create_initialized_view(team, '+contactaddress', 
> form=form)
> +expected_msg = (
> +'%s is already registered in Launchpad and is associated '
> +'with Unicode Person \xc9.')
> +expected_msg %= (someone_email, someone_url)
> +self.assertEqual([expected_msg], view.errors)


-- 
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/395036
Your team Launchpad code reviewers is subscribed to branch 
~pappacena/launchpad:bugfix-email-change-error-msg-1907173.

___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


[Launchpad-reviewers] [Merge] ~cjwatson/launchpad:script-activity-statsd into launchpad:master

2020-12-09 Thread Colin Watson
Colin Watson has proposed merging ~cjwatson/launchpad:script-activity-statsd 
into launchpad:master.

Commit message:
Send script activity timings to statsd as well

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/395074

This will make it easier to add graphs, use modern alerting systems, and so on.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
~cjwatson/launchpad:script-activity-statsd into launchpad:master.
diff --git a/lib/lp/services/scripts/doc/script-monitoring.txt b/lib/lp/services/scripts/doc/script-monitoring.txt
index 9e22745..eeb3604 100644
--- a/lib/lp/services/scripts/doc/script-monitoring.txt
+++ b/lib/lp/services/scripts/doc/script-monitoring.txt
@@ -22,21 +22,38 @@ IScriptActivitySet.recordSuccess():
 >>> import socket
 >>> import subprocess
 >>> import tempfile
+>>> from textwrap import dedent
+
+>>> from fixtures import MockPatchObject
 >>> import pytz
 >>> import transaction
 >>> from zope.component import getUtility
+
+>>> from lp.services.compat import mock
+>>> from lp.services.config import config
 >>> from lp.services.scripts.interfaces.scriptactivity import (
 ... IScriptActivitySet)
+>>> from lp.services.statsd.interfaces.statsd_client import IStatsdClient
 >>> from lp.testing.dbuser import switch_dbuser
 
 >>> UTC = pytz.timezone('UTC')
 >>> switch_dbuser('garbo_daily') # A script db user
 
->>> activity = getUtility(IScriptActivitySet).recordSuccess(
-... name='script-name',
-... date_started=datetime.datetime(2007,2,1,10,0,tzinfo=UTC),
-... date_completed=datetime.datetime(2007,2,1,10,1,tzinfo=UTC),
-... hostname='script-host')
+>>> config.push('statsd_test', dedent('''
+... [statsd]
+... environment: test
+... '''))
+>>> statsd_client = getUtility(IStatsdClient)
+>>> stats_client = mock.Mock()
+
+>>> with MockPatchObject(statsd_client, '_client', stats_client):
+... activity = getUtility(IScriptActivitySet).recordSuccess(
+... name='script-name',
+... date_started=datetime.datetime(2007,2,1,10,0,tzinfo=UTC),
+... date_completed=datetime.datetime(2007,2,1,10,1,tzinfo=UTC),
+... hostname='script-host')
+
+>>> _ = config.pop('statsd_test')
 
 The activity object records the script name, the host name it ran on
 and the start and end timestamps:
@@ -50,6 +67,15 @@ and the start and end timestamps:
 >>> print(activity.date_completed)
 2007-02-01 10:01:00+00:00
 
+It sends a corresponding timing stat to statsd.
+
+>>> stats_client.timing.call_count
+1
+>>> print(stats_client.timing.call_args[0][0])
+script_activity,name=script-name,env=test
+>>> stats_client.timing.call_args[0][1]
+6.0
+
 We can also query for the last activity for a particular script, which
 will match the activity we just created:
 
diff --git a/lib/lp/services/scripts/model/scriptactivity.py b/lib/lp/services/scripts/model/scriptactivity.py
index 7984696..0df3849 100644
--- a/lib/lp/services/scripts/model/scriptactivity.py
+++ b/lib/lp/services/scripts/model/scriptactivity.py
@@ -17,6 +17,7 @@ from storm.locals import (
 Int,
 Unicode,
 )
+from zope.component import getUtility
 from zope.interface import implementer
 
 from lp.services.database.interfaces import IStore
@@ -25,6 +26,7 @@ from lp.services.scripts.interfaces.scriptactivity import (
 IScriptActivity,
 IScriptActivitySet,
 )
+from lp.services.statsd.interfaces.statsd_client import IStatsdClient
 
 
 @implementer(IScriptActivity)
@@ -58,6 +60,11 @@ class ScriptActivitySet:
 name=six.ensure_text(name), hostname=six.ensure_text(hostname),
 date_started=date_started, date_completed=date_completed)
 IStore(ScriptActivity).add(activity)
+# Pass equivalent information through to statsd as well.  (Don't
+# bother with the hostname, since telegraf adds that.)
+getUtility(IStatsdClient).timing(
+'script_activity,name={}'.format(name),
+(date_completed - date_started).total_seconds() * 1000)
 return activity
 
 def getLastActivity(self, name):
___
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp


[Launchpad-reviewers] [Merge] ~cjwatson/launchpad:stormify-translations-queries into launchpad:master

2020-12-09 Thread Colin Watson
Colin Watson has proposed merging 
~cjwatson/launchpad:stormify-translations-queries into launchpad:master with 
~cjwatson/launchpad:stormify-potranslation as a prerequisite.

Commit message:
Convert SQLObject-style queries in lp.translations to Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/395062
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
~cjwatson/launchpad:stormify-translations-queries into launchpad:master.
diff --git a/lib/lp/registry/model/distroseries.py b/lib/lp/registry/model/distroseries.py
index 2811a42..e83a7dc 100644
--- a/lib/lp/registry/model/distroseries.py
+++ b/lib/lp/registry/model/distroseries.py
@@ -178,7 +178,6 @@ from lp.translations.model.hastranslationtemplates import (
 )
 from lp.translations.model.languagepack import LanguagePack
 from lp.translations.model.pofile import POFile
-from lp.translations.model.pofiletranslator import POFileTranslator
 from lp.translations.model.potemplate import (
 POTemplate,
 TranslationTemplatesCollection,
@@ -1362,6 +1361,9 @@ class DistroSeries(SQLBase, BugTargetBase, HasSpecificationsMixin,
 
 def getPOFileContributorsByLanguage(self, language):
 """See `IDistroSeries`."""
+# Circular import.
+from lp.translations.model.pofiletranslator import POFileTranslator
+
 contributors = IStore(Person).find(
 Person,
 POFileTranslator.personID == Person.id,
diff --git a/lib/lp/translations/doc/poexport-request-productseries.txt b/lib/lp/translations/doc/poexport-request-productseries.txt
index 1978e3e..53303a2 100644
--- a/lib/lp/translations/doc/poexport-request-productseries.txt
+++ b/lib/lp/translations/doc/poexport-request-productseries.txt
@@ -7,9 +7,9 @@
 
 This is a dummy logger class to capture the export's log messages.
 
->>> from lp.registry.model.person import Person
+>>> from lp.registry.interfaces.person import IPersonSet
 >>> from lp.services.log.logger import FakeLogger
->>> person = Person.selectOneBy(name='name12')
+>>> person = getUtility(IPersonSet).getByName('name12')
 
 An arbitrary logged-in user requests an export of all translations for
 Evolution series trunk.
@@ -18,16 +18,15 @@ At the UI level, this is easy.  At the level we are looking at now, this
 consists of a series of requests for all templates and translations attached
 to the product series.
 
->>> from lp.registry.model.product import Product
->>> from lp.registry.model.productseries import ProductSeries
->>> from lp.translations.model.potemplate import POTemplate
->>> evolution_product = Product.selectOneBy(name='evolution')
->>> evolution_trunk = ProductSeries.selectOneBy(
-... product=evolution_product, name='trunk')
->>> potemplates = list(POTemplate.selectBy(productseries=evolution_trunk))
+>>> from lp.registry.interfaces.product import IProductSet
+>>> from lp.translations.interfaces.potemplate import IPOTemplateSet
+>>> evolution_product = getUtility(IProductSet).getByName('evolution')
+>>> evolution_trunk = evolution_product.getSeries('trunk')
+>>> potemplates = list(getUtility(IPOTemplateSet).getSubset(
+... productseries=evolution_trunk))
 >>> pofiles = []
 >>> for template in potemplates:
-... pofiles += template.pofiles
+... pofiles.extend(template.pofiles)
 
 >>> request_set = getUtility(IPOExportRequestSet)
 >>> request_set.addRequest(person, potemplates, pofiles)
diff --git a/lib/lp/translations/doc/poexport-request.txt b/lib/lp/translations/doc/poexport-request.txt
index cf6d13f..8e87314 100644
--- a/lib/lp/translations/doc/poexport-request.txt
+++ b/lib/lp/translations/doc/poexport-request.txt
@@ -233,9 +233,11 @@ just PO files.
 >>> product_template.productseries is None
 False
 >>> request_set.addRequest(person, product_template)
->>> alsa_template = POTemplate.selectOneBy(path='po/alsa-utils.pot')
+>>> alsa_template = IStore(POTemplate).find(
+... POTemplate, path='po/alsa-utils.pot').one()
 >>> alsa_es = alsa_template.getPOFileByLang('es')
->>> netapplet_template = POTemplate.selectOneBy(path='po/netapplet.pot')
+>>> netapplet_template = IStore(POTemplate).find(
+... POTemplate, path='po/netapplet.pot').one()
 >>> request_set.addRequest(
 ... person, [alsa_template, netapplet_template], [alsa_es])
 >>> transaction.commit()
diff --git a/lib/lp/translations/doc/pofile.txt b/lib/lp/translations/doc/pofile.txt
index 9caf91d..286080b 100644
--- a/lib/lp/translations/doc/pofile.txt
+++ b/lib/lp/translations/doc/pofile.txt
@@ -611,10 +611,8 @@ If you have a distroseries and want to know all the people who
 contributed translations on a given language for that distroseries, you
 can use the getPOFileContributorsByLanguage() method of IDistroSeries.