← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~enriqueesanchz/launchpad:change-external-url into launchpad:master

 

Enrique Sánchez has proposed merging ~enriqueesanchz/launchpad:change-external-url into launchpad:master.

Commit message:
Change +external url to +<packagetype>
    
Change `+external` url to `+unknown`, `+generic`, `+snap`, `+charm`,
`+rock`, `+python`, `+conda`, `+cargo`, `+maven`.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~enriqueesanchz/launchpad/+git/launchpad/+merge/493961
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~enriqueesanchz/launchpad:change-external-url into launchpad:master.
diff --git a/lib/lp/bugs/browser/bugtask.py b/lib/lp/bugs/browser/bugtask.py
index 3e1373c..270167d 100644
--- a/lib/lp/bugs/browser/bugtask.py
+++ b/lib/lp/bugs/browser/bugtask.py
@@ -393,6 +393,10 @@ class BugTaskNavigation(Navigation):
             return
         if bugtask.distribution != self.context.distribution:
             return
+        if bugtask.distroseries != self.context.distroseries:
+            return
+        if bugtask.packagetype != self.context.packagetype:
+            return
 
         return bugtask
 
diff --git a/lib/lp/bugs/browser/tests/test_buglisting.py b/lib/lp/bugs/browser/tests/test_buglisting.py
index 8b075d6..4652ae2 100644
--- a/lib/lp/bugs/browser/tests/test_buglisting.py
+++ b/lib/lp/bugs/browser/tests/test_buglisting.py
@@ -67,7 +67,7 @@ class TestBugTaskSearchListingPage(BrowserTestCase):
         # An external package from url will use unknown type
         self.assertTextMatchesExpressionIgnoreWhitespace(
             """
-            ep - Unknown in Ep-distro
+            ep - Snap in Ep-distro
             does not use Launchpad for bug tracking.
             Getting started with bug tracking in Launchpad.""",
             extract_text(top_portlet[0]),
@@ -195,7 +195,7 @@ class TestBugTaskSearchListingPage(BrowserTestCase):
         )
         self.assertTextMatchesExpressionIgnoreWhitespace(
             """
-            test-sp - Unknown in Test-series does not
+            test-sp - Snap in Test-series does not
             use Launchpad for bug tracking.
             Getting started with bug tracking in Launchpad.""",
             extract_text(top_portlet[0]),
diff --git a/lib/lp/bugs/browser/tests/test_bugtask_navigation.py b/lib/lp/bugs/browser/tests/test_bugtask_navigation.py
index bb41781..8cf2537 100644
--- a/lib/lp/bugs/browser/tests/test_bugtask_navigation.py
+++ b/lib/lp/bugs/browser/tests/test_bugtask_navigation.py
@@ -134,10 +134,11 @@ class TestBugTaskTraversal(TestCaseWithFactory):
         for bugtask in bugtasks[:3]:
             self.assertEqual(
                 canonical_url(bugtask),
-                "http://bugs.launchpad.test/%s/+external/%s/+bug/%d/";
+                "http://bugs.launchpad.test/%s/+%s/%s/+bug/%d/";
                 "+bugtask/%s"
                 % (
                     bugtask.distribution.name,
+                    bugtask.target.packagetype.name.lower(),
                     bugtask.target.name,
                     bugtask.bug.id,
                     bugtask.id,
@@ -150,11 +151,12 @@ class TestBugTaskTraversal(TestCaseWithFactory):
         for bugtask in bugtasks[3:]:
             self.assertEqual(
                 canonical_url(bugtask),
-                "http://bugs.launchpad.test/%s/%s/+external/%s/+bug/%d/";
+                "http://bugs.launchpad.test/%s/%s/+%s/%s/+bug/%d/";
                 "+bugtask/%s"
                 % (
                     bugtask.target.distribution.name,
                     bugtask.distroseries.name,
+                    bugtask.target.packagetype.name.lower(),
                     bugtask.target.name,
                     bugtask.bug.id,
                     bugtask.id,
@@ -178,9 +180,10 @@ class TestBugTaskTraversal(TestCaseWithFactory):
         )
         self.assertEqual(
             removeSecurityProxy(view).target,
-            "http://bugs.launchpad.test/%s/+external/%s/+bug/%d/+bugtask/%s";
+            "http://bugs.launchpad.test/%s/+%s/%s/+bug/%d/+bugtask/%s";
             % (
                 bug.default_bugtask.distribution.name,
+                bug.default_bugtask.target.packagetype.name.lower(),
                 bug.default_bugtask.target.name,
                 bug.default_bugtask.bug.id,
                 bug.default_bugtask.id,
@@ -213,10 +216,11 @@ class TestBugTaskTraversal(TestCaseWithFactory):
         )
         self.assertEqual(
             removeSecurityProxy(view).target,
-            "http://bugs.launchpad.test/%s/%s/+external/%s/+bug/%d/+bugtask/%s";
+            "http://bugs.launchpad.test/%s/%s/+%s/%s/+bug/%d/+bugtask/%s";
             % (
                 bug.default_bugtask.target.distribution.name,
                 bug.default_bugtask.distroseries.name,
+                bug.default_bugtask.target.packagetype.name.lower(),
                 bug.default_bugtask.target.name,
                 bug.default_bugtask.bug.id,
                 bug.default_bugtask.id,
@@ -236,9 +240,10 @@ class TestBugTaskTraversal(TestCaseWithFactory):
         )
         self.assertEqual(
             removeSecurityProxy(view).target,
-            "http://api.launchpad.test/1.0/%s/+external/%s/+bug/%d/+bugtask/%s";
+            "http://api.launchpad.test/1.0/%s/+%s/%s/+bug/%d/+bugtask/%s";
             % (
                 bug.default_bugtask.distribution.name,
+                bug.default_bugtask.target.packagetype.name.lower(),
                 bug.default_bugtask.target.name,
                 bug.default_bugtask.bug.id,
                 bug.default_bugtask.id,
@@ -267,11 +272,12 @@ class TestBugTaskTraversal(TestCaseWithFactory):
         )
         self.assertEqual(
             removeSecurityProxy(view).target,
-            "http://api.launchpad.test/1.0/%s/%s/+external/%s/+bug/%d/";
+            "http://api.launchpad.test/1.0/%s/%s/+%s/%s/+bug/%d/";
             "+bugtask/%s"
             % (
                 bug.default_bugtask.target.distribution.name,
                 bug.default_bugtask.distroseries.name,
+                bug.default_bugtask.target.packagetype.name.lower(),
                 bug.default_bugtask.target.name,
                 bug.default_bugtask.bug.id,
                 bug.default_bugtask.id,
diff --git a/lib/lp/bugs/configure.zcml b/lib/lp/bugs/configure.zcml
index 4f713bc..ea98516 100644
--- a/lib/lp/bugs/configure.zcml
+++ b/lib/lp/bugs/configure.zcml
@@ -208,6 +208,7 @@
                     milestone_id
                     product_id
                     productseries_id
+                    packagetype
                     sourcepackagename_id
                     task_age
                     bug_subscribers
diff --git a/lib/lp/bugs/interfaces/bugtasksearch.py b/lib/lp/bugs/interfaces/bugtasksearch.py
index 045049d..55e69ae 100644
--- a/lib/lp/bugs/interfaces/bugtasksearch.py
+++ b/lib/lp/bugs/interfaces/bugtasksearch.py
@@ -38,7 +38,7 @@ from lp.bugs.interfaces.bugtask import (
     IBugTask,
 )
 from lp.services.fields import SearchTag
-from lp.services.searchbuilder import NULL, all, any, not_equals
+from lp.services.searchbuilder import NULL, all, any
 from lp.soyuz.interfaces.component import IComponent
 
 
@@ -315,15 +315,15 @@ class BugTaskSearchParams:
     def setExternalPackage(self, externalpackage):
         """Set the externalpackage context on which to filter the search."""
         self.distribution = externalpackage.distribution
-        # Currently we are only filtering by having any packagetype
-        self.packagetype = not_equals(None)
+        # Currently we are not filtering by channel
+        self.packagetype = externalpackage.packagetype.value
         self.sourcepackagename = externalpackage.sourcepackagename
 
     def setExternalPackageSeries(self, externalpackageseries):
         """Set the externalpackage context on which to filter the search."""
         self.distroseries = externalpackageseries.distroseries
-        # Currently we are only filtering by having any packagetype
-        self.packagetype = not_equals(None)
+        # Currently we are not filtering by channel
+        self.packagetype = externalpackageseries.packagetype.value
         self.sourcepackagename = externalpackageseries.sourcepackagename
 
     def setOCIProject(self, ociproject):
diff --git a/lib/lp/registry/browser/configure.zcml b/lib/lp/registry/browser/configure.zcml
index 052a793..bff5d4f 100644
--- a/lib/lp/registry/browser/configure.zcml
+++ b/lib/lp/registry/browser/configure.zcml
@@ -605,12 +605,12 @@
         />
     <lp:url
         for="lp.registry.interfaces.externalpackage.IExternalPackage"
-        path_expression="string:+external/${name}"
+        urldata="lp.registry.browser.externalpackage.ExternalPackageURL"
         attribute_to_parent="distribution"
         />
     <lp:url
         for="lp.registry.interfaces.externalpackageseries.IExternalPackageSeries"
-        path_expression="string:+external/${name}"
+        urldata="lp.registry.browser.externalpackageseries.ExternalPackageSeriesURL"
         attribute_to_parent="distroseries"
         />
     <lp:navigation
diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
index d8d40c2..4ef3d1d 100644
--- a/lib/lp/registry/browser/distribution.py
+++ b/lib/lp/registry/browser/distribution.py
@@ -184,12 +184,60 @@ class DistributionNavigation(
         else:
             return dsp
 
-    @stepthrough("+external")
-    def traverse_external(self, name):
+    @stepthrough("+unknown")
+    def traverse_unknown(self, name):
         return self.context.getExternalPackage(
             name, ExternalPackageType.UNKNOWN, None
         )
 
+    @stepthrough("+generic")
+    def traverse_generic(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.GENERIC, None
+        )
+
+    @stepthrough("+snap")
+    def traverse_snap(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.SNAP, None
+        )
+
+    @stepthrough("+charm")
+    def traverse_charm(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.CHARM, None
+        )
+
+    @stepthrough("+rock")
+    def traverse_rock(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.ROCK, None
+        )
+
+    @stepthrough("+python")
+    def traverse_python(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.PYTHON, None
+        )
+
+    @stepthrough("+conda")
+    def traverse_conda(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.CONDA, None
+        )
+
+    @stepthrough("+cargo")
+    def traverse_cargo(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.CARGO, None
+        )
+
+    @stepthrough("+maven")
+    def traverse_maven(self, name):
+        return self.context.getExternalPackage(
+            name, ExternalPackageType.MAVEN, None
+        )
+
     @stepthrough("+oci")
     def traverse_oci(self, name):
         oci_project = self.context.getOCIProject(name)
diff --git a/lib/lp/registry/browser/distroseries.py b/lib/lp/registry/browser/distroseries.py
index c72511d..98636c8 100644
--- a/lib/lp/registry/browser/distroseries.py
+++ b/lib/lp/registry/browser/distroseries.py
@@ -182,12 +182,60 @@ class DistroSeriesNavigation(
 
         return distroserieslang
 
-    @stepthrough("+external")
-    def external(self, name):
+    @stepthrough("+unknown")
+    def traverse_unknown(self, name):
         return self.context.getExternalPackageSeries(
             name, ExternalPackageType.UNKNOWN, None
         )
 
+    @stepthrough("+generic")
+    def traverse_generic(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.GENERIC, None
+        )
+
+    @stepthrough("+snap")
+    def traverse_snap(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.SNAP, None
+        )
+
+    @stepthrough("+charm")
+    def traverse_charm(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.CHARM, None
+        )
+
+    @stepthrough("+rock")
+    def traverse_rock(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.ROCK, None
+        )
+
+    @stepthrough("+python")
+    def traverse_python(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.PYTHON, None
+        )
+
+    @stepthrough("+conda")
+    def traverse_conda(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.CONDA, None
+        )
+
+    @stepthrough("+cargo")
+    def traverse_cargo(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.CARGO, None
+        )
+
+    @stepthrough("+maven")
+    def traverse_maven(self, name):
+        return self.context.getExternalPackageSeries(
+            name, ExternalPackageType.MAVEN, None
+        )
+
     @stepthrough("+source")
     def source(self, name):
         return self.context.getSourcePackage(name)
diff --git a/lib/lp/registry/browser/externalpackage.py b/lib/lp/registry/browser/externalpackage.py
index b0df2ba..6ec7657 100644
--- a/lib/lp/registry/browser/externalpackage.py
+++ b/lib/lp/registry/browser/externalpackage.py
@@ -5,6 +5,7 @@ __all__ = [
     "ExternalPackageBreadcrumb",
     "ExternalPackageNavigation",
     "ExternalPackageFacets",
+    "ExternalPackageURL",
 ]
 
 
@@ -18,7 +19,10 @@ from lp.bugs.browser.structuralsubscription import (
 from lp.registry.interfaces.externalpackage import IExternalPackage
 from lp.services.webapp import Navigation, StandardLaunchpadFacets, redirection
 from lp.services.webapp.breadcrumb import Breadcrumb
-from lp.services.webapp.interfaces import IMultiFacetedBreadcrumb
+from lp.services.webapp.interfaces import (
+    ICanonicalUrlData,
+    IMultiFacetedBreadcrumb,
+)
 
 
 @implementer(IHeadingBreadcrumb, IMultiFacetedBreadcrumb)
@@ -29,7 +33,10 @@ class ExternalPackageBreadcrumb(Breadcrumb):
 
     @property
     def text(self):
-        return "%s external package" % self.context.sourcepackagename.name
+        return "%s %s package" % (
+            self.context.sourcepackagename.name,
+            self.context.packagetype.name.lower(),
+        )
 
 
 class ExternalPackageFacets(StandardLaunchpadFacets):
@@ -49,3 +56,22 @@ class ExternalPackageNavigation(
     @redirection("+editbugcontact")
     def redirect_editbugcontact(self):
         return "+subscribe"
+
+
+@implementer(ICanonicalUrlData)
+class ExternalPackageURL:
+    """External Package URL creation rules."""
+
+    rootsite = None
+
+    def __init__(self, context):
+        self.context = context
+
+    @property
+    def inside(self):
+        return self.context.distribution
+
+    @property
+    def path(self):
+        packagetype = self.context.packagetype.name.lower()
+        return f"+{packagetype}/{self.context.name}"
diff --git a/lib/lp/registry/browser/externalpackageseries.py b/lib/lp/registry/browser/externalpackageseries.py
index 3d262ae..4221ef8 100644
--- a/lib/lp/registry/browser/externalpackageseries.py
+++ b/lib/lp/registry/browser/externalpackageseries.py
@@ -5,6 +5,7 @@ __all__ = [
     "ExternalPackageSeriesBreadcrumb",
     "ExternalPackageSeriesNavigation",
     "ExternalPackageSeriesFacets",
+    "ExternalPackageSeriesURL",
 ]
 
 
@@ -24,7 +25,10 @@ from lp.services.webapp import (
     stepto,
 )
 from lp.services.webapp.breadcrumb import Breadcrumb
-from lp.services.webapp.interfaces import IMultiFacetedBreadcrumb
+from lp.services.webapp.interfaces import (
+    ICanonicalUrlData,
+    IMultiFacetedBreadcrumb,
+)
 
 
 @implementer(IHeadingBreadcrumb, IMultiFacetedBreadcrumb)
@@ -35,8 +39,9 @@ class ExternalPackageSeriesBreadcrumb(Breadcrumb):
 
     @property
     def text(self):
-        return "%s external package in %s" % (
+        return "%s %s package in %s" % (
             self.context.sourcepackagename.name,
+            self.context.packagetype.name.lower(),
             self.context.distroseries.named_version,
         )
 
@@ -68,3 +73,22 @@ class ExternalPackageSeriesNavigation(
         if self.request.form.get("no-redirect") is not None:
             redirection_url += "?no-redirect"
         return self.redirectSubTree(redirection_url, status=303)
+
+
+@implementer(ICanonicalUrlData)
+class ExternalPackageSeriesURL:
+    """External Package URL creation rules."""
+
+    rootsite = None
+
+    def __init__(self, context):
+        self.context = context
+
+    @property
+    def inside(self):
+        return self.context.distroseries
+
+    @property
+    def path(self):
+        packagetype = self.context.packagetype.name.lower()
+        return f"+{packagetype}/{self.context.name}"
diff --git a/lib/lp/registry/model/externalpackage.py b/lib/lp/registry/model/externalpackage.py
index d874ca6..8327349 100644
--- a/lib/lp/registry/model/externalpackage.py
+++ b/lib/lp/registry/model/externalpackage.py
@@ -117,6 +117,7 @@ class ExternalPackage(
             IExternalPackage.providedBy(other)
             and self.sourcepackagename.id == other.sourcepackagename.id
             and self.distribution.id == other.distribution.id
+            and self.packagetype == other.packagetype
         )
 
     def __eq__(self, other: "ExternalPackage") -> str:
diff --git a/lib/lp/registry/model/externalpackageseries.py b/lib/lp/registry/model/externalpackageseries.py
index b312ba4..c6c08c7 100644
--- a/lib/lp/registry/model/externalpackageseries.py
+++ b/lib/lp/registry/model/externalpackageseries.py
@@ -139,6 +139,7 @@ class ExternalPackageSeries(
             IExternalPackageSeries.providedBy(other)
             and self.sourcepackagename.id == other.sourcepackagename.id
             and self.distroseries.id == other.distroseries.id
+            and self.packagetype == other.packagetype
         )
 
     def __eq__(self, other: "ExternalPackageSeries") -> str:
diff --git a/lib/lp/registry/tests/test_externalpackage.py b/lib/lp/registry/tests/test_externalpackage.py
index f7b132c..ab1f715 100644
--- a/lib/lp/registry/tests/test_externalpackage.py
+++ b/lib/lp/registry/tests/test_externalpackage.py
@@ -28,6 +28,11 @@ class TestExternalPackage(TestCaseWithFactory):
             packagetype=ExternalPackageType.SNAP,
             channel=self.channel,
         )
+        self.externalpackage_matching = self.distribution.getExternalPackage(
+            name=self.sourcepackagename,
+            packagetype=ExternalPackageType.SNAP,
+            channel=("22", "candidate", "staging"),
+        )
         self.externalpackage_maven = self.distribution.getExternalPackage(
             name=self.sourcepackagename,
             packagetype=ExternalPackageType.MAVEN,
@@ -135,10 +140,14 @@ class TestExternalPackage(TestCaseWithFactory):
         )
 
     def test_matches(self):
-        """Test if two externalpackages matches in sourcepackagename and
-        distribution.
+        """Test if two externalpackages matches in sourcepackagename,
+        distribution and packagetype.
         """
         self.assertTrue(
+            self.externalpackage.isMatching(self.externalpackage_matching)
+        )
+
+        self.assertFalse(
             self.externalpackage.isMatching(self.externalpackage_maven)
         )
 
@@ -158,6 +167,9 @@ class TestExternalPackage(TestCaseWithFactory):
     def test_compare(self):
         """Test __eq__ and __neq__"""
         self.assertEqual(self.externalpackage, self.externalpackage_copy)
+        self.assertNotEqual(
+            self.externalpackage, self.externalpackage_matching
+        )
         self.assertNotEqual(self.externalpackage, self.externalpackage_maven)
 
     def test_hash(self):
diff --git a/lib/lp/registry/tests/test_externalpackageseries.py b/lib/lp/registry/tests/test_externalpackageseries.py
index c3b2728..03539d8 100644
--- a/lib/lp/registry/tests/test_externalpackageseries.py
+++ b/lib/lp/registry/tests/test_externalpackageseries.py
@@ -34,6 +34,13 @@ class TestExternalPackageSeries(TestCaseWithFactory):
                 channel=self.channel,
             )
         )
+        self.externalpackageseries_matching = (
+            self.distroseries.getExternalPackageSeries(
+                name=self.sourcepackagename,
+                packagetype=ExternalPackageType.SNAP,
+                channel=("22", "candidate", "staging"),
+            )
+        )
         self.externalpackageseries_maven = (
             self.distroseries.getExternalPackageSeries(
                 name=self.sourcepackagename,
@@ -172,11 +179,17 @@ class TestExternalPackageSeries(TestCaseWithFactory):
         self.assertEqual(expected, self.externalpackageseries.bugtarget_parent)
 
     def test_matches(self):
-        """Test if two externalpackageseries matches in sourcepackagename and
-        distroseries.
+        """Test if two externalpackageseries matches in sourcepackagename,
+        distroseries and packagetype.
         """
         self.assertTrue(
             self.externalpackageseries.isMatching(
+                self.externalpackageseries_matching
+            )
+        )
+
+        self.assertFalse(
+            self.externalpackageseries.isMatching(
                 self.externalpackageseries_maven
             )
         )
@@ -201,6 +214,9 @@ class TestExternalPackageSeries(TestCaseWithFactory):
             self.externalpackageseries, self.externalpackageseries_copy
         )
         self.assertNotEqual(
+            self.externalpackageseries, self.externalpackageseries_matching
+        )
+        self.assertNotEqual(
             self.externalpackageseries, self.externalpackageseries_maven
         )