Merge ~pappacena/launchpad:export-oci-recipe-build into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: 647b626a65e4a56c1b1e5d38c84de19515b2b596
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:export-oci-recipe-build
Merge into: launchpad:master
Diff against target: 224 lines (+69/-22)
5 files modified
lib/lp/oci/interfaces/ocirecipe.py (+3/-2)
lib/lp/oci/interfaces/ocirecipebuild.py (+26/-20)
lib/lp/oci/interfaces/webservice.py (+1/-0)
lib/lp/oci/tests/test_ocirecipe.py (+27/-0)
lib/lp/services/webservice/wadl-to-refhtml.xsl (+12/-0)
Reviewer Review Type Date Requested Status
Colin Watson Approve
Review via email: mp+383032@code.launchpad.net

Commit message

Exporting OCIRecipeBuild on webservice, and also on IOCIRecipeBuildRequest.builds.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
647b626... by Thiago F. Pappacena

Exporting a few more attributes on OCIRecipeBuild's webservice

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

Thanks for the review, cjwatson.

Pushed the requested changes. I'll land this.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/oci/interfaces/ocirecipe.py b/lib/lp/oci/interfaces/ocirecipe.py
2index ea14d04..3163f0f 100644
3--- a/lib/lp/oci/interfaces/ocirecipe.py
4+++ b/lib/lp/oci/interfaces/ocirecipe.py
5@@ -24,6 +24,7 @@ __all__ = [
6 'OCI_RECIPE_WEBHOOKS_FEATURE_FLAG',
7 ]
8
9+from lazr.lifecycle.snapshot import doNotSnapshot
10 from lazr.restful.declarations import (
11 call_with,
12 error_status,
13@@ -164,11 +165,11 @@ class IOCIRecipeBuildRequest(Interface):
14 error_message = exported(TextLine(
15 title=_("Error message"), required=False, readonly=True))
16
17- builds = CollectionField(
18+ builds = exported(doNotSnapshot(CollectionField(
19 title=_("Builds produced by this request"),
20 # Really IOCIRecipeBuild, patched in lp.oci.interfaces.webservice.
21 value_type=Reference(schema=Interface),
22- required=True, readonly=True)
23+ required=True, readonly=True)))
24
25
26 class IOCIRecipeView(Interface):
27diff --git a/lib/lp/oci/interfaces/ocirecipebuild.py b/lib/lp/oci/interfaces/ocirecipebuild.py
28index a1fbfc0..3169c85 100644
29--- a/lib/lp/oci/interfaces/ocirecipebuild.py
30+++ b/lib/lp/oci/interfaces/ocirecipebuild.py
31@@ -17,6 +17,10 @@ from lazr.enum import (
32 EnumeratedType,
33 Item,
34 )
35+from lazr.restful.declarations import (
36+ export_as_webservice_entry,
37+ exported,
38+ )
39 from lazr.restful.fields import (
40 CollectionField,
41 Reference,
42@@ -78,28 +82,28 @@ class OCIRecipeBuildRegistryUploadStatus(EnumeratedType):
43 class IOCIRecipeBuildView(IPackageBuild):
44 """`IOCIRecipeBuild` attributes that require launchpad.View permission."""
45
46- requester = PublicPersonChoice(
47+ requester = exported(PublicPersonChoice(
48 title=_("Requester"),
49 description=_("The person who requested this OCI recipe build."),
50- vocabulary='ValidPersonOrTeam', required=True, readonly=True)
51+ vocabulary='ValidPersonOrTeam', required=True, readonly=True))
52
53- recipe = Reference(
54+ recipe = exported(Reference(
55 IOCIRecipe,
56 title=_("The OCI recipe to build."),
57 required=True,
58- readonly=True)
59+ readonly=True))
60
61- eta = Datetime(
62+ eta = exported(Datetime(
63 title=_("The datetime when the build job is estimated to complete."),
64- readonly=True)
65+ readonly=True))
66
67- estimate = Bool(
68- title=_("If true, the date value is an estimate."), readonly=True)
69+ estimate = exported(Bool(
70+ title=_("If true, the date value is an estimate."), readonly=True))
71
72- date = Datetime(
73+ date = exported(Datetime(
74 title=_(
75 "The date when the build completed or is estimated to complete."),
76- readonly=True)
77+ readonly=True))
78
79 def getFiles():
80 """Retrieve the build's `IOCIFile` records.
81@@ -127,24 +131,24 @@ class IOCIRecipeBuildView(IPackageBuild):
82 :return: The corresponding `ILibraryFileAlias`.
83 """
84
85- distro_arch_series = Reference(
86+ distro_arch_series = exported(Reference(
87 IDistroArchSeries,
88 title=_("The series and architecture for which to build."),
89- required=True, readonly=True)
90+ required=True, readonly=True))
91
92- score = Int(
93+ score = exported(Int(
94 title=_("Score of the related build farm job (if any)."),
95- required=False, readonly=True)
96+ required=False, readonly=True))
97
98- can_be_rescored = Bool(
99+ can_be_rescored = exported(Bool(
100 title=_("Can be rescored"),
101 required=True, readonly=True,
102- description=_("Whether this build record can be rescored manually."))
103+ description=_("Whether this build record can be rescored manually.")))
104
105- can_be_cancelled = Bool(
106+ can_be_cancelled = exported(Bool(
107 title=_("Can be cancelled"),
108 required=True, readonly=True,
109- description=_("Whether this build record can be cancelled."))
110+ description=_("Whether this build record can be cancelled.")))
111
112 manifest = Attribute(_("The manifest of the image."))
113
114@@ -160,11 +164,11 @@ class IOCIRecipeBuildView(IPackageBuild):
115 last_registry_upload_job = Reference(
116 title=_("Last registry upload job for this build."), schema=Interface)
117
118- registry_upload_status = Choice(
119+ registry_upload_status = exported(Choice(
120 title=_("Registry upload status"),
121 vocabulary=OCIRecipeBuildRegistryUploadStatus,
122 required=True, readonly=False
123- )
124+ ))
125
126
127 class IOCIRecipeBuildEdit(Interface):
128@@ -203,6 +207,8 @@ class IOCIRecipeBuildAdmin(Interface):
129 class IOCIRecipeBuild(IOCIRecipeBuildAdmin, IOCIRecipeBuildEdit,
130 IOCIRecipeBuildView):
131 """A build record for an OCI recipe."""
132+ export_as_webservice_entry(
133+ publish_web_link=True, as_of="devel", singular_name="oci_recipe_build")
134
135
136 class IOCIRecipeBuildSet(ISpecificBuildFarmJobSource):
137diff --git a/lib/lp/oci/interfaces/webservice.py b/lib/lp/oci/interfaces/webservice.py
138index 4db31e1..b337c70 100644
139--- a/lib/lp/oci/interfaces/webservice.py
140+++ b/lib/lp/oci/interfaces/webservice.py
141@@ -8,6 +8,7 @@ __all__ = [
142 'IOCIProjectSeries',
143 'IOCIPushRule',
144 'IOCIRecipe',
145+ 'IOCIRecipeBuild',
146 'IOCIRecipeBuildRequest'
147 ]
148
149diff --git a/lib/lp/oci/tests/test_ocirecipe.py b/lib/lp/oci/tests/test_ocirecipe.py
150index 42e854a..3388a4a 100644
151--- a/lib/lp/oci/tests/test_ocirecipe.py
152+++ b/lib/lp/oci/tests/test_ocirecipe.py
153@@ -5,9 +5,11 @@
154
155 from __future__ import absolute_import, print_function, unicode_literals
156
157+from datetime import datetime
158 import json
159
160 from fixtures import FakeLogger
161+from pytz import utc
162 from six import (
163 ensure_text,
164 string_types,
165@@ -16,6 +18,7 @@ from storm.exceptions import LostObjectError
166 from testtools.matchers import (
167 ContainsDict,
168 Equals,
169+ IsInstance,
170 MatchesDict,
171 MatchesSetwise,
172 MatchesStructure,
173@@ -977,4 +980,28 @@ class TestOCIRecipeAsyncWebservice(TestCaseWithFactory):
174 date_requested=Equals(fmt_date(build_request.date_requested)),
175 date_finished=Equals(fmt_date(build_request.date_finished)),
176 error_message=Equals(build_request.error_message),
177+ builds_collection_link=Equals(build_request_url + '/builds')
178 )))
179+
180+ # Checks the structure of OCI recipe build objects created.
181+ builds = self.webservice.get(
182+ ws_build_request["builds_collection_link"]).jsonBody()["entries"]
183+ with person_logged_in(self.person):
184+ self.assertThat(builds, MatchesSetwise(*[
185+ ContainsDict({
186+ "recipe_link": Equals(abs_url(oci_recipe)),
187+ "requester_link": Equals(abs_url(self.person)),
188+ "buildstate": Equals("Needs building"),
189+ "eta": IsInstance(string_types, type(None)),
190+ "date": IsInstance(string_types, type(None)),
191+ "estimate": IsInstance(bool),
192+ "distro_arch_series_link": Equals(abs_url(arch_series)),
193+ "registry_upload_status": Equals("Unscheduled"),
194+ "title": Equals(
195+ "%s build of %s" % (
196+ arch_series.processor.name, api_url(oci_recipe))),
197+ "score": IsInstance(int),
198+ "can_be_rescored": Equals(True),
199+ "can_be_cancelled": Equals(True),
200+ })
201+ for arch_series in distro_arch_series]))
202diff --git a/lib/lp/services/webservice/wadl-to-refhtml.xsl b/lib/lp/services/webservice/wadl-to-refhtml.xsl
203index 3a4fc2f..86d8467 100644
204--- a/lib/lp/services/webservice/wadl-to-refhtml.xsl
205+++ b/lib/lp/services/webservice/wadl-to-refhtml.xsl
206@@ -479,6 +479,18 @@
207 <xsl:text>/+recipe/</xsl:text>
208 <var>&lt;oci_recipe.name&gt;</var>
209 </xsl:when>
210+ <xsl:when test="@id = 'oci_recipe_build'">
211+ <xsl:text>/~</xsl:text>
212+ <var>&lt;person.name&gt;</var>
213+ <xsl:text>/</xsl:text>
214+ <var>&lt;distribution.name&gt;</var>
215+ <xsl:text>/+oci/</xsl:text>
216+ <var>&lt;oci_project.name&gt;</var>
217+ <xsl:text>/+recipe/</xsl:text>
218+ <var>&lt;oci_recipe.name&gt;</var>
219+ <xsl:text>/+build/</xsl:text>
220+ <var>&lt;oci_recipe_build.id&gt;</var>
221+ </xsl:when>
222 <xsl:when test="@id = 'oci_recipe_build_request'">
223 <xsl:text>/~</xsl:text>
224 <var>&lt;person.name&gt;</var>