Merge ~pappacena/launchpad:snap-project-links into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: ba0d466630b10f9a1cd7946e96e030c3be96e447
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:snap-project-links
Merge into: launchpad:master
Prerequisite: ~pappacena/launchpad:snap-create-on-project
Diff against target: 305 lines (+98/-59)
7 files modified
lib/lp/code/browser/tests/test_product.py (+28/-3)
lib/lp/registry/browser/product.py (+3/-1)
lib/lp/registry/templates/product-index.pt (+5/-1)
lib/lp/snappy/browser/snap.py (+16/-17)
lib/lp/snappy/model/snap.py (+6/-2)
lib/lp/snappy/templates/snap-new.pt (+35/-32)
lib/lp/snappy/tests/test_snap.py (+5/-3)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+399224@code.launchpad.net

Commit message

Adding +new-snap link to project page

Description of the change

This is a complementary MP for the +new-snap page on project (https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/399184)

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Otto Co-Pilot (otto-copilot) wrote :

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 2115eb5..61a6240 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-2020 Canonical Ltd. This software is licensed under the
7+# Copyright 2009-2021 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@@ -430,14 +430,39 @@ class TestCanConfigureBranches(TestCaseWithFactory):
12 self.assertTrue(view.can_configure_branches())
13
14
15-class TestProductOverviewOCIProject(TestCaseWithFactory):
16+class TestProductOverviewLinks(TestCaseWithFactory):
17
18 layer = DatabaseFunctionalLayer
19
20 def setUp(self, user=ANONYMOUS):
21- super(TestProductOverviewOCIProject, self).setUp(user)
22+ super(TestProductOverviewLinks, self).setUp(user)
23 self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: True}))
24
25+ def test_displays_create_and_list_snaps(self):
26+ project = self.factory.makeProduct()
27+ self.factory.makeSnap(project=project)
28+
29+ browser = self.getUserBrowser(
30+ canonical_url(project), user=project.owner)
31+ text = extract_text(
32+ find_tag_by_id(browser.contents, 'project-link-info'))
33+
34+ # Search link should be available because we have an Snap created.
35+ self.assertIn("View snap packages", text)
36+ self.assertIn("Create snap package", text)
37+
38+ def test_hides_list_snaps_if_no_snap_is_available(self):
39+ project = self.factory.makeProduct()
40+
41+ browser = self.getUserBrowser(
42+ canonical_url(project), user=project.owner)
43+ text = extract_text(
44+ find_tag_by_id(browser.contents, 'project-link-info'))
45+
46+ # Search link should not be available.
47+ self.assertNotIn("View snap packages", text)
48+ self.assertIn("Create snap package", text)
49+
50 def test_displays_create_and_list_oci_project_link_for_owner(self):
51 product = self.factory.makeProduct()
52 self.factory.makeOCIProject(pillar=product)
53diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py
54index 780c236..df7ee7a 100644
55--- a/lib/lp/registry/browser/product.py
56+++ b/lib/lp/registry/browser/product.py
57@@ -1,4 +1,4 @@
58-# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
59+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
60 # GNU Affero General Public License version 3 (see the file LICENSE).
61
62 """Browser views for products."""
63@@ -233,6 +233,7 @@ from lp.services.webapp.vhosts import allvhosts
64 from lp.services.worlddata.helpers import browser_languages
65 from lp.services.worlddata.interfaces.country import ICountry
66 from lp.snappy.browser.hassnaps import HasSnapsMenuMixin
67+from lp.snappy.interfaces.snap import ISnapSet
68 from lp.translations.browser.customlanguagecode import (
69 HasCustomLanguageCodesTraversalMixin,
70 )
71@@ -585,6 +586,7 @@ class ProductOverviewMenu(ApplicationMenu, ProductEditLinksMixin,
72 'branding',
73 'view_recipes',
74 'view_snaps',
75+ 'create_snap',
76 ]
77
78 def top_contributors(self):
79diff --git a/lib/lp/registry/templates/product-index.pt b/lib/lp/registry/templates/product-index.pt
80index a22574c..73d339b 100644
81--- a/lib/lp/registry/templates/product-index.pt
82+++ b/lib/lp/registry/templates/product-index.pt
83@@ -168,7 +168,7 @@
84 <a tal:replace="structure overview_menu/edit/fmt:icon" />
85 </p>
86
87- <ul class="horizontal">
88+ <ul class="horizontal" id="project-link-info">
89 <li tal:condition="overview_menu/series_add/enabled">
90 <a tal:replace="structure overview_menu/series_add/fmt:link" />
91 </li>
92@@ -183,6 +183,10 @@
93 tal:condition="link/enabled">
94 <a tal:replace="structure link/fmt:link" />
95 </li>
96+ <li tal:define="link context/menu:overview/create_snap"
97+ tal:condition="link/enabled">
98+ <a tal:replace="structure link/fmt:link" />
99+ </li>
100 </ul>
101 </div>
102 </div>
103diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py
104index d189323..c8c2edb 100644
105--- a/lib/lp/snappy/browser/snap.py
106+++ b/lib/lp/snappy/browser/snap.py
107@@ -143,16 +143,19 @@ class SnapNavigation(WebhookTargetNavigationMixin, Navigation):
108 class SnapFormMixin:
109 def validateVCSWidgets(self, cls, data):
110 """Validates if VCS sub-widgets."""
111- # Set widgets as required or optional depending on the vcs field.
112- vcs = data.get('vcs')
113- if vcs == VCSType.BZR:
114- self.widgets['branch'].context.required = True
115- self.widgets['git_ref'].context.required = False
116- elif vcs == VCSType.GIT:
117- self.widgets['branch'].context.required = False
118- self.widgets['git_ref'].context.required = True
119- else:
120- raise AssertionError("Unknown branch type %s" % vcs)
121+ if self.widgets.get('vcs') is not None:
122+ # Set widgets as required or optional depending on the vcs
123+ # field.
124+ super(cls, self).validate_widgets(data, ['vcs'])
125+ vcs = data.get('vcs')
126+ if vcs == VCSType.BZR:
127+ self.widgets['branch'].context.required = True
128+ self.widgets['git_ref'].context.required = False
129+ elif vcs == VCSType.GIT:
130+ self.widgets['branch'].context.required = False
131+ self.widgets['git_ref'].context.required = True
132+ else:
133+ raise AssertionError("Unknown branch type %s" % vcs)
134
135 def setUpVCSWidgets(self):
136 widget = self.widgets.get('vcs')
137@@ -570,7 +573,7 @@ class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin,
138 self.widgets['processors'].widget_class = 'processors'
139 if self.is_project_context:
140 # If we are on Project:+new-snap page, we know which information
141- # types the project supports. Let's filter out the ones that are
142+ # types the project supports. Let's filter our the ones that are
143 # not supported.
144 types = getUtility(ISnapSet).getPossibleSnapInformationTypes(
145 self.context)
146@@ -630,9 +633,7 @@ class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin,
147
148 def validate_widgets(self, data, names=None):
149 """See `LaunchpadFormView`."""
150- if self.widgets.get('vcs') is not None:
151- super(SnapAddView, self).validate_widgets(data, ['vcs'])
152- self.validateVCSWidgets(SnapAddView, data)
153+ self.validateVCSWidgets(SnapAddView, data)
154 if self.widgets.get('auto_build') is not None:
155 # Set widgets as required or optional depending on the
156 # auto_build field.
157@@ -718,9 +719,7 @@ class BaseSnapEditView(LaunchpadEditFormView, SnapAuthorizeMixin,
158
159 def validate_widgets(self, data, names=None):
160 """See `LaunchpadFormView`."""
161- if self.widgets.get('vcs') is not None:
162- super(BaseSnapEditView, self).validate_widgets(data, ['vcs'])
163- self.validateVCSWidgets(BaseSnapEditView, data)
164+ self.validateVCSWidgets(BaseSnapEditView, data)
165 if self.widgets.get('auto_build') is not None:
166 # Set widgets as required or optional depending on the
167 # auto_build field.
168diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
169index 36e8a56..eeed37b 100644
170--- a/lib/lp/snappy/model/snap.py
171+++ b/lib/lp/snappy/model/snap.py
172@@ -1393,7 +1393,6 @@ class SnapSet:
173 """See `ISnapSet`."""
174 return BRANCH_POLICY_ALLOWED_TYPES[project.branch_sharing_policy]
175
176-
177 def isValidInformationType(self, information_type, owner, branch=None,
178 git_ref=None):
179 private = information_type not in PUBLIC_INFORMATION_TYPES
180@@ -1479,9 +1478,14 @@ class SnapSet:
181 collection.visibleByUser(visible_by_user),
182 visible_by_user=visible_by_user)
183
184+ snaps_for_project = IStore(Snap).find(
185+ Snap,
186+ Snap.project == project,
187+ get_snap_privacy_filter(visible_by_user))
188 bzr_collection = removeSecurityProxy(IBranchCollection(project))
189 git_collection = removeSecurityProxy(IGitCollection(project))
190- return _getSnaps(bzr_collection).union(_getSnaps(git_collection))
191+ return snaps_for_project.union(
192+ _getSnaps(bzr_collection)).union(_getSnaps(git_collection))
193
194 def findByBranch(self, branch, visible_by_user=None):
195 """See `ISnapSet`."""
196diff --git a/lib/lp/snappy/templates/snap-new.pt b/lib/lp/snappy/templates/snap-new.pt
197index 480d51c..146d2cb 100644
198--- a/lib/lp/snappy/templates/snap-new.pt
199+++ b/lib/lp/snappy/templates/snap-new.pt
200@@ -40,38 +40,41 @@
201 <metal:block use-macro="context/@@launchpad_form/widget_row" />
202 </tal:widget>
203
204- <tr tal:condition="view/is_project_context">
205- <td>
206- <div>
207- <label for="field.vcs">Source:</label>
208- <table>
209- <tr>
210- <td>
211- <label tal:replace="structure view/vcs_bzr_radio" />
212- <table class="subordinate">
213- <tal:widget define="widget nocall:view/widgets/branch">
214- <metal:block
215- use-macro="context/@@launchpad_form/widget_row" />
216- </tal:widget>
217- </table>
218- </td>
219- </tr>
220- <tr>
221- <td>
222- <label tal:replace="structure view/vcs_git_radio" />
223- <table class="subordinate">
224- <tal:widget define="widget
225- nocall:view/widgets/git_ref">
226- <metal:block
227- use-macro="context/@@launchpad_form/widget_row" />
228- </tal:widget>
229- </table>
230- </td>
231- </tr>
232- </table>
233- </div>
234- </td>
235- </tr>
236+ <tal:guard condition="view/is_project_context">
237+ <tr>
238+ <td>
239+ <div>
240+ <label for="field.vcs">Source:</label>
241+ <table>
242+ <tr>
243+ <td>
244+ <label tal:replace="structure view/vcs_bzr_radio" />
245+ <table class="subordinate">
246+ <tal:widget define="widget nocall:view/widgets/branch">
247+ <metal:block
248+ use-macro="context/@@launchpad_form/widget_row" />
249+ </tal:widget>
250+ </table>
251+ </td>
252+ </tr>
253+
254+ <tr>
255+ <td>
256+ <label tal:replace="structure view/vcs_git_radio" />
257+ <table class="subordinate">
258+ <tal:widget define="widget
259+ nocall:view/widgets/git_ref">
260+ <metal:block
261+ use-macro="context/@@launchpad_form/widget_row" />
262+ </tal:widget>
263+ </table>
264+ </td>
265+ </tr>
266+ </table>
267+ </div>
268+ </td>
269+ </tr>
270+ </tal:guard>
271
272 <tal:widget define="widget nocall:view/widgets/store_distro_series">
273 <metal:block use-macro="context/@@launchpad_form/widget_row" />
274diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
275index 0c6f68e..5f9ba74 100644
276--- a/lib/lp/snappy/tests/test_snap.py
277+++ b/lib/lp/snappy/tests/test_snap.py
278@@ -1752,7 +1752,8 @@ class TestSnapSet(TestCaseWithFactory):
279
280 def test_findByProject(self):
281 # ISnapSet.findByProject returns all Snaps based on branches or
282- # repositories for the given project.
283+ # repositories for the given project, and snaps associated directly
284+ # to the project.
285 projects = [self.factory.makeProduct() for i in range(2)]
286 snaps = []
287 for project in projects:
288@@ -1760,14 +1761,15 @@ class TestSnapSet(TestCaseWithFactory):
289 branch=self.factory.makeProductBranch(product=project)))
290 [ref] = self.factory.makeGitRefs(target=project)
291 snaps.append(self.factory.makeSnap(git_ref=ref))
292+ snaps.append(self.factory.makeSnap(project=project))
293 snaps.append(self.factory.makeSnap(
294 branch=self.factory.makePersonalBranch()))
295 [ref] = self.factory.makeGitRefs(target=None)
296 snaps.append(self.factory.makeSnap(git_ref=ref))
297 snap_set = getUtility(ISnapSet)
298- self.assertContentEqual(snaps[:2], snap_set.findByProject(projects[0]))
299+ self.assertContentEqual(snaps[:3], snap_set.findByProject(projects[0]))
300 self.assertContentEqual(
301- snaps[2:4], snap_set.findByProject(projects[1]))
302+ snaps[3:6], snap_set.findByProject(projects[1]))
303
304 def test_findByBranch(self):
305 # ISnapSet.findByBranch returns all Snaps with the given Bazaar branch.