Merge lp:~cjwatson/launchpad/snap-set-git-path into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 18449
Proposed branch: lp:~cjwatson/launchpad/snap-set-git-path
Merge into: lp:launchpad
Diff against target: 158 lines (+81/-4)
4 files modified
lib/lp/code/model/gitref.py (+2/-1)
lib/lp/snappy/interfaces/snap.py (+17/-3)
lib/lp/snappy/model/snap.py (+14/-0)
lib/lp/snappy/tests/test_snap.py (+48/-0)
To merge this branch: bzr merge lp:~cjwatson/launchpad/snap-set-git-path
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+329360@code.launchpad.net

Commit message

Allow setting Snap.git_path directly on the webservice.

Description of the change

This allows the backfill requested in https://github.com/canonical-websites/build.snapcraft.io/issues/917.

I thought about adding similar setters for the other components of the snap's source, but it got rather complex and less broadly-applicable, whereas changing the branch should be lightweight and easy.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/model/gitref.py'
2--- lib/lp/code/model/gitref.py 2017-05-22 11:27:17 +0000
3+++ lib/lp/code/model/gitref.py 2017-08-22 12:01:09 +0000
4@@ -592,7 +592,8 @@
5 """See `GitRefDatabaseBackedMixin`."""
6 path = self.repository.default_branch
7 if path is None:
8- raise NotFoundError("Repository '%s' has no default branch")
9+ raise NotFoundError(
10+ "Repository '%s' has no default branch" % self.repository)
11 ref = IStore(GitRef).get(GitRef, (self.repository_id, path))
12 if ref is None:
13 raise NotFoundError(
14
15=== modified file 'lib/lp/snappy/interfaces/snap.py'
16--- lib/lp/snappy/interfaces/snap.py 2017-04-24 13:38:04 +0000
17+++ lib/lp/snappy/interfaces/snap.py 2017-08-22 12:01:09 +0000
18@@ -7,6 +7,7 @@
19
20 __all__ = [
21 'BadSnapSearchContext',
22+ 'BadSnapSource',
23 'CannotAuthorizeStoreUploads',
24 'CannotModifySnapProcessor',
25 'CannotRequestAutoBuilds',
26@@ -185,6 +186,11 @@
27
28
29 @error_status(httplib.BAD_REQUEST)
30+class BadSnapSource(Exception):
31+ """The elements of the source for a snap package are inconsistent."""
32+
33+
34+@error_status(httplib.BAD_REQUEST)
35 class SnapPrivacyMismatch(Exception):
36 """Snap package privacy does not match its content."""
37
38@@ -461,11 +467,19 @@
39 allow_fragment=False,
40 trailing_slash=False))
41
42- git_path = exported(TextLine(
43- title=_("Git branch path"), required=False, readonly=True,
44+ git_path = TextLine(
45+ title=_("Git branch path"), required=False, readonly=False,
46 description=_(
47 "The path of the Git branch containing a snap/snapcraft.yaml, "
48- "snapcraft.yaml, or .snapcraft.yaml recipe at the top level.")))
49+ "snapcraft.yaml, or .snapcraft.yaml recipe at the top level."))
50+ _api_git_path = exported(
51+ TextLine(
52+ title=_("Git branch path"), required=False, readonly=False,
53+ description=_(
54+ "The path of the Git branch containing a snap/snapcraft.yaml, "
55+ "snapcraft.yaml, or .snapcraft.yaml recipe at the top "
56+ "level.")),
57+ exported_as="git_path")
58
59 git_ref = exported(Reference(
60 IGitRef, title=_("Git branch"), required=False, readonly=False,
61
62=== modified file 'lib/lp/snappy/model/snap.py'
63--- lib/lp/snappy/model/snap.py 2017-06-29 12:02:11 +0000
64+++ lib/lp/snappy/model/snap.py 2017-08-22 12:01:09 +0000
65@@ -107,6 +107,7 @@
66 from lp.services.webhooks.model import WebhookTargetMixin
67 from lp.snappy.interfaces.snap import (
68 BadSnapSearchContext,
69+ BadSnapSource,
70 CannotAuthorizeStoreUploads,
71 CannotModifySnapProcessor,
72 CannotRequestAutoBuilds,
73@@ -241,6 +242,19 @@
74 return ["snap:build:0.1"]
75
76 @property
77+ def _api_git_path(self):
78+ return self.git_path
79+
80+ @_api_git_path.setter
81+ def _api_git_path(self, value):
82+ if self.git_repository is None and self.git_repository_url is None:
83+ raise BadSnapSource(
84+ "git_path may only be set on a Git-based snap.")
85+ if value is None:
86+ raise BadSnapSource("git_path may not be set to None.")
87+ self.git_path = value
88+
89+ @property
90 def git_ref(self):
91 """See `ISnap`."""
92 if self.git_repository is not None:
93
94=== modified file 'lib/lp/snappy/tests/test_snap.py'
95--- lib/lp/snappy/tests/test_snap.py 2017-04-24 13:38:04 +0000
96+++ lib/lp/snappy/tests/test_snap.py 2017-08-22 12:01:09 +0000
97@@ -22,6 +22,7 @@
98 from storm.exceptions import LostObjectError
99 from storm.locals import Store
100 from testtools.matchers import (
101+ ContainsDict,
102 Equals,
103 MatchesSetwise,
104 MatchesStructure,
105@@ -1361,6 +1362,53 @@
106 self.assertEqual(
107 "Test Person is not a member of Other Team.", response.body)
108
109+ def test_cannot_set_git_path_for_bzr(self):
110+ # Setting git_path on a Bazaar-based Snap fails.
111+ snap = self.makeSnap(branch=self.factory.makeAnyBranch())
112+ response = self.webservice.patch(
113+ snap["self_link"], "application/json",
114+ json.dumps({"git_path": "HEAD"}))
115+ self.assertEqual(400, response.status)
116+
117+ def test_cannot_set_git_path_to_None(self):
118+ # Setting git_path to None fails.
119+ snap = self.makeSnap(git_ref=self.factory.makeGitRefs()[0])
120+ response = self.webservice.patch(
121+ snap["self_link"], "application/json",
122+ json.dumps({"git_path": None}))
123+ self.assertEqual(400, response.status)
124+
125+ def test_set_git_path(self):
126+ # Setting git_path on a Git-based Snap works.
127+ ref_master, ref_next = self.factory.makeGitRefs(
128+ paths=[u"refs/heads/master", u"refs/heads/next"])
129+ snap = self.makeSnap(git_ref=ref_master)
130+ response = self.webservice.patch(
131+ snap["self_link"], "application/json",
132+ json.dumps({"git_path": ref_next.path}))
133+ self.assertEqual(209, response.status)
134+ self.assertThat(response.jsonBody(), ContainsDict({
135+ "git_repository_link": Equals(snap["git_repository_link"]),
136+ "git_path": Equals(ref_next.path),
137+ }))
138+
139+ def test_set_git_path_external(self):
140+ # Setting git_path on a Snap backed by an external Git repository
141+ # works.
142+ ref = self.factory.makeGitRefRemote()
143+ repository_url = ref.repository_url
144+ snap = self.factory.makeSnap(
145+ registrant=self.person, owner=self.person, git_ref=ref)
146+ snap_url = api_url(snap)
147+ logout()
148+ response = self.webservice.patch(
149+ snap_url, "application/json", json.dumps({"git_path": "HEAD"}))
150+ self.assertEqual(209, response.status)
151+ self.assertThat(response.jsonBody(), ContainsDict({
152+ "git_repository_url": Equals(repository_url),
153+ "git_path": Equals("HEAD"),
154+ }))
155+
156 def test_getByName(self):
157 # lp.snaps.getByName returns a matching Snap.
158 snap = self.makeSnap()