Merge ~pappacena/launchpad:snap-project-links into launchpad:master
- Git
- lp:~pappacena/launchpad
- snap-project-links
- Merge into 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) |
Related bugs: |
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:/
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
1 | diff --git a/lib/lp/code/browser/tests/test_product.py b/lib/lp/code/browser/tests/test_product.py | |||
2 | index 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 @@ | |||
7 | 1 | # Copyright 2009-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
8 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
9 | 3 | 3 | ||
10 | 4 | """Tests for the product view classes and templates.""" | 4 | """Tests for the product view classes and templates.""" |
11 | @@ -430,14 +430,39 @@ class TestCanConfigureBranches(TestCaseWithFactory): | |||
12 | 430 | self.assertTrue(view.can_configure_branches()) | 430 | self.assertTrue(view.can_configure_branches()) |
13 | 431 | 431 | ||
14 | 432 | 432 | ||
16 | 433 | class TestProductOverviewOCIProject(TestCaseWithFactory): | 433 | class TestProductOverviewLinks(TestCaseWithFactory): |
17 | 434 | 434 | ||
18 | 435 | layer = DatabaseFunctionalLayer | 435 | layer = DatabaseFunctionalLayer |
19 | 436 | 436 | ||
20 | 437 | def setUp(self, user=ANONYMOUS): | 437 | def setUp(self, user=ANONYMOUS): |
22 | 438 | super(TestProductOverviewOCIProject, self).setUp(user) | 438 | super(TestProductOverviewLinks, self).setUp(user) |
23 | 439 | self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: True})) | 439 | self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: True})) |
24 | 440 | 440 | ||
25 | 441 | def test_displays_create_and_list_snaps(self): | ||
26 | 442 | project = self.factory.makeProduct() | ||
27 | 443 | self.factory.makeSnap(project=project) | ||
28 | 444 | |||
29 | 445 | browser = self.getUserBrowser( | ||
30 | 446 | canonical_url(project), user=project.owner) | ||
31 | 447 | text = extract_text( | ||
32 | 448 | find_tag_by_id(browser.contents, 'project-link-info')) | ||
33 | 449 | |||
34 | 450 | # Search link should be available because we have an Snap created. | ||
35 | 451 | self.assertIn("View snap packages", text) | ||
36 | 452 | self.assertIn("Create snap package", text) | ||
37 | 453 | |||
38 | 454 | def test_hides_list_snaps_if_no_snap_is_available(self): | ||
39 | 455 | project = self.factory.makeProduct() | ||
40 | 456 | |||
41 | 457 | browser = self.getUserBrowser( | ||
42 | 458 | canonical_url(project), user=project.owner) | ||
43 | 459 | text = extract_text( | ||
44 | 460 | find_tag_by_id(browser.contents, 'project-link-info')) | ||
45 | 461 | |||
46 | 462 | # Search link should not be available. | ||
47 | 463 | self.assertNotIn("View snap packages", text) | ||
48 | 464 | self.assertIn("Create snap package", text) | ||
49 | 465 | |||
50 | 441 | def test_displays_create_and_list_oci_project_link_for_owner(self): | 466 | def test_displays_create_and_list_oci_project_link_for_owner(self): |
51 | 442 | product = self.factory.makeProduct() | 467 | product = self.factory.makeProduct() |
52 | 443 | self.factory.makeOCIProject(pillar=product) | 468 | self.factory.makeOCIProject(pillar=product) |
53 | diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py | |||
54 | index 780c236..df7ee7a 100644 | |||
55 | --- a/lib/lp/registry/browser/product.py | |||
56 | +++ b/lib/lp/registry/browser/product.py | |||
57 | @@ -1,4 +1,4 @@ | |||
59 | 1 | # Copyright 2009-2020 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2021 Canonical Ltd. This software is licensed under the |
60 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
61 | 3 | 3 | ||
62 | 4 | """Browser views for products.""" | 4 | """Browser views for products.""" |
63 | @@ -233,6 +233,7 @@ from lp.services.webapp.vhosts import allvhosts | |||
64 | 233 | from lp.services.worlddata.helpers import browser_languages | 233 | from lp.services.worlddata.helpers import browser_languages |
65 | 234 | from lp.services.worlddata.interfaces.country import ICountry | 234 | from lp.services.worlddata.interfaces.country import ICountry |
66 | 235 | from lp.snappy.browser.hassnaps import HasSnapsMenuMixin | 235 | from lp.snappy.browser.hassnaps import HasSnapsMenuMixin |
67 | 236 | from lp.snappy.interfaces.snap import ISnapSet | ||
68 | 236 | from lp.translations.browser.customlanguagecode import ( | 237 | from lp.translations.browser.customlanguagecode import ( |
69 | 237 | HasCustomLanguageCodesTraversalMixin, | 238 | HasCustomLanguageCodesTraversalMixin, |
70 | 238 | ) | 239 | ) |
71 | @@ -585,6 +586,7 @@ class ProductOverviewMenu(ApplicationMenu, ProductEditLinksMixin, | |||
72 | 585 | 'branding', | 586 | 'branding', |
73 | 586 | 'view_recipes', | 587 | 'view_recipes', |
74 | 587 | 'view_snaps', | 588 | 'view_snaps', |
75 | 589 | 'create_snap', | ||
76 | 588 | ] | 590 | ] |
77 | 589 | 591 | ||
78 | 590 | def top_contributors(self): | 592 | def top_contributors(self): |
79 | diff --git a/lib/lp/registry/templates/product-index.pt b/lib/lp/registry/templates/product-index.pt | |||
80 | index 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 | 168 | <a tal:replace="structure overview_menu/edit/fmt:icon" /> | 168 | <a tal:replace="structure overview_menu/edit/fmt:icon" /> |
85 | 169 | </p> | 169 | </p> |
86 | 170 | 170 | ||
88 | 171 | <ul class="horizontal"> | 171 | <ul class="horizontal" id="project-link-info"> |
89 | 172 | <li tal:condition="overview_menu/series_add/enabled"> | 172 | <li tal:condition="overview_menu/series_add/enabled"> |
90 | 173 | <a tal:replace="structure overview_menu/series_add/fmt:link" /> | 173 | <a tal:replace="structure overview_menu/series_add/fmt:link" /> |
91 | 174 | </li> | 174 | </li> |
92 | @@ -183,6 +183,10 @@ | |||
93 | 183 | tal:condition="link/enabled"> | 183 | tal:condition="link/enabled"> |
94 | 184 | <a tal:replace="structure link/fmt:link" /> | 184 | <a tal:replace="structure link/fmt:link" /> |
95 | 185 | </li> | 185 | </li> |
96 | 186 | <li tal:define="link context/menu:overview/create_snap" | ||
97 | 187 | tal:condition="link/enabled"> | ||
98 | 188 | <a tal:replace="structure link/fmt:link" /> | ||
99 | 189 | </li> | ||
100 | 186 | </ul> | 190 | </ul> |
101 | 187 | </div> | 191 | </div> |
102 | 188 | </div> | 192 | </div> |
103 | diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py | |||
104 | index 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 | 143 | class SnapFormMixin: | 143 | class SnapFormMixin: |
109 | 144 | def validateVCSWidgets(self, cls, data): | 144 | def validateVCSWidgets(self, cls, data): |
110 | 145 | """Validates if VCS sub-widgets.""" | 145 | """Validates if VCS sub-widgets.""" |
121 | 146 | # Set widgets as required or optional depending on the vcs field. | 146 | if self.widgets.get('vcs') is not None: |
122 | 147 | vcs = data.get('vcs') | 147 | # Set widgets as required or optional depending on the vcs |
123 | 148 | if vcs == VCSType.BZR: | 148 | # field. |
124 | 149 | self.widgets['branch'].context.required = True | 149 | super(cls, self).validate_widgets(data, ['vcs']) |
125 | 150 | self.widgets['git_ref'].context.required = False | 150 | vcs = data.get('vcs') |
126 | 151 | elif vcs == VCSType.GIT: | 151 | if vcs == VCSType.BZR: |
127 | 152 | self.widgets['branch'].context.required = False | 152 | self.widgets['branch'].context.required = True |
128 | 153 | self.widgets['git_ref'].context.required = True | 153 | self.widgets['git_ref'].context.required = False |
129 | 154 | else: | 154 | elif vcs == VCSType.GIT: |
130 | 155 | raise AssertionError("Unknown branch type %s" % vcs) | 155 | self.widgets['branch'].context.required = False |
131 | 156 | self.widgets['git_ref'].context.required = True | ||
132 | 157 | else: | ||
133 | 158 | raise AssertionError("Unknown branch type %s" % vcs) | ||
134 | 156 | 159 | ||
135 | 157 | def setUpVCSWidgets(self): | 160 | def setUpVCSWidgets(self): |
136 | 158 | widget = self.widgets.get('vcs') | 161 | widget = self.widgets.get('vcs') |
137 | @@ -570,7 +573,7 @@ class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin, | |||
138 | 570 | self.widgets['processors'].widget_class = 'processors' | 573 | self.widgets['processors'].widget_class = 'processors' |
139 | 571 | if self.is_project_context: | 574 | if self.is_project_context: |
140 | 572 | # If we are on Project:+new-snap page, we know which information | 575 | # If we are on Project:+new-snap page, we know which information |
142 | 573 | # types the project supports. Let's filter out the ones that are | 576 | # types the project supports. Let's filter our the ones that are |
143 | 574 | # not supported. | 577 | # not supported. |
144 | 575 | types = getUtility(ISnapSet).getPossibleSnapInformationTypes( | 578 | types = getUtility(ISnapSet).getPossibleSnapInformationTypes( |
145 | 576 | self.context) | 579 | self.context) |
146 | @@ -630,9 +633,7 @@ class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin, | |||
147 | 630 | 633 | ||
148 | 631 | def validate_widgets(self, data, names=None): | 634 | def validate_widgets(self, data, names=None): |
149 | 632 | """See `LaunchpadFormView`.""" | 635 | """See `LaunchpadFormView`.""" |
153 | 633 | if self.widgets.get('vcs') is not None: | 636 | self.validateVCSWidgets(SnapAddView, data) |
151 | 634 | super(SnapAddView, self).validate_widgets(data, ['vcs']) | ||
152 | 635 | self.validateVCSWidgets(SnapAddView, data) | ||
154 | 636 | if self.widgets.get('auto_build') is not None: | 637 | if self.widgets.get('auto_build') is not None: |
155 | 637 | # Set widgets as required or optional depending on the | 638 | # Set widgets as required or optional depending on the |
156 | 638 | # auto_build field. | 639 | # auto_build field. |
157 | @@ -718,9 +719,7 @@ class BaseSnapEditView(LaunchpadEditFormView, SnapAuthorizeMixin, | |||
158 | 718 | 719 | ||
159 | 719 | def validate_widgets(self, data, names=None): | 720 | def validate_widgets(self, data, names=None): |
160 | 720 | """See `LaunchpadFormView`.""" | 721 | """See `LaunchpadFormView`.""" |
164 | 721 | if self.widgets.get('vcs') is not None: | 722 | self.validateVCSWidgets(BaseSnapEditView, data) |
162 | 722 | super(BaseSnapEditView, self).validate_widgets(data, ['vcs']) | ||
163 | 723 | self.validateVCSWidgets(BaseSnapEditView, data) | ||
165 | 724 | if self.widgets.get('auto_build') is not None: | 723 | if self.widgets.get('auto_build') is not None: |
166 | 725 | # Set widgets as required or optional depending on the | 724 | # Set widgets as required or optional depending on the |
167 | 726 | # auto_build field. | 725 | # auto_build field. |
168 | diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py | |||
169 | index 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 | 1393 | """See `ISnapSet`.""" | 1393 | """See `ISnapSet`.""" |
174 | 1394 | return BRANCH_POLICY_ALLOWED_TYPES[project.branch_sharing_policy] | 1394 | return BRANCH_POLICY_ALLOWED_TYPES[project.branch_sharing_policy] |
175 | 1395 | 1395 | ||
176 | 1396 | |||
177 | 1397 | def isValidInformationType(self, information_type, owner, branch=None, | 1396 | def isValidInformationType(self, information_type, owner, branch=None, |
178 | 1398 | git_ref=None): | 1397 | git_ref=None): |
179 | 1399 | private = information_type not in PUBLIC_INFORMATION_TYPES | 1398 | private = information_type not in PUBLIC_INFORMATION_TYPES |
180 | @@ -1479,9 +1478,14 @@ class SnapSet: | |||
181 | 1479 | collection.visibleByUser(visible_by_user), | 1478 | collection.visibleByUser(visible_by_user), |
182 | 1480 | visible_by_user=visible_by_user) | 1479 | visible_by_user=visible_by_user) |
183 | 1481 | 1480 | ||
184 | 1481 | snaps_for_project = IStore(Snap).find( | ||
185 | 1482 | Snap, | ||
186 | 1483 | Snap.project == project, | ||
187 | 1484 | get_snap_privacy_filter(visible_by_user)) | ||
188 | 1482 | bzr_collection = removeSecurityProxy(IBranchCollection(project)) | 1485 | bzr_collection = removeSecurityProxy(IBranchCollection(project)) |
189 | 1483 | git_collection = removeSecurityProxy(IGitCollection(project)) | 1486 | git_collection = removeSecurityProxy(IGitCollection(project)) |
191 | 1484 | return _getSnaps(bzr_collection).union(_getSnaps(git_collection)) | 1487 | return snaps_for_project.union( |
192 | 1488 | _getSnaps(bzr_collection)).union(_getSnaps(git_collection)) | ||
193 | 1485 | 1489 | ||
194 | 1486 | def findByBranch(self, branch, visible_by_user=None): | 1490 | def findByBranch(self, branch, visible_by_user=None): |
195 | 1487 | """See `ISnapSet`.""" | 1491 | """See `ISnapSet`.""" |
196 | diff --git a/lib/lp/snappy/templates/snap-new.pt b/lib/lp/snappy/templates/snap-new.pt | |||
197 | index 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 | 40 | <metal:block use-macro="context/@@launchpad_form/widget_row" /> | 40 | <metal:block use-macro="context/@@launchpad_form/widget_row" /> |
202 | 41 | </tal:widget> | 41 | </tal:widget> |
203 | 42 | 42 | ||
236 | 43 | <tr tal:condition="view/is_project_context"> | 43 | <tal:guard condition="view/is_project_context"> |
237 | 44 | <td> | 44 | <tr> |
238 | 45 | <div> | 45 | <td> |
239 | 46 | <label for="field.vcs">Source:</label> | 46 | <div> |
240 | 47 | <table> | 47 | <label for="field.vcs">Source:</label> |
241 | 48 | <tr> | 48 | <table> |
242 | 49 | <td> | 49 | <tr> |
243 | 50 | <label tal:replace="structure view/vcs_bzr_radio" /> | 50 | <td> |
244 | 51 | <table class="subordinate"> | 51 | <label tal:replace="structure view/vcs_bzr_radio" /> |
245 | 52 | <tal:widget define="widget nocall:view/widgets/branch"> | 52 | <table class="subordinate"> |
246 | 53 | <metal:block | 53 | <tal:widget define="widget nocall:view/widgets/branch"> |
247 | 54 | use-macro="context/@@launchpad_form/widget_row" /> | 54 | <metal:block |
248 | 55 | </tal:widget> | 55 | use-macro="context/@@launchpad_form/widget_row" /> |
249 | 56 | </table> | 56 | </tal:widget> |
250 | 57 | </td> | 57 | </table> |
251 | 58 | </tr> | 58 | </td> |
252 | 59 | <tr> | 59 | </tr> |
253 | 60 | <td> | 60 | |
254 | 61 | <label tal:replace="structure view/vcs_git_radio" /> | 61 | <tr> |
255 | 62 | <table class="subordinate"> | 62 | <td> |
256 | 63 | <tal:widget define="widget | 63 | <label tal:replace="structure view/vcs_git_radio" /> |
257 | 64 | nocall:view/widgets/git_ref"> | 64 | <table class="subordinate"> |
258 | 65 | <metal:block | 65 | <tal:widget define="widget |
259 | 66 | use-macro="context/@@launchpad_form/widget_row" /> | 66 | nocall:view/widgets/git_ref"> |
260 | 67 | </tal:widget> | 67 | <metal:block |
261 | 68 | </table> | 68 | use-macro="context/@@launchpad_form/widget_row" /> |
262 | 69 | </td> | 69 | </tal:widget> |
263 | 70 | </tr> | 70 | </table> |
264 | 71 | </table> | 71 | </td> |
265 | 72 | </div> | 72 | </tr> |
266 | 73 | </td> | 73 | </table> |
267 | 74 | </tr> | 74 | </div> |
268 | 75 | </td> | ||
269 | 76 | </tr> | ||
270 | 77 | </tal:guard> | ||
271 | 75 | 78 | ||
272 | 76 | <tal:widget define="widget nocall:view/widgets/store_distro_series"> | 79 | <tal:widget define="widget nocall:view/widgets/store_distro_series"> |
273 | 77 | <metal:block use-macro="context/@@launchpad_form/widget_row" /> | 80 | <metal:block use-macro="context/@@launchpad_form/widget_row" /> |
274 | diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py | |||
275 | index 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 | 1752 | 1752 | ||
280 | 1753 | def test_findByProject(self): | 1753 | def test_findByProject(self): |
281 | 1754 | # ISnapSet.findByProject returns all Snaps based on branches or | 1754 | # ISnapSet.findByProject returns all Snaps based on branches or |
283 | 1755 | # repositories for the given project. | 1755 | # repositories for the given project, and snaps associated directly |
284 | 1756 | # to the project. | ||
285 | 1756 | projects = [self.factory.makeProduct() for i in range(2)] | 1757 | projects = [self.factory.makeProduct() for i in range(2)] |
286 | 1757 | snaps = [] | 1758 | snaps = [] |
287 | 1758 | for project in projects: | 1759 | for project in projects: |
288 | @@ -1760,14 +1761,15 @@ class TestSnapSet(TestCaseWithFactory): | |||
289 | 1760 | branch=self.factory.makeProductBranch(product=project))) | 1761 | branch=self.factory.makeProductBranch(product=project))) |
290 | 1761 | [ref] = self.factory.makeGitRefs(target=project) | 1762 | [ref] = self.factory.makeGitRefs(target=project) |
291 | 1762 | snaps.append(self.factory.makeSnap(git_ref=ref)) | 1763 | snaps.append(self.factory.makeSnap(git_ref=ref)) |
292 | 1764 | snaps.append(self.factory.makeSnap(project=project)) | ||
293 | 1763 | snaps.append(self.factory.makeSnap( | 1765 | snaps.append(self.factory.makeSnap( |
294 | 1764 | branch=self.factory.makePersonalBranch())) | 1766 | branch=self.factory.makePersonalBranch())) |
295 | 1765 | [ref] = self.factory.makeGitRefs(target=None) | 1767 | [ref] = self.factory.makeGitRefs(target=None) |
296 | 1766 | snaps.append(self.factory.makeSnap(git_ref=ref)) | 1768 | snaps.append(self.factory.makeSnap(git_ref=ref)) |
297 | 1767 | snap_set = getUtility(ISnapSet) | 1769 | snap_set = getUtility(ISnapSet) |
299 | 1768 | self.assertContentEqual(snaps[:2], snap_set.findByProject(projects[0])) | 1770 | self.assertContentEqual(snaps[:3], snap_set.findByProject(projects[0])) |
300 | 1769 | self.assertContentEqual( | 1771 | self.assertContentEqual( |
302 | 1770 | snaps[2:4], snap_set.findByProject(projects[1])) | 1772 | snaps[3:6], snap_set.findByProject(projects[1])) |
303 | 1771 | 1773 | ||
304 | 1772 | def test_findByBranch(self): | 1774 | def test_findByBranch(self): |
305 | 1773 | # ISnapSet.findByBranch returns all Snaps with the given Bazaar branch. | 1775 | # ISnapSet.findByBranch returns all Snaps with the given Bazaar branch. |
Merging failed /jenkins. ols.canonical. com/online- services/ job/launchpad/ 1501/
https:/