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 (community) 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
diff --git a/lib/lp/oci/interfaces/ocirecipe.py b/lib/lp/oci/interfaces/ocirecipe.py
index ea14d04..3163f0f 100644
--- a/lib/lp/oci/interfaces/ocirecipe.py
+++ b/lib/lp/oci/interfaces/ocirecipe.py
@@ -24,6 +24,7 @@ __all__ = [
24 'OCI_RECIPE_WEBHOOKS_FEATURE_FLAG',24 'OCI_RECIPE_WEBHOOKS_FEATURE_FLAG',
25 ]25 ]
2626
27from lazr.lifecycle.snapshot import doNotSnapshot
27from lazr.restful.declarations import (28from lazr.restful.declarations import (
28 call_with,29 call_with,
29 error_status,30 error_status,
@@ -164,11 +165,11 @@ class IOCIRecipeBuildRequest(Interface):
164 error_message = exported(TextLine(165 error_message = exported(TextLine(
165 title=_("Error message"), required=False, readonly=True))166 title=_("Error message"), required=False, readonly=True))
166167
167 builds = CollectionField(168 builds = exported(doNotSnapshot(CollectionField(
168 title=_("Builds produced by this request"),169 title=_("Builds produced by this request"),
169 # Really IOCIRecipeBuild, patched in lp.oci.interfaces.webservice.170 # Really IOCIRecipeBuild, patched in lp.oci.interfaces.webservice.
170 value_type=Reference(schema=Interface),171 value_type=Reference(schema=Interface),
171 required=True, readonly=True)172 required=True, readonly=True)))
172173
173174
174class IOCIRecipeView(Interface):175class IOCIRecipeView(Interface):
diff --git a/lib/lp/oci/interfaces/ocirecipebuild.py b/lib/lp/oci/interfaces/ocirecipebuild.py
index a1fbfc0..3169c85 100644
--- a/lib/lp/oci/interfaces/ocirecipebuild.py
+++ b/lib/lp/oci/interfaces/ocirecipebuild.py
@@ -17,6 +17,10 @@ from lazr.enum import (
17 EnumeratedType,17 EnumeratedType,
18 Item,18 Item,
19 )19 )
20from lazr.restful.declarations import (
21 export_as_webservice_entry,
22 exported,
23 )
20from lazr.restful.fields import (24from lazr.restful.fields import (
21 CollectionField,25 CollectionField,
22 Reference,26 Reference,
@@ -78,28 +82,28 @@ class OCIRecipeBuildRegistryUploadStatus(EnumeratedType):
78class IOCIRecipeBuildView(IPackageBuild):82class IOCIRecipeBuildView(IPackageBuild):
79 """`IOCIRecipeBuild` attributes that require launchpad.View permission."""83 """`IOCIRecipeBuild` attributes that require launchpad.View permission."""
8084
81 requester = PublicPersonChoice(85 requester = exported(PublicPersonChoice(
82 title=_("Requester"),86 title=_("Requester"),
83 description=_("The person who requested this OCI recipe build."),87 description=_("The person who requested this OCI recipe build."),
84 vocabulary='ValidPersonOrTeam', required=True, readonly=True)88 vocabulary='ValidPersonOrTeam', required=True, readonly=True))
8589
86 recipe = Reference(90 recipe = exported(Reference(
87 IOCIRecipe,91 IOCIRecipe,
88 title=_("The OCI recipe to build."),92 title=_("The OCI recipe to build."),
89 required=True,93 required=True,
90 readonly=True)94 readonly=True))
9195
92 eta = Datetime(96 eta = exported(Datetime(
93 title=_("The datetime when the build job is estimated to complete."),97 title=_("The datetime when the build job is estimated to complete."),
94 readonly=True)98 readonly=True))
9599
96 estimate = Bool(100 estimate = exported(Bool(
97 title=_("If true, the date value is an estimate."), readonly=True)101 title=_("If true, the date value is an estimate."), readonly=True))
98102
99 date = Datetime(103 date = exported(Datetime(
100 title=_(104 title=_(
101 "The date when the build completed or is estimated to complete."),105 "The date when the build completed or is estimated to complete."),
102 readonly=True)106 readonly=True))
103107
104 def getFiles():108 def getFiles():
105 """Retrieve the build's `IOCIFile` records.109 """Retrieve the build's `IOCIFile` records.
@@ -127,24 +131,24 @@ class IOCIRecipeBuildView(IPackageBuild):
127 :return: The corresponding `ILibraryFileAlias`.131 :return: The corresponding `ILibraryFileAlias`.
128 """132 """
129133
130 distro_arch_series = Reference(134 distro_arch_series = exported(Reference(
131 IDistroArchSeries,135 IDistroArchSeries,
132 title=_("The series and architecture for which to build."),136 title=_("The series and architecture for which to build."),
133 required=True, readonly=True)137 required=True, readonly=True))
134138
135 score = Int(139 score = exported(Int(
136 title=_("Score of the related build farm job (if any)."),140 title=_("Score of the related build farm job (if any)."),
137 required=False, readonly=True)141 required=False, readonly=True))
138142
139 can_be_rescored = Bool(143 can_be_rescored = exported(Bool(
140 title=_("Can be rescored"),144 title=_("Can be rescored"),
141 required=True, readonly=True,145 required=True, readonly=True,
142 description=_("Whether this build record can be rescored manually."))146 description=_("Whether this build record can be rescored manually.")))
143147
144 can_be_cancelled = Bool(148 can_be_cancelled = exported(Bool(
145 title=_("Can be cancelled"),149 title=_("Can be cancelled"),
146 required=True, readonly=True,150 required=True, readonly=True,
147 description=_("Whether this build record can be cancelled."))151 description=_("Whether this build record can be cancelled.")))
148152
149 manifest = Attribute(_("The manifest of the image."))153 manifest = Attribute(_("The manifest of the image."))
150154
@@ -160,11 +164,11 @@ class IOCIRecipeBuildView(IPackageBuild):
160 last_registry_upload_job = Reference(164 last_registry_upload_job = Reference(
161 title=_("Last registry upload job for this build."), schema=Interface)165 title=_("Last registry upload job for this build."), schema=Interface)
162166
163 registry_upload_status = Choice(167 registry_upload_status = exported(Choice(
164 title=_("Registry upload status"),168 title=_("Registry upload status"),
165 vocabulary=OCIRecipeBuildRegistryUploadStatus,169 vocabulary=OCIRecipeBuildRegistryUploadStatus,
166 required=True, readonly=False170 required=True, readonly=False
167 )171 ))
168172
169173
170class IOCIRecipeBuildEdit(Interface):174class IOCIRecipeBuildEdit(Interface):
@@ -203,6 +207,8 @@ class IOCIRecipeBuildAdmin(Interface):
203class IOCIRecipeBuild(IOCIRecipeBuildAdmin, IOCIRecipeBuildEdit,207class IOCIRecipeBuild(IOCIRecipeBuildAdmin, IOCIRecipeBuildEdit,
204 IOCIRecipeBuildView):208 IOCIRecipeBuildView):
205 """A build record for an OCI recipe."""209 """A build record for an OCI recipe."""
210 export_as_webservice_entry(
211 publish_web_link=True, as_of="devel", singular_name="oci_recipe_build")
206212
207213
208class IOCIRecipeBuildSet(ISpecificBuildFarmJobSource):214class IOCIRecipeBuildSet(ISpecificBuildFarmJobSource):
diff --git a/lib/lp/oci/interfaces/webservice.py b/lib/lp/oci/interfaces/webservice.py
index 4db31e1..b337c70 100644
--- a/lib/lp/oci/interfaces/webservice.py
+++ b/lib/lp/oci/interfaces/webservice.py
@@ -8,6 +8,7 @@ __all__ = [
8 'IOCIProjectSeries',8 'IOCIProjectSeries',
9 'IOCIPushRule',9 'IOCIPushRule',
10 'IOCIRecipe',10 'IOCIRecipe',
11 'IOCIRecipeBuild',
11 'IOCIRecipeBuildRequest'12 'IOCIRecipeBuildRequest'
12 ]13 ]
1314
diff --git a/lib/lp/oci/tests/test_ocirecipe.py b/lib/lp/oci/tests/test_ocirecipe.py
index 42e854a..3388a4a 100644
--- a/lib/lp/oci/tests/test_ocirecipe.py
+++ b/lib/lp/oci/tests/test_ocirecipe.py
@@ -5,9 +5,11 @@
55
6from __future__ import absolute_import, print_function, unicode_literals6from __future__ import absolute_import, print_function, unicode_literals
77
8from datetime import datetime
8import json9import json
910
10from fixtures import FakeLogger11from fixtures import FakeLogger
12from pytz import utc
11from six import (13from six import (
12 ensure_text,14 ensure_text,
13 string_types,15 string_types,
@@ -16,6 +18,7 @@ from storm.exceptions import LostObjectError
16from testtools.matchers import (18from testtools.matchers import (
17 ContainsDict,19 ContainsDict,
18 Equals,20 Equals,
21 IsInstance,
19 MatchesDict,22 MatchesDict,
20 MatchesSetwise,23 MatchesSetwise,
21 MatchesStructure,24 MatchesStructure,
@@ -977,4 +980,28 @@ class TestOCIRecipeAsyncWebservice(TestCaseWithFactory):
977 date_requested=Equals(fmt_date(build_request.date_requested)),980 date_requested=Equals(fmt_date(build_request.date_requested)),
978 date_finished=Equals(fmt_date(build_request.date_finished)),981 date_finished=Equals(fmt_date(build_request.date_finished)),
979 error_message=Equals(build_request.error_message),982 error_message=Equals(build_request.error_message),
983 builds_collection_link=Equals(build_request_url + '/builds')
980 )))984 )))
985
986 # Checks the structure of OCI recipe build objects created.
987 builds = self.webservice.get(
988 ws_build_request["builds_collection_link"]).jsonBody()["entries"]
989 with person_logged_in(self.person):
990 self.assertThat(builds, MatchesSetwise(*[
991 ContainsDict({
992 "recipe_link": Equals(abs_url(oci_recipe)),
993 "requester_link": Equals(abs_url(self.person)),
994 "buildstate": Equals("Needs building"),
995 "eta": IsInstance(string_types, type(None)),
996 "date": IsInstance(string_types, type(None)),
997 "estimate": IsInstance(bool),
998 "distro_arch_series_link": Equals(abs_url(arch_series)),
999 "registry_upload_status": Equals("Unscheduled"),
1000 "title": Equals(
1001 "%s build of %s" % (
1002 arch_series.processor.name, api_url(oci_recipe))),
1003 "score": IsInstance(int),
1004 "can_be_rescored": Equals(True),
1005 "can_be_cancelled": Equals(True),
1006 })
1007 for arch_series in distro_arch_series]))
diff --git a/lib/lp/services/webservice/wadl-to-refhtml.xsl b/lib/lp/services/webservice/wadl-to-refhtml.xsl
index 3a4fc2f..86d8467 100644
--- a/lib/lp/services/webservice/wadl-to-refhtml.xsl
+++ b/lib/lp/services/webservice/wadl-to-refhtml.xsl
@@ -479,6 +479,18 @@
479 <xsl:text>/+recipe/</xsl:text>479 <xsl:text>/+recipe/</xsl:text>
480 <var>&lt;oci_recipe.name&gt;</var>480 <var>&lt;oci_recipe.name&gt;</var>
481 </xsl:when>481 </xsl:when>
482 <xsl:when test="@id = 'oci_recipe_build'">
483 <xsl:text>/~</xsl:text>
484 <var>&lt;person.name&gt;</var>
485 <xsl:text>/</xsl:text>
486 <var>&lt;distribution.name&gt;</var>
487 <xsl:text>/+oci/</xsl:text>
488 <var>&lt;oci_project.name&gt;</var>
489 <xsl:text>/+recipe/</xsl:text>
490 <var>&lt;oci_recipe.name&gt;</var>
491 <xsl:text>/+build/</xsl:text>
492 <var>&lt;oci_recipe_build.id&gt;</var>
493 </xsl:when>
482 <xsl:when test="@id = 'oci_recipe_build_request'">494 <xsl:when test="@id = 'oci_recipe_build_request'">
483 <xsl:text>/~</xsl:text>495 <xsl:text>/~</xsl:text>
484 <var>&lt;person.name&gt;</var>496 <var>&lt;person.name&gt;</var>