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
diff --git a/lib/lp/code/browser/tests/test_product.py b/lib/lp/code/browser/tests/test_product.py
index 2115eb5..61a6240 100644
--- a/lib/lp/code/browser/tests/test_product.py
+++ b/lib/lp/code/browser/tests/test_product.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2020 Canonical Ltd. This software is licensed under the1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for the product view classes and templates."""4"""Tests for the product view classes and templates."""
@@ -430,14 +430,39 @@ class TestCanConfigureBranches(TestCaseWithFactory):
430 self.assertTrue(view.can_configure_branches())430 self.assertTrue(view.can_configure_branches())
431431
432432
433class TestProductOverviewOCIProject(TestCaseWithFactory):433class TestProductOverviewLinks(TestCaseWithFactory):
434434
435 layer = DatabaseFunctionalLayer435 layer = DatabaseFunctionalLayer
436436
437 def setUp(self, user=ANONYMOUS):437 def setUp(self, user=ANONYMOUS):
438 super(TestProductOverviewOCIProject, self).setUp(user)438 super(TestProductOverviewLinks, self).setUp(user)
439 self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: True}))439 self.useFixture(FeatureFixture({OCI_PROJECT_ALLOW_CREATE: True}))
440440
441 def test_displays_create_and_list_snaps(self):
442 project = self.factory.makeProduct()
443 self.factory.makeSnap(project=project)
444
445 browser = self.getUserBrowser(
446 canonical_url(project), user=project.owner)
447 text = extract_text(
448 find_tag_by_id(browser.contents, 'project-link-info'))
449
450 # Search link should be available because we have an Snap created.
451 self.assertIn("View snap packages", text)
452 self.assertIn("Create snap package", text)
453
454 def test_hides_list_snaps_if_no_snap_is_available(self):
455 project = self.factory.makeProduct()
456
457 browser = self.getUserBrowser(
458 canonical_url(project), user=project.owner)
459 text = extract_text(
460 find_tag_by_id(browser.contents, 'project-link-info'))
461
462 # Search link should not be available.
463 self.assertNotIn("View snap packages", text)
464 self.assertIn("Create snap package", text)
465
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):
442 product = self.factory.makeProduct()467 product = self.factory.makeProduct()
443 self.factory.makeOCIProject(pillar=product)468 self.factory.makeOCIProject(pillar=product)
diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py
index 780c236..df7ee7a 100644
--- a/lib/lp/registry/browser/product.py
+++ b/lib/lp/registry/browser/product.py
@@ -1,4 +1,4 @@
1# Copyright 2009-2020 Canonical Ltd. This software is licensed under the1# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Browser views for products."""4"""Browser views for products."""
@@ -233,6 +233,7 @@ from lp.services.webapp.vhosts import allvhosts
233from lp.services.worlddata.helpers import browser_languages233from lp.services.worlddata.helpers import browser_languages
234from lp.services.worlddata.interfaces.country import ICountry234from lp.services.worlddata.interfaces.country import ICountry
235from lp.snappy.browser.hassnaps import HasSnapsMenuMixin235from lp.snappy.browser.hassnaps import HasSnapsMenuMixin
236from lp.snappy.interfaces.snap import ISnapSet
236from lp.translations.browser.customlanguagecode import (237from lp.translations.browser.customlanguagecode import (
237 HasCustomLanguageCodesTraversalMixin,238 HasCustomLanguageCodesTraversalMixin,
238 )239 )
@@ -585,6 +586,7 @@ class ProductOverviewMenu(ApplicationMenu, ProductEditLinksMixin,
585 'branding',586 'branding',
586 'view_recipes',587 'view_recipes',
587 'view_snaps',588 'view_snaps',
589 'create_snap',
588 ]590 ]
589591
590 def top_contributors(self):592 def top_contributors(self):
diff --git a/lib/lp/registry/templates/product-index.pt b/lib/lp/registry/templates/product-index.pt
index a22574c..73d339b 100644
--- a/lib/lp/registry/templates/product-index.pt
+++ b/lib/lp/registry/templates/product-index.pt
@@ -168,7 +168,7 @@
168 <a tal:replace="structure overview_menu/edit/fmt:icon" />168 <a tal:replace="structure overview_menu/edit/fmt:icon" />
169 </p>169 </p>
170170
171 <ul class="horizontal">171 <ul class="horizontal" id="project-link-info">
172 <li tal:condition="overview_menu/series_add/enabled">172 <li tal:condition="overview_menu/series_add/enabled">
173 <a tal:replace="structure overview_menu/series_add/fmt:link" />173 <a tal:replace="structure overview_menu/series_add/fmt:link" />
174 </li>174 </li>
@@ -183,6 +183,10 @@
183 tal:condition="link/enabled">183 tal:condition="link/enabled">
184 <a tal:replace="structure link/fmt:link" />184 <a tal:replace="structure link/fmt:link" />
185 </li>185 </li>
186 <li tal:define="link context/menu:overview/create_snap"
187 tal:condition="link/enabled">
188 <a tal:replace="structure link/fmt:link" />
189 </li>
186 </ul>190 </ul>
187 </div>191 </div>
188 </div>192 </div>
diff --git a/lib/lp/snappy/browser/snap.py b/lib/lp/snappy/browser/snap.py
index d189323..c8c2edb 100644
--- a/lib/lp/snappy/browser/snap.py
+++ b/lib/lp/snappy/browser/snap.py
@@ -143,16 +143,19 @@ class SnapNavigation(WebhookTargetNavigationMixin, Navigation):
143class SnapFormMixin:143class SnapFormMixin:
144 def validateVCSWidgets(self, cls, data):144 def validateVCSWidgets(self, cls, data):
145 """Validates if VCS sub-widgets."""145 """Validates if VCS sub-widgets."""
146 # Set widgets as required or optional depending on the vcs field.146 if self.widgets.get('vcs') is not None:
147 vcs = data.get('vcs')147 # Set widgets as required or optional depending on the vcs
148 if vcs == VCSType.BZR:148 # field.
149 self.widgets['branch'].context.required = True149 super(cls, self).validate_widgets(data, ['vcs'])
150 self.widgets['git_ref'].context.required = False150 vcs = data.get('vcs')
151 elif vcs == VCSType.GIT:151 if vcs == VCSType.BZR:
152 self.widgets['branch'].context.required = False152 self.widgets['branch'].context.required = True
153 self.widgets['git_ref'].context.required = True153 self.widgets['git_ref'].context.required = False
154 else:154 elif vcs == VCSType.GIT:
155 raise AssertionError("Unknown branch type %s" % vcs)155 self.widgets['branch'].context.required = False
156 self.widgets['git_ref'].context.required = True
157 else:
158 raise AssertionError("Unknown branch type %s" % vcs)
156159
157 def setUpVCSWidgets(self):160 def setUpVCSWidgets(self):
158 widget = self.widgets.get('vcs')161 widget = self.widgets.get('vcs')
@@ -570,7 +573,7 @@ class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin,
570 self.widgets['processors'].widget_class = 'processors'573 self.widgets['processors'].widget_class = 'processors'
571 if self.is_project_context:574 if self.is_project_context:
572 # If we are on Project:+new-snap page, we know which information575 # If we are on Project:+new-snap page, we know which information
573 # types the project supports. Let's filter out the ones that are576 # types the project supports. Let's filter our the ones that are
574 # not supported.577 # not supported.
575 types = getUtility(ISnapSet).getPossibleSnapInformationTypes(578 types = getUtility(ISnapSet).getPossibleSnapInformationTypes(
576 self.context)579 self.context)
@@ -630,9 +633,7 @@ class SnapAddView(LaunchpadFormView, SnapAuthorizeMixin, EnableProcessorsMixin,
630633
631 def validate_widgets(self, data, names=None):634 def validate_widgets(self, data, names=None):
632 """See `LaunchpadFormView`."""635 """See `LaunchpadFormView`."""
633 if self.widgets.get('vcs') is not None:636 self.validateVCSWidgets(SnapAddView, data)
634 super(SnapAddView, self).validate_widgets(data, ['vcs'])
635 self.validateVCSWidgets(SnapAddView, data)
636 if self.widgets.get('auto_build') is not None:637 if self.widgets.get('auto_build') is not None:
637 # Set widgets as required or optional depending on the638 # Set widgets as required or optional depending on the
638 # auto_build field.639 # auto_build field.
@@ -718,9 +719,7 @@ class BaseSnapEditView(LaunchpadEditFormView, SnapAuthorizeMixin,
718719
719 def validate_widgets(self, data, names=None):720 def validate_widgets(self, data, names=None):
720 """See `LaunchpadFormView`."""721 """See `LaunchpadFormView`."""
721 if self.widgets.get('vcs') is not None:722 self.validateVCSWidgets(BaseSnapEditView, data)
722 super(BaseSnapEditView, self).validate_widgets(data, ['vcs'])
723 self.validateVCSWidgets(BaseSnapEditView, data)
724 if self.widgets.get('auto_build') is not None:723 if self.widgets.get('auto_build') is not None:
725 # Set widgets as required or optional depending on the724 # Set widgets as required or optional depending on the
726 # auto_build field.725 # auto_build field.
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index 36e8a56..eeed37b 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -1393,7 +1393,6 @@ class SnapSet:
1393 """See `ISnapSet`."""1393 """See `ISnapSet`."""
1394 return BRANCH_POLICY_ALLOWED_TYPES[project.branch_sharing_policy]1394 return BRANCH_POLICY_ALLOWED_TYPES[project.branch_sharing_policy]
13951395
1396
1397 def isValidInformationType(self, information_type, owner, branch=None,1396 def isValidInformationType(self, information_type, owner, branch=None,
1398 git_ref=None):1397 git_ref=None):
1399 private = information_type not in PUBLIC_INFORMATION_TYPES1398 private = information_type not in PUBLIC_INFORMATION_TYPES
@@ -1479,9 +1478,14 @@ class SnapSet:
1479 collection.visibleByUser(visible_by_user),1478 collection.visibleByUser(visible_by_user),
1480 visible_by_user=visible_by_user)1479 visible_by_user=visible_by_user)
14811480
1481 snaps_for_project = IStore(Snap).find(
1482 Snap,
1483 Snap.project == project,
1484 get_snap_privacy_filter(visible_by_user))
1482 bzr_collection = removeSecurityProxy(IBranchCollection(project))1485 bzr_collection = removeSecurityProxy(IBranchCollection(project))
1483 git_collection = removeSecurityProxy(IGitCollection(project))1486 git_collection = removeSecurityProxy(IGitCollection(project))
1484 return _getSnaps(bzr_collection).union(_getSnaps(git_collection))1487 return snaps_for_project.union(
1488 _getSnaps(bzr_collection)).union(_getSnaps(git_collection))
14851489
1486 def findByBranch(self, branch, visible_by_user=None):1490 def findByBranch(self, branch, visible_by_user=None):
1487 """See `ISnapSet`."""1491 """See `ISnapSet`."""
diff --git a/lib/lp/snappy/templates/snap-new.pt b/lib/lp/snappy/templates/snap-new.pt
index 480d51c..146d2cb 100644
--- a/lib/lp/snappy/templates/snap-new.pt
+++ b/lib/lp/snappy/templates/snap-new.pt
@@ -40,38 +40,41 @@
40 <metal:block use-macro="context/@@launchpad_form/widget_row" />40 <metal:block use-macro="context/@@launchpad_form/widget_row" />
41 </tal:widget>41 </tal:widget>
4242
43 <tr tal:condition="view/is_project_context">43 <tal:guard condition="view/is_project_context">
44 <td>44 <tr>
45 <div>45 <td>
46 <label for="field.vcs">Source:</label>46 <div>
47 <table>47 <label for="field.vcs">Source:</label>
48 <tr>48 <table>
49 <td>49 <tr>
50 <label tal:replace="structure view/vcs_bzr_radio" />50 <td>
51 <table class="subordinate">51 <label tal:replace="structure view/vcs_bzr_radio" />
52 <tal:widget define="widget nocall:view/widgets/branch">52 <table class="subordinate">
53 <metal:block53 <tal:widget define="widget nocall:view/widgets/branch">
54 use-macro="context/@@launchpad_form/widget_row" />54 <metal:block
55 </tal:widget>55 use-macro="context/@@launchpad_form/widget_row" />
56 </table>56 </tal:widget>
57 </td>57 </table>
58 </tr>58 </td>
59 <tr>59 </tr>
60 <td>60
61 <label tal:replace="structure view/vcs_git_radio" />61 <tr>
62 <table class="subordinate">62 <td>
63 <tal:widget define="widget63 <label tal:replace="structure view/vcs_git_radio" />
64 nocall:view/widgets/git_ref">64 <table class="subordinate">
65 <metal:block65 <tal:widget define="widget
66 use-macro="context/@@launchpad_form/widget_row" />66 nocall:view/widgets/git_ref">
67 </tal:widget>67 <metal:block
68 </table>68 use-macro="context/@@launchpad_form/widget_row" />
69 </td>69 </tal:widget>
70 </tr>70 </table>
71 </table>71 </td>
72 </div>72 </tr>
73 </td>73 </table>
74 </tr>74 </div>
75 </td>
76 </tr>
77 </tal:guard>
7578
76 <tal:widget define="widget nocall:view/widgets/store_distro_series">79 <tal:widget define="widget nocall:view/widgets/store_distro_series">
77 <metal:block use-macro="context/@@launchpad_form/widget_row" />80 <metal:block use-macro="context/@@launchpad_form/widget_row" />
diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
index 0c6f68e..5f9ba74 100644
--- a/lib/lp/snappy/tests/test_snap.py
+++ b/lib/lp/snappy/tests/test_snap.py
@@ -1752,7 +1752,8 @@ class TestSnapSet(TestCaseWithFactory):
17521752
1753 def test_findByProject(self):1753 def test_findByProject(self):
1754 # ISnapSet.findByProject returns all Snaps based on branches or1754 # ISnapSet.findByProject returns all Snaps based on branches or
1755 # repositories for the given project.1755 # repositories for the given project, and snaps associated directly
1756 # to the project.
1756 projects = [self.factory.makeProduct() for i in range(2)]1757 projects = [self.factory.makeProduct() for i in range(2)]
1757 snaps = []1758 snaps = []
1758 for project in projects:1759 for project in projects:
@@ -1760,14 +1761,15 @@ class TestSnapSet(TestCaseWithFactory):
1760 branch=self.factory.makeProductBranch(product=project)))1761 branch=self.factory.makeProductBranch(product=project)))
1761 [ref] = self.factory.makeGitRefs(target=project)1762 [ref] = self.factory.makeGitRefs(target=project)
1762 snaps.append(self.factory.makeSnap(git_ref=ref))1763 snaps.append(self.factory.makeSnap(git_ref=ref))
1764 snaps.append(self.factory.makeSnap(project=project))
1763 snaps.append(self.factory.makeSnap(1765 snaps.append(self.factory.makeSnap(
1764 branch=self.factory.makePersonalBranch()))1766 branch=self.factory.makePersonalBranch()))
1765 [ref] = self.factory.makeGitRefs(target=None)1767 [ref] = self.factory.makeGitRefs(target=None)
1766 snaps.append(self.factory.makeSnap(git_ref=ref))1768 snaps.append(self.factory.makeSnap(git_ref=ref))
1767 snap_set = getUtility(ISnapSet)1769 snap_set = getUtility(ISnapSet)
1768 self.assertContentEqual(snaps[:2], snap_set.findByProject(projects[0]))1770 self.assertContentEqual(snaps[:3], snap_set.findByProject(projects[0]))
1769 self.assertContentEqual(1771 self.assertContentEqual(
1770 snaps[2:4], snap_set.findByProject(projects[1]))1772 snaps[3:6], snap_set.findByProject(projects[1]))
17711773
1772 def test_findByBranch(self):1774 def test_findByBranch(self):
1773 # ISnapSet.findByBranch returns all Snaps with the given Bazaar branch.1775 # ISnapSet.findByBranch returns all Snaps with the given Bazaar branch.