Merge ~pappacena/launchpad:ui-ociproject-search-on-projects into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: 132b2dbb5f1280572173ad0a6aef8ad464a170cc
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:ui-ociproject-search-on-projects
Merge into: launchpad:master
Prerequisite: ~pappacena/launchpad:gitrepo-ociproject-refactoring
Diff against target: 609 lines (+235/-196)
9 files modified
lib/lp/code/browser/tests/test_product.py (+3/-2)
lib/lp/registry/browser/configure.zcml (+9/-2)
lib/lp/registry/browser/distribution.py (+0/-49)
lib/lp/registry/browser/ociproject.py (+50/-0)
lib/lp/registry/browser/product.py (+5/-1)
lib/lp/registry/browser/tests/test_distribution.py (+0/-137)
lib/lp/registry/browser/tests/test_ociproject.py (+163/-0)
lib/lp/registry/interfaces/ociproject.py (+3/-3)
lib/lp/registry/model/ociproject.py (+2/-2)
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Tom Wardill (community) Approve
Review via email: mp+384514@code.launchpad.net

Commit message

OCIProject search on project page.

To post a comment you must log in.
Revision history for this message
Thiago F. Pappacena (pappacena) :
Revision history for this message
Tom Wardill (twom) wrote :

One minor typo fix that I think was mine to start with...

review: Approve
Revision history for this message
Ioana Lasc (ilasc) :
review: Approve
7049999... by Thiago F. Pappacena

Fixing typo

Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

Pushed the typo fix. Thanks, twom!

132b2db... by Thiago F. Pappacena

Merge branch 'master' into ui-ociproject-search-on-projects

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/code/browser/tests/test_product.py b/lib/lp/code/browser/tests/test_product.py
2index d33a85e..57540e3 100644
3--- a/lib/lp/code/browser/tests/test_product.py
4+++ b/lib/lp/code/browser/tests/test_product.py
5@@ -1,4 +1,4 @@
6-# Copyright 2009-2017 Canonical Ltd. This software is licensed under the
7+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
8 # GNU Affero General Public License version 3 (see the file LICENSE).
9
10 """Tests for the product view classes and templates."""
11@@ -432,11 +432,12 @@ class TestProductOverviewOCIProject(TestCaseWithFactory):
12
13 layer = DatabaseFunctionalLayer
14
15- def test_displays_create_oci_project_link(self):
16+ def test_displays_create_and_list_oci_project_link(self):
17 product = self.factory.makeProduct()
18
19 browser = self.getUserBrowser(
20 canonical_url(product), user=product.owner)
21 text = extract_text(find_tag_by_id(browser.contents, 'global-actions'))
22
23+ self.assertIn("Search for OCI Project", text)
24 self.assertIn("Create an OCI Project", text)
25diff --git a/lib/lp/registry/browser/configure.zcml b/lib/lp/registry/browser/configure.zcml
26index 7e97bf9..b8f00d5 100644
27--- a/lib/lp/registry/browser/configure.zcml
28+++ b/lib/lp/registry/browser/configure.zcml
29@@ -2179,9 +2179,16 @@
30 <browser:page
31 name="+search-oci-project"
32 for="lp.registry.interfaces.distribution.IDistribution"
33- class="lp.registry.browser.distribution.DistributionOCIProjectSearchView"
34+ class="lp.registry.browser.ociproject.OCIProjectSearchView"
35 permission="zope.Public"
36- template="../templates/distribution-search-oci-projects.pt"
37+ template="../templates/search-oci-projects.pt"
38+ />
39+ <browser:page
40+ name="+search-oci-project"
41+ for="lp.registry.interfaces.product.IProduct"
42+ class="lp.registry.browser.ociproject.OCIProjectSearchView"
43+ permission="zope.Public"
44+ template="../templates/search-oci-projects.pt"
45 />
46 <browser:page
47 name="+search"
48diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py
49index 29eab7a..351aa1a 100644
50--- a/lib/lp/registry/browser/distribution.py
51+++ b/lib/lp/registry/browser/distribution.py
52@@ -42,7 +42,6 @@ from collections import defaultdict
53 import datetime
54
55 from lazr.restful.utils import smartquote
56-import six
57 from zope.component import getUtility
58 from zope.event import notify
59 from zope.formlib import form
60@@ -106,7 +105,6 @@ from lp.registry.interfaces.distributionmirror import (
61 MirrorContent,
62 MirrorSpeed,
63 )
64-from lp.registry.interfaces.ociproject import IOCIProjectSet
65 from lp.registry.interfaces.series import SeriesStatus
66 from lp.services.database.decoratedresultset import DecoratedResultSet
67 from lp.services.feeds.browser import FeedsMixin
68@@ -1387,50 +1385,3 @@ class DistributionPublisherConfigView(LaunchpadFormView):
69 self.request.response.addInfoNotification(
70 'Your changes have been applied.')
71 self.next_url = canonical_url(self.context)
72-
73-
74-class DistributionOCIProjectSearchView(LaunchpadView):
75- """Page to search for OCI projects of a given distribution."""
76- page_title = ''
77-
78- @property
79- def label(self):
80- return "Search OCI projects in %s" % self.context.title
81-
82- @property
83- def text(self):
84- text = self.request.get("text", None)
85- if isinstance(text, list):
86- # The user may have URL hacked a query string with more than one
87- # "text" parameter. We'll take the last one.
88- text = text[-1]
89- return text
90-
91- @property
92- def search_requested(self):
93- return self.text is not None
94-
95- @property
96- def title(self):
97- return self.context.name
98-
99- @cachedproperty
100- def count(self):
101- """Return the number of matched search results."""
102- return self.batchnav.batch.total()
103-
104- @cachedproperty
105- def batchnav(self):
106- """Return the batch navigator for the search results."""
107- return BatchNavigator(self.search_results, self.request)
108-
109- @cachedproperty
110- def preloaded_batch(self):
111- projects = self.batchnav.batch
112- getUtility(IOCIProjectSet).preloadDataForOCIProjects(projects)
113- return projects
114-
115- @property
116- def search_results(self):
117- return getUtility(IOCIProjectSet).findByDistributionAndName(
118- self.context, self.text or six.ensure_text(''))
119diff --git a/lib/lp/registry/browser/ociproject.py b/lib/lp/registry/browser/ociproject.py
120index 99c5b43..0d23a15 100644
121--- a/lib/lp/registry/browser/ociproject.py
122+++ b/lib/lp/registry/browser/ociproject.py
123@@ -41,16 +41,19 @@ from lp.registry.interfaces.ociprojectname import (
124 )
125 from lp.registry.interfaces.product import IProduct
126 from lp.services.features import getFeatureFlag
127+from lp.services.propertycache import cachedproperty
128 from lp.services.webapp import (
129 canonical_url,
130 ContextMenu,
131 enabled_with_permission,
132+ LaunchpadView,
133 Link,
134 Navigation,
135 NavigationMenu,
136 StandardLaunchpadFacets,
137 stepthrough,
138 )
139+from lp.services.webapp.batching import BatchNavigator
140 from lp.services.webapp.breadcrumb import Breadcrumb
141 from lp.services.webapp.interfaces import IMultiFacetedBreadcrumb
142
143@@ -234,3 +237,50 @@ class OCIProjectEditView(LaunchpadEditFormView):
144 return canonical_url(self.context)
145
146 cancel_url = next_url
147+
148+
149+class OCIProjectSearchView(LaunchpadView):
150+ """Page to search for OCI projects of a given pillar."""
151+ page_title = ''
152+
153+ @property
154+ def label(self):
155+ return "Search OCI projects in %s" % self.context.title
156+
157+ @property
158+ def text(self):
159+ text = self.request.get("text", None)
160+ if isinstance(text, list):
161+ # The user may have URL hacked a query string with more than one
162+ # "text" parameter. We'll take the last one.
163+ text = text[-1]
164+ return text
165+
166+ @property
167+ def search_requested(self):
168+ return self.text is not None
169+
170+ @property
171+ def title(self):
172+ return self.context.name
173+
174+ @cachedproperty
175+ def count(self):
176+ """Return the number of matched search results."""
177+ return self.batchnav.batch.total()
178+
179+ @cachedproperty
180+ def batchnav(self):
181+ """Return the batch navigator for the search results."""
182+ return BatchNavigator(self.search_results, self.request)
183+
184+ @cachedproperty
185+ def preloaded_batch(self):
186+ projects = self.batchnav.batch
187+ getUtility(IOCIProjectSet).preloadDataForOCIProjects(projects)
188+ return projects
189+
190+ @property
191+ def search_results(self):
192+ return getUtility(IOCIProjectSet).findByPillarAndName(
193+ self.context, self.text or '')
194diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py
195index f974d39..aad1fc8 100644
196--- a/lib/lp/registry/browser/product.py
197+++ b/lib/lp/registry/browser/product.py
198@@ -509,6 +509,10 @@ class ProductEditLinksMixin(StructuralSubscriptionMenuMixin):
199 def sharing(self):
200 return Link('+sharing', 'Sharing', icon='edit')
201
202+ def search_oci_project(self):
203+ text = 'Search for OCI Project'
204+ return Link('+search-oci-project', text, icon='info')
205+
206 @enabled_with_permission('launchpad.Driver')
207 def new_oci_project(self):
208 text = 'Create an OCI Project'
209@@ -533,7 +537,7 @@ class ProductActionNavigationMenu(NavigationMenu, ProductEditLinksMixin):
210 @cachedproperty
211 def links(self):
212 links = ['edit', 'review_license', 'administer', 'sharing',
213- 'new_oci_project']
214+ 'search_oci_project', 'new_oci_project']
215 add_subscribe_link(links)
216 return links
217
218diff --git a/lib/lp/registry/browser/tests/test_distribution.py b/lib/lp/registry/browser/tests/test_distribution.py
219index f7f37fd..d3cd559 100644
220--- a/lib/lp/registry/browser/tests/test_distribution.py
221+++ b/lib/lp/registry/browser/tests/test_distribution.py
222@@ -26,21 +26,14 @@ from lp.services.webapp import canonical_url
223 from lp.services.webapp.publisher import RedirectionView
224 from lp.testing import (
225 admin_logged_in,
226- BrowserTestCase,
227 login_celebrity,
228 login_person,
229- record_two_runs,
230 TestCaseWithFactory,
231 )
232 from lp.testing.layers import (
233 DatabaseFunctionalLayer,
234 ZopelessDatabaseLayer,
235 )
236-from lp.testing.pages import (
237- extract_text,
238- find_tag_by_id,
239- find_tags_by_class,
240- )
241 from lp.testing.publication import test_traverse
242 from lp.testing.views import create_initialized_view
243
244@@ -211,133 +204,3 @@ class TestDistributionView(TestCaseWithFactory):
245 self.assertContentEqual(
246 team_membership_policy_data,
247 cache.objects['team_membership_policy_data'])
248-
249-
250-class TestDistributionOCIProjectSearchView(BrowserTestCase):
251-
252- layer = DatabaseFunctionalLayer
253-
254- def assertPaginationIsPresent(
255- self, browser, results_in_page, total_result):
256- """Checks that pagination is shown at the browser."""
257- nav_index = find_tags_by_class(
258- browser.contents, "batch-navigation-index")[0]
259- nav_index_text = extract_text(nav_index).replace('\n', ' ')
260- self.assertIn(
261- "1 → %s of %s results" % (results_in_page, total_result),
262- nav_index_text)
263-
264- nav_links = find_tags_by_class(
265- browser.contents, "batch-navigation-links")[0]
266- nav_links_text = extract_text(nav_links).replace('\n', ' ')
267- self.assertIn("First • Previous • Next • Last", nav_links_text)
268-
269- def assertOCIProjectsArePresent(self, browser, oci_projects):
270- table = find_tag_by_id(browser.contents, "projects_list")
271- with admin_logged_in():
272- for oci_project in oci_projects:
273- url = canonical_url(oci_project, force_local_path=True)
274- self.assertIn(url, str(table))
275- self.assertIn(oci_project.name, str(table))
276-
277- def assertOCIProjectsAreNotPresent(self, browser, oci_projects):
278- table = find_tag_by_id(browser.contents, "projects_list")
279- with admin_logged_in():
280- for oci_project in oci_projects:
281- url = canonical_url(oci_project, force_local_path=True)
282- self.assertNotIn(url, str(table))
283- self.assertNotIn(oci_project.name, str(table))
284-
285- def test_search_no_oci_projects(self):
286- person = self.factory.makePerson()
287- distribution = self.factory.makeDistribution()
288- browser = self.getViewBrowser(
289- distribution, user=person, view_name='+search-oci-project')
290-
291- main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0]
292- self.assertIn(
293- "There are no OCI projects registered for %s" % distribution.name,
294- extract_text(main_portlet).replace("\n", " "))
295-
296- def test_oci_projects_no_search_keyword(self):
297- person = self.factory.makePerson()
298- distro = self.factory.makeDistribution(owner=person)
299-
300- # Creates 3 OCI Projects
301- oci_projects = [
302- self.factory.makeOCIProject(
303- ociprojectname="test-project-%s" % i,
304- registrant=person, pillar=distro) for i in range(3)]
305-
306- browser = self.getViewBrowser(
307- distro, user=person, view_name='+search-oci-project')
308-
309- # Check top message.
310- main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0]
311- self.assertIn(
312- "There are 3 OCI projects registered for %s" % distro.name,
313- extract_text(main_portlet).replace("\n", " "))
314-
315- self.assertOCIProjectsArePresent(browser, oci_projects)
316- self.assertPaginationIsPresent(browser, 3, 3)
317-
318- def test_oci_projects_with_search_keyword(self):
319- person = self.factory.makePerson()
320- distro = self.factory.makeDistribution(owner=person)
321-
322- # And 2 OCI projects that will match the name
323- oci_projects = [
324- self.factory.makeOCIProject(
325- ociprojectname="find-me-%s" % i,
326- registrant=person, pillar=distro) for i in range(2)]
327-
328- # Creates 2 OCI Projects that will not match search
329- other_oci_projects = [
330- self.factory.makeOCIProject(
331- ociprojectname="something-%s" % i,
332- registrant=person, pillar=distro) for i in range(2)]
333-
334- browser = self.getViewBrowser(
335- distro, user=person, view_name='+search-oci-project')
336- browser.getControl(name="text").value = "find-me"
337- browser.getControl("Search").click()
338-
339- # Check top message.
340- main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0]
341- self.assertIn(
342- 'There are 2 OCI projects registered for %s matching "%s"' %
343- (distro.name, "find-me"),
344- extract_text(main_portlet).replace("\n", " "))
345-
346- self.assertOCIProjectsArePresent(browser, oci_projects)
347- self.assertOCIProjectsAreNotPresent(browser, other_oci_projects)
348- self.assertPaginationIsPresent(browser, 2, 2)
349-
350- def test_query_count_is_constant(self):
351- batch_size = 3
352- self.pushConfig("launchpad", default_batch_size=batch_size)
353-
354- person = self.factory.makePerson()
355- distro = self.factory.makeDistribution(owner=person)
356- name_pattern = "find-me-"
357-
358- def createOCIProject():
359- self.factory.makeOCIProject(
360- ociprojectname=self.factory.getUniqueString(name_pattern),
361- pillar=distro)
362-
363- viewer = self.factory.makePerson()
364-
365- def getView():
366- browser = self.getViewBrowser(
367- distro, user=viewer, view_name='+search-oci-project')
368- browser.getControl(name="text").value = name_pattern
369- browser.getControl("Search").click()
370- return browser
371-
372- def do_login():
373- login_person(person)
374-
375- recorder1, recorder2 = record_two_runs(
376- getView, createOCIProject, 1, 10, login_method=do_login)
377- self.assertEqual(recorder1.count, recorder2.count)
378diff --git a/lib/lp/registry/browser/tests/test_ociproject.py b/lib/lp/registry/browser/tests/test_ociproject.py
379index 648f4d4..9fb5822 100644
380--- a/lib/lp/registry/browser/tests/test_ociproject.py
381+++ b/lib/lp/registry/browser/tests/test_ociproject.py
382@@ -12,6 +12,7 @@ __all__ = []
383 from datetime import datetime
384
385 import pytz
386+from zope.security.proxy import removeSecurityProxy
387
388 from lp.oci.interfaces.ocirecipe import OCI_RECIPE_ALLOW_CREATE
389 from lp.registry.interfaces.ociproject import (
390@@ -25,7 +26,9 @@ from lp.services.webapp.escaping import structured
391 from lp.testing import (
392 admin_logged_in,
393 BrowserTestCase,
394+ login_person,
395 person_logged_in,
396+ record_two_runs,
397 test_tales,
398 TestCaseWithFactory,
399 )
400@@ -34,6 +37,7 @@ from lp.testing.matchers import MatchesTagText
401 from lp.testing.pages import (
402 extract_text,
403 find_main_content,
404+ find_tag_by_id,
405 find_tags_by_class,
406 )
407 from lp.testing.publication import test_traverse
408@@ -376,3 +380,162 @@ class TestOCIProjectAddView(BrowserTestCase):
409 new_distribution,
410 user=another_person,
411 view_name='+new-oci-project')
412+
413+
414+class TestOCIProjectSearchView(BrowserTestCase):
415+
416+ layer = DatabaseFunctionalLayer
417+
418+ def assertPaginationIsPresent(
419+ self, browser, results_in_page, total_result):
420+ """Checks that pagination is shown at the browser."""
421+ nav_index = find_tags_by_class(
422+ browser.contents, "batch-navigation-index")[0]
423+ nav_index_text = extract_text(nav_index).replace('\n', ' ')
424+ self.assertIn(
425+ "1 → %s of %s results" % (results_in_page, total_result),
426+ nav_index_text)
427+
428+ nav_links = find_tags_by_class(
429+ browser.contents, "batch-navigation-links")[0]
430+ nav_links_text = extract_text(nav_links).replace('\n', ' ')
431+ self.assertIn("First • Previous • Next • Last", nav_links_text)
432+
433+ def assertOCIProjectsArePresent(self, browser, oci_projects):
434+ table = find_tag_by_id(browser.contents, "projects_list")
435+ with admin_logged_in():
436+ for oci_project in oci_projects:
437+ url = canonical_url(oci_project, force_local_path=True)
438+ self.assertIn(url, str(table))
439+ self.assertIn(oci_project.name, str(table))
440+
441+ def assertOCIProjectsAreNotPresent(self, browser, oci_projects):
442+ table = find_tag_by_id(browser.contents, "projects_list")
443+ with admin_logged_in():
444+ for oci_project in oci_projects:
445+ url = canonical_url(oci_project, force_local_path=True)
446+ self.assertNotIn(url, str(table))
447+ self.assertNotIn(oci_project.name, str(table))
448+
449+ def check_search_no_oci_projects(self, pillar):
450+ pillar = removeSecurityProxy(pillar)
451+ person = self.factory.makePerson()
452+
453+ browser = self.getViewBrowser(
454+ pillar, user=person, view_name='+search-oci-project')
455+
456+ main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0]
457+ self.assertIn(
458+ "There are no OCI projects registered for %s" % pillar.name,
459+ extract_text(main_portlet).replace("\n", " "))
460+
461+ def test_search_no_oci_projects_distribution_pillar(self):
462+ return self.check_search_no_oci_projects(
463+ self.factory.makeDistribution())
464+
465+ def test_search_no_oci_projects_project_pillar(self):
466+ return self.check_search_no_oci_projects(self.factory.makeProduct())
467+
468+ def check_oci_projects_no_search_keyword(self, pillar):
469+ pillar = removeSecurityProxy(pillar)
470+ person = pillar.owner
471+
472+ # Creates 3 OCI Projects
473+ oci_projects = [
474+ self.factory.makeOCIProject(
475+ ociprojectname="test-project-%s" % i,
476+ registrant=person, pillar=pillar) for i in range(3)]
477+
478+ browser = self.getViewBrowser(
479+ pillar, user=person, view_name='+search-oci-project')
480+
481+ # Check top message.
482+ main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0]
483+ self.assertIn(
484+ "There are 3 OCI projects registered for %s" % pillar.name,
485+ extract_text(main_portlet).replace("\n", " "))
486+
487+ self.assertOCIProjectsArePresent(browser, oci_projects)
488+ self.assertPaginationIsPresent(browser, 3, 3)
489+
490+ def test_oci_projects_no_search_keyword_for_distribution(self):
491+ return self.check_oci_projects_no_search_keyword(
492+ self.factory.makeDistribution())
493+
494+ def test_oci_projects_no_search_keyword_for_project(self):
495+ return self.check_oci_projects_no_search_keyword(
496+ self.factory.makeProduct())
497+
498+ def check_oci_projects_with_search_keyword(self, pillar):
499+ pillar = removeSecurityProxy(pillar)
500+ person = pillar.owner
501+
502+ # And 2 OCI projects that will match the name
503+ oci_projects = [
504+ self.factory.makeOCIProject(
505+ ociprojectname="find-me-%s" % i,
506+ registrant=person, pillar=pillar) for i in range(2)]
507+
508+ # Creates 2 OCI Projects that will not match search
509+ other_oci_projects = [
510+ self.factory.makeOCIProject(
511+ ociprojectname="something-%s" % i,
512+ registrant=person, pillar=pillar) for i in range(2)]
513+
514+ browser = self.getViewBrowser(
515+ pillar, user=person, view_name='+search-oci-project')
516+ browser.getControl(name="text").value = "find-me"
517+ browser.getControl("Search").click()
518+
519+ # Check top message.
520+ main_portlet = find_tags_by_class(browser.contents, "main-portlet")[0]
521+ self.assertIn(
522+ 'There are 2 OCI projects registered for %s matching "%s"' %
523+ (pillar.name, "find-me"),
524+ extract_text(main_portlet).replace("\n", " "))
525+
526+ self.assertOCIProjectsArePresent(browser, oci_projects)
527+ self.assertOCIProjectsAreNotPresent(browser, other_oci_projects)
528+ self.assertPaginationIsPresent(browser, 2, 2)
529+
530+ def test_oci_projects_with_search_keyword_for_distribution(self):
531+ self.check_oci_projects_with_search_keyword(
532+ self.factory.makeDistribution())
533+
534+ def test_oci_projects_with_search_keyword_for_project(self):
535+ self.check_oci_projects_with_search_keyword(self.factory.makeProduct())
536+
537+ def check_query_count_is_constant(self, pillar):
538+ batch_size = 3
539+ self.pushConfig("launchpad", default_batch_size=batch_size)
540+
541+ person = self.factory.makePerson()
542+ distro = self.factory.makeDistribution(owner=person)
543+ name_pattern = "find-me-"
544+
545+ def createOCIProject():
546+ self.factory.makeOCIProject(
547+ ociprojectname=self.factory.getUniqueString(name_pattern),
548+ pillar=distro)
549+
550+ viewer = self.factory.makePerson()
551+
552+ def getView():
553+ browser = self.getViewBrowser(
554+ distro, user=viewer, view_name='+search-oci-project')
555+ browser.getControl(name="text").value = name_pattern
556+ browser.getControl("Search").click()
557+ return browser
558+
559+ def do_login():
560+ login_person(person)
561+
562+ recorder1, recorder2 = record_two_runs(
563+ getView, createOCIProject, 1, 10, login_method=do_login)
564+ self.assertEqual(recorder1.count, recorder2.count)
565+
566+ def test_query_count_is_constant_for_distribution(self):
567+ self.check_query_count_is_constant(self.factory.makeDistribution())
568+
569+ def test_query_count_is_constant_for_project(self):
570+ self.check_query_count_is_constant(self.factory.makeProduct())
571diff --git a/lib/lp/registry/interfaces/ociproject.py b/lib/lp/registry/interfaces/ociproject.py
572index ad3e121..1344093 100644
573--- a/lib/lp/registry/interfaces/ociproject.py
574+++ b/lib/lp/registry/interfaces/ociproject.py
575@@ -202,9 +202,9 @@ class IOCIProjectSet(Interface):
576 :return: The OCIProject found.
577 """
578
579- def findByDistributionAndName(distribution, name_substring):
580- """Find OCIProjects for a given distribution that contains the
581- provided name."""
582+ def findByPillarAndName(pillar, name_substring):
583+ """Find OCIProjects for a given pillar that contain the provided
584+ name."""
585
586 def preloadDataForOCIProjects(oci_projects):
587 """Preload data for the given list of OCIProject objects."""
588diff --git a/lib/lp/registry/model/ociproject.py b/lib/lp/registry/model/ociproject.py
589index b991c19..28b3dc0 100644
590--- a/lib/lp/registry/model/ociproject.py
591+++ b/lib/lp/registry/model/ociproject.py
592@@ -269,11 +269,11 @@ class OCIProjectSet:
593 OCIProjectName.name == name).one()
594 return target
595
596- def findByDistributionAndName(self, distribution, name_substring):
597+ def findByPillarAndName(self, pillar, name_substring):
598 """See `IOCIProjectSet`."""
599 return IStore(OCIProject).find(
600 OCIProject,
601- OCIProject.distribution == distribution,
602+ self._get_pillar_attribute(pillar) == pillar,
603 OCIProject.ociprojectname == OCIProjectName.id,
604 OCIProjectName.name.contains_string(name_substring))
605
606diff --git a/lib/lp/registry/templates/distribution-search-oci-projects.pt b/lib/lp/registry/templates/search-oci-projects.pt
607similarity index 100%
608rename from lib/lp/registry/templates/distribution-search-oci-projects.pt
609rename to lib/lp/registry/templates/search-oci-projects.pt