← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~twom/launchpad:oci-recipe-name into launchpad:master

 

Tom Wardill has proposed merging ~twom/launchpad:oci-recipe-name into launchpad:master.

Commit message:
Add OCIRecipeName in preparation for OCIRecipeTarget

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

Names are their own object to allow multiple recipes to have different targets, but the same name.

Add the model, interface, factory method, zcml and security.cfg declarations.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:oci-recipe-name into launchpad:master.
diff --git a/database/schema/security.cfg b/database/schema/security.cfg
index 1e9ca05..2a760b5 100644
--- a/database/schema/security.cfg
+++ b/database/schema/security.cfg
@@ -1238,6 +1238,7 @@ public.logintoken                       = SELECT, INSERT, UPDATE
 public.message                          = SELECT, INSERT, UPDATE
 public.milestone                        = SELECT, INSERT, UPDATE
 public.openididentifier                 = SELECT
+public.ocirecipename                    = SELECT, INSERT, UPDATE
 public.packageupload                    = SELECT, INSERT, UPDATE
 public.packageuploadbuild               = SELECT, INSERT, UPDATE
 public.packageuploadcustom              = SELECT, INSERT, UPDATE
@@ -1413,6 +1414,7 @@ public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.milestone                        = SELECT
 public.milestonetag                     = SELECT
+public.ocirecipename                    = SELECT
 public.openididentifier                 = SELECT
 public.packagecopyjob                   = SELECT, INSERT
 public.packagediff                      = SELECT, INSERT, UPDATE, DELETE
@@ -1529,6 +1531,7 @@ public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.milestone                        = SELECT
 public.milestonetag                     = SELECT
+public.ocirecipename                    = SELECT
 public.openididentifier                 = SELECT
 public.packagecopyjob                   = SELECT, INSERT, UPDATE
 public.packagediff                      = SELECT, UPDATE
@@ -1631,6 +1634,7 @@ public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.milestone                        = SELECT
 public.milestonetag                     = SELECT
+public.ocirecipename                    = SELECT
 public.person                           = SELECT
 public.personlanguage                   = SELECT
 public.personsettings                   = SELECT
@@ -1832,6 +1836,7 @@ public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.milestone                        = SELECT
 public.milestonetag                     = SELECT, INSERT, DELETE
+public.ocirecipename                    = SELECT
 public.openididentifier                 = SELECT
 public.packageset                       = SELECT
 public.packagesetgroup                  = SELECT
@@ -1951,6 +1956,7 @@ public.libraryfilealias                 = SELECT, INSERT
 public.libraryfilecontent               = SELECT, INSERT
 public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
+public.ocirecipename                    = SELECT
 public.openididentifier                 = SELECT
 public.person                           = SELECT
 public.product                          = SELECT
@@ -2008,6 +2014,7 @@ public.libraryfilecontent               = SELECT, INSERT
 public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.milestone                        = SELECT
+public.ocirecipename                    = SELECT
 public.person                           = SELECT
 public.personsettings                   = SELECT
 public.previewdiff                      = SELECT, INSERT
@@ -2144,6 +2151,7 @@ public.job                              = SELECT, INSERT, UPDATE
 public.message                          = SELECT, INSERT
 public.messagechunk                     = SELECT, INSERT
 public.milestonetag                     = SELECT
+public.ocirecipename                    = SELECT
 public.person                           = SELECT, INSERT
 public.personsettings                   = SELECT, INSERT
 public.product                          = SELECT, INSERT, UPDATE
@@ -2260,6 +2268,7 @@ public.milestonetag                     = SELECT, INSERT, UPDATE, DELETE
 public.nameblacklist                    = SELECT, UPDATE
 public.oauthaccesstoken                 = SELECT, UPDATE
 public.oauthrequesttoken                = SELECT, UPDATE
+public.ocirecipename                    = SELECT
 public.officialbugtag                   = SELECT
 public.openididentifier                 = SELECT, UPDATE
 public.packagecopyrequest               = SELECT, UPDATE
@@ -2377,6 +2386,7 @@ public.livefsfile                       = SELECT, DELETE
 public.logintoken                       = SELECT, DELETE
 public.mailinglistsubscription          = SELECT, DELETE
 public.milestonetag                     = SELECT
+public.ocirecipename                    = SELECT
 public.openidconsumerassociation        = SELECT, DELETE
 public.openidconsumernonce              = SELECT, DELETE
 public.person                           = SELECT, DELETE
@@ -2529,6 +2539,7 @@ public.distroseries                     = SELECT
 public.emailaddress                     = SELECT
 public.gitrepository                    = SELECT
 public.job                              = SELECT, INSERT, UPDATE
+public.ocirecipename                    = SELECT
 public.person                           = SELECT
 public.packaging                        = SELECT
 public.product                          = SELECT, UPDATE
@@ -2551,6 +2562,7 @@ public.bugtask                          = SELECT
 public.bugtaskflat                      = SELECT
 public.distribution                     = SELECT
 public.distroseries                     = SELECT
+public.ocirecipename                    = SELECT
 public.product                          = SELECT
 public.productseries                    = SELECT
 public.sourcepackagename                = SELECT
@@ -2562,6 +2574,7 @@ public.branch                           = SELECT
 public.distribution                     = SELECT
 public.gitrepository                    = SELECT
 public.job                              = SELECT, UPDATE
+public.ocirecipename                    = SELECT
 public.person                           = SELECT
 public.product                          = SELECT
 public.snap                             = SELECT
diff --git a/lib/lp/registry/configure.zcml b/lib/lp/registry/configure.zcml
index 7a74bad..047a31b 100644
--- a/lib/lp/registry/configure.zcml
+++ b/lib/lp/registry/configure.zcml
@@ -714,6 +714,26 @@
             interface="lp.registry.interfaces.pillar.IPillarPersonFactory"/>
     </securedutility>
 
+    <!-- OCIRecipeName -->
+    <class
+        class="lp.registry.model.ocirecipename.OCIRecipeName">
+        <allow
+            interface="lp.registry.interfaces.ocirecipename.IOCIRecipeName"/>
+    </class>
+
+    <!-- OCIRecipeNameSet -->
+    <securedutility
+        class="lp.registry.model.ocirecipename.OCIRecipeNameSet"
+        provides="lp.registry.interfaces.ocirecipename.IOCIRecipeNameSet">
+        <allow
+            interface="lp.registry.interfaces.ocirecipename.IOCIRecipeNameSet"/>
+    </securedutility>
+    <class
+        class="lp.registry.model.ocirecipename.OCIRecipeNameSet">
+        <allow
+            interface="lp.registry.interfaces.ocirecipename.IOCIRecipeNameSet"/>
+    </class>
+
     <!-- SourcePackageName -->
 
     <class
diff --git a/lib/lp/registry/errors.py b/lib/lp/registry/errors.py
index 7564299..e8a99e1 100644
--- a/lib/lp/registry/errors.py
+++ b/lib/lp/registry/errors.py
@@ -23,6 +23,7 @@ __all__ = [
     'NoSuchAccount',
     'NoSuchDistroSeries',
     'NoSuchSourcePackageName',
+    'NoSuchRecipeName',
     'NotPlaceholderAccount',
     'InclusiveTeamLinkageError',
     'PPACreationError',
@@ -109,6 +110,10 @@ class NoSuchSourcePackageName(NameLookupFailed):
     """Raised when we can't find a particular sourcepackagename."""
     _message_prefix = "No such source package"
 
+class NoSuchRecipeName(NameLookupFailed):
+    """Raised when we can't find a particular ocirecipename."""
+    _message_prefix = "No such OCI recipe"
+
 
 @error_status(httplib.BAD_REQUEST)
 class CannotTransitionToCountryMirror(Exception):
diff --git a/lib/lp/registry/interfaces/ocirecipename.py b/lib/lp/registry/interfaces/ocirecipename.py
new file mode 100644
index 0000000..b6226e1
--- /dev/null
+++ b/lib/lp/registry/interfaces/ocirecipename.py
@@ -0,0 +1,38 @@
+from zope.interface import (
+    Interface
+)
+from zope.schema import (
+    Int,
+    Text,
+    )
+
+from lp import _
+
+
+class IOCIRecipeName(Interface):
+
+    id = Int(title=_("OCI Recipe Name ID"),
+             required=True,
+             readonly=True
+             )
+
+    name = Text(title=_("Name of recipe"))
+
+
+class IOCIRecipeNameSet(Interface):
+
+    def __getitem__(name):
+        """Retrieve a ocirecipename by name."""
+
+    def getByName(name):
+        """Return a ocirecipename by its name.
+
+        If the ocirecipename can't be found a NoSuchRecipeName will be
+        raised.
+        """
+
+    def getAll():
+        """return an iselectresults representing all package names"""
+
+    def new(name):
+        """Create a new oci recipe name."""
diff --git a/lib/lp/registry/model/ocirecipename.py b/lib/lp/registry/model/ocirecipename.py
new file mode 100644
index 0000000..88d3a65
--- /dev/null
+++ b/lib/lp/registry/model/ocirecipename.py
@@ -0,0 +1,66 @@
+from storm.properties import Unicode
+from storm.locals import (
+    Desc,
+    Int,
+    )
+from zope.interface import implementer
+
+from lp.app.validators.name import valid_name
+from lp.services.database.interfaces import (
+    IMasterStore,
+    IStore,
+    )
+from lp.services.database.stormbase import StormBase
+from lp.registry.errors import (
+    InvalidName,
+    NoSuchRecipeName,
+    )
+from lp.registry.interfaces.ocirecipename import (
+    IOCIRecipeName,
+    IOCIRecipeNameSet,
+    )
+from lp.services.helpers import ensure_unicode
+
+
+@implementer(IOCIRecipeName)
+class OCIRecipeName(StormBase):
+
+    __storm_table__ = "OCIRecipeName"
+
+    id = Int(primary=True)
+    name = Unicode(name="name", allow_none=False)
+
+    def __init__(self, name):
+        super(OCIRecipeName, self).__init__()
+        self.name = name
+
+
+@implementer(IOCIRecipeNameSet)
+class OCIRecipeNameSet:
+
+    def __getitem__(self, name):
+        """See `IOCIRecipeNameSet`."""
+        return self.getByName
+
+    def getByName(self, name):
+        """See `IOCIRecipeNameSet`."""
+        recipe_name  = IStore(OCIRecipeName).find(
+            OCIRecipeName, OCIRecipeName.name == name).one()
+        if recipe_name is None:
+            raise NoSuchRecipeName(name)
+        return recipe_name
+
+    def getAll(self):
+        """See `IOCIRecipeNameSet`."""
+        return IStore(OCIRecipeName).find(OCIRecipeName).order_by(
+            Desc(OCIRecipeName.name))
+
+    def new(self, name):
+        """See `IOCIRecipeNameSet`."""
+        if not valid_name(name):
+            raise InvalidName(
+                "%s is not a valid name for an OCI recipe." % name)
+        store = IMasterStore(OCIRecipeName)
+        recipe_name = OCIRecipeName(name=name)
+        store.add(recipe_name)
+        return recipe_name
diff --git a/lib/lp/registry/tests/test_ocirecipename.py b/lib/lp/registry/tests/test_ocirecipename.py
new file mode 100644
index 0000000..0a576cb
--- /dev/null
+++ b/lib/lp/registry/tests/test_ocirecipename.py
@@ -0,0 +1,47 @@
+import transaction
+from testtools.testcase import ExpectedException
+
+from lp.registry.errors import (
+    InvalidName,
+    NoSuchRecipeName,
+    )
+from lp.registry.model.ocirecipename import (
+    OCIRecipeName,
+    OCIRecipeNameSet,
+    )
+from lp.services.database.interfaces import IStore
+from lp.testing import TestCaseWithFactory
+from lp.testing.layers import DatabaseFunctionalLayer
+
+
+class OCIRecipeNameTest(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def test_create(self):
+        name = self.factory.makeOCIRecipeName()
+        self.assertTrue(name.name.startswith('oci-base-name'))
+
+    def test_invalid_name(self):
+        with ExpectedException(
+            InvalidName,
+            'invalid%20name is not a valid name for an OCI recipe.'):
+            OCIRecipeNameSet().new('invalid%20name')
+
+    def test_get_missing(self):
+        with ExpectedException(
+            NoSuchRecipeName,
+            "No such OCI recipe: 'invalid'"):
+            OCIRecipeNameSet().getByName(u'invalid')
+
+    def test_get(self):
+        created = self.factory.makeOCIRecipeName()
+        IStore(OCIRecipeName).flush()
+        fetched = OCIRecipeNameSet().getByName(created.name)
+        self.assertEqual(fetched, created)
+
+    def test_get_all(self):
+        for i in range(5):
+            self.factory.makeOCIRecipeName()
+        all_recipes = OCIRecipeNameSet().getAll()
+        self.assertEqual(all_recipes.count(), 5)
diff --git a/lib/lp/registry/tests/test_ocirecipetarget.py b/lib/lp/registry/tests/test_ocirecipetarget.py
new file mode 100644
index 0000000..5333cf6
--- /dev/null
+++ b/lib/lp/registry/tests/test_ocirecipetarget.py
@@ -0,0 +1,24 @@
+# Copyright 2019 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+
+from lp.registry.model.ocirecipename import OCIRecipeName
+from lp.registry.model.ocirecipetarget import OCIRecipeTarget
+from lp.testing import TestCaseWithFactory
+from lp.testing.layers import DatabaseFunctionalLayer
+
+
+class OCIRecipeTargetTest(TestCaseWithFactory):
+
+    layer = DatabaseFunctionalLayer
+
+    def test_create(self):
+        name = OCIRecipeName(name="Test OCI Recipe Name")
+        registrant = self.factory.makePerson()
+        project = self.factory.makeProduct()
+        distribution = self.factory.makeDistribution()
+        target = OCIRecipeTarget(registrant, project, distribution, name)
+        print(target.date_created)
+        self.assertTrue(target)
diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
index 568ddab..1d421fe 100644
--- a/lib/lp/testing/factory.py
+++ b/lib/lp/testing/factory.py
@@ -200,6 +200,8 @@ from lp.registry.interfaces.mailinglist import (
 from lp.registry.interfaces.mailinglistsubscription import (
     MailingListAutoSubscribePolicy,
     )
+from lp.registry.interfaces.ocirecipename import IOCIRecipeNameSet
+from lp.registry.interfaces.ocirecipetarget import IOCIRecipeTarget
 from lp.registry.interfaces.packaging import (
     IPackagingUtil,
     PackagingType,
@@ -4896,6 +4898,11 @@ class BareLaunchpadObjectFactory(ObjectFactory):
             registrant, name, display_name, distro_series, build_channels,
             date_created=date_created)
 
+    def makeOCIRecipeName(self, name=None):
+        if name is None:
+            name = self.getUniqueString(u"oci-base-name")
+        return getUtility(IOCIRecipeNameSet).new(name)
+
 
 # Some factory methods return simple Python types. We don't add
 # security wrappers for them, as well as for objects created by