launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25522
[Merge] ~pappacena/launchpad:oci-build-info-to-buildd into launchpad:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad:oci-build-info-to-buildd into launchpad:master.
Commit message:
Adding extra meta info when requesting an OCI build to buildd
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/392500
This information will be useful on buildd side to create the OCI security manifest file.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:oci-build-info-to-buildd into launchpad:master.
diff --git a/database/schema/security.cfg b/database/schema/security.cfg
index d5a23f1..11aba6f 100644
--- a/database/schema/security.cfg
+++ b/database/schema/security.cfg
@@ -1004,6 +1004,7 @@ public.ocipushrule = SELECT
public.ocirecipe = SELECT
public.ocirecipebuild = SELECT, UPDATE
public.ocirecipebuildjob = SELECT, INSERT
+public.ocirecipejob = SELECT
public.openididentifier = SELECT
public.packageset = SELECT
public.packagesetgroup = SELECT
diff --git a/lib/lp/oci/model/ocirecipebuildbehaviour.py b/lib/lp/oci/model/ocirecipebuildbehaviour.py
index 1008884..e83d8fe 100644
--- a/lib/lp/oci/model/ocirecipebuildbehaviour.py
+++ b/lib/lp/oci/model/ocirecipebuildbehaviour.py
@@ -38,6 +38,7 @@ from lp.buildmaster.model.buildfarmjobbehaviour import (
from lp.oci.interfaces.ocirecipebuild import IOCIFileSet
from lp.registry.interfaces.series import SeriesStatus
from lp.services.librarian.utils import copy_and_close
+from lp.services.webapp import canonical_url
from lp.snappy.model.snapbuildbehaviour import SnapProxyMixin
from lp.soyuz.adapters.archivedependencies import (
get_sources_list_for_building,
@@ -77,6 +78,38 @@ class OCIRecipeBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase):
raise CannotBuild(
"Missing chroot for %s" % build.distro_arch_series.displayname)
+ def getBuildInfoArgs(self):
+ def format_user(user):
+ if user is None:
+ return None
+ hide_email = not user.preferredemail or user.hide_email_addresses
+ return {
+ "name": user.name,
+ "email": (None if hide_email else user.preferredemail.email)}
+ build = self.build
+ build_request = build.build_request
+ builds = list(build_request.builds) if build_request else [build]
+ info = {
+ "architectures": [],
+ "recipe_owner": format_user(self.build.recipe.owner),
+ "build_request_id": None,
+ "build_request_timestamp": None,
+ # With build_request set, all builds in this list will have the
+ # same requester. Without build_request, we only care about the
+ # only existing build in this list.
+ "build_requester": format_user(builds[0].requester),
+ # Build URL per architecture.
+ "build_urls": {},
+ }
+ if build_request:
+ info["build_request_id"] = build_request.id
+ info["build_request_timestamp"] = (
+ build_request.date_requested.isoformat())
+ info["architectures"] = [i.processor.name for i in builds]
+ info["build_urls"] = {
+ i.processor.name: canonical_url(i) for i in builds}
+ return info
+
@defer.inlineCallbacks
def extraBuildArgs(self, logger=None):
"""
@@ -101,6 +134,7 @@ class OCIRecipeBuildBehaviour(SnapProxyMixin, BuildFarmJobBehaviourBase):
# XML-RPC.
args['build_args'] = removeSecurityProxy(build.recipe.build_args)
args['build_path'] = build.recipe.build_path
+ args['metadata'] = self.getBuildInfoArgs()
if build.recipe.git_ref is not None:
args["git_repository"] = (
diff --git a/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py b/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py
index ded60cf..476899d 100644
--- a/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py
+++ b/lib/lp/oci/tests/test_ocirecipebuildbehaviour.py
@@ -104,7 +104,7 @@ class MakeOCIBuildMixin:
build.queueBuild()
return build
- def makeJob(self, git_ref, recipe=None, build=None, **kwargs):
+ def makeJob(self, git_ref=None, recipe=None, build=None, **kwargs):
"""Create a sample `IOCIRecipeBuildBehaviour`."""
if build is None:
if recipe is None:
@@ -112,6 +112,8 @@ class MakeOCIBuildMixin:
else:
build = self.factory.makeOCIRecipeBuild(
recipe=recipe, **kwargs)
+ if git_ref is None:
+ [git_ref] = self.factory.makeGitRefs()
build.recipe.git_ref = git_ref
build.recipe.build_args = {"BUILD_VAR": "123"}
@@ -131,7 +133,7 @@ class MakeOCIBuildMixin:
return job
-class TestOCIBuildBehaviour(TestCaseWithFactory):
+class TestOCIBuildBehaviour(TestCaseWithFactory, MakeOCIBuildMixin):
layer = LaunchpadZopelessLayer
@@ -150,6 +152,89 @@ class TestOCIBuildBehaviour(TestCaseWithFactory):
job = IBuildFarmJobBehaviour(build)
self.assertProvides(job, IBuildFarmJobBehaviour)
+ def makeRecipe(self, **kwargs):
+ amd64 = getUtility(IProcessorSet).getByName("amd64")
+ recipe = self.factory.makeOCIRecipe(**kwargs)
+ distroseries = self.factory.makeDistroSeries(
+ distribution=recipe.oci_project.distribution)
+ distro = self.factory.makeDistroArchSeries(
+ distroseries=distroseries, architecturetag="amd64",
+ processor=amd64)
+ distro.addOrUpdateChroot(self.factory.makeLibraryFileAlias())
+ recipe.setProcessors([amd64])
+ return recipe
+
+ def makeBuildRequest(self, recipe, requester):
+ build_request = recipe.requestBuilds(requester)
+ # Create the builds for the build request, and set them at the build
+ # request job.
+ builds = recipe.requestBuildsFromJob(requester, build_request)
+ job = removeSecurityProxy(build_request).job
+ removeSecurityProxy(job).builds = builds
+ return build_request
+
+ def test_getBuildInfoArgs_with_build_request(self):
+ owner = self.factory.makePerson()
+ owner.setPreferredEmail(self.factory.makeEmail('owner@xxxxxxx', owner))
+ oci_project = self.factory.makeOCIProject(registrant=owner)
+ recipe = self.makeRecipe(
+ oci_project=oci_project, registrant=owner, owner=owner)
+ build_request = self.makeBuildRequest(recipe, recipe.owner)
+ build = build_request.builds[0]
+ job = self.makeJob(build=build)
+
+ self.assertThat(job.getBuildInfoArgs(), MatchesDict({
+ "architectures": Equals(["amd64"]),
+ "recipe_owner": Equals({
+ "name": recipe.owner.name,
+ "email": "owner@xxxxxxx"}),
+ "build_request_id": Equals(build_request.id),
+ "build_requester": Equals({
+ "name": build.requester.name,
+ "email": "owner@xxxxxxx"}),
+ "build_request_timestamp": Equals(
+ build_request.date_requested.isoformat()),
+ "build_urls": MatchesDict({
+ "amd64": Equals(canonical_url(build_request.builds[0]))
+ }),
+ }))
+
+ def test_getBuildInfoArgs_hide_email(self):
+ owner = self.factory.makePerson()
+ owner.setPreferredEmail(self.factory.makeEmail('owner@xxxxxxx', owner))
+ owner.hide_email_addresses = True
+ oci_project = self.factory.makeOCIProject(registrant=owner)
+ recipe = self.makeRecipe(
+ oci_project=oci_project, registrant=owner, owner=owner)
+ build_request = self.makeBuildRequest(recipe, recipe.owner)
+ build = build_request.builds[0]
+ job = self.makeJob(build=build)
+
+ self.assertThat(job.getBuildInfoArgs(), MatchesDict({
+ "architectures": Equals(["amd64"]),
+ "recipe_owner": Equals({"name": recipe.owner.name, "email": None}),
+ "build_request_id": Equals(build_request.id),
+ "build_requester": Equals({
+ "name": build.requester.name, "email": None}),
+ "build_request_timestamp": Equals(
+ build_request.date_requested.isoformat()),
+ "build_urls": MatchesDict({
+ "amd64": Equals(canonical_url(build_request.builds[0]))
+ }),
+ }))
+
+ def test_getBuildInfoArgs_without_build_request(self):
+ build = self.factory.makeOCIRecipeBuild()
+ job = self.makeJob(build=build)
+ self.assertThat(job.getBuildInfoArgs(), ContainsDict({
+ "architectures": Equals(["386"]),
+ "build_request_id": Equals(None),
+ "build_request_timestamp": Equals(None),
+ "build_urls": MatchesDict({
+ "386": Equals(canonical_url(build))
+ }),
+ }))
+
class TestAsyncOCIRecipeBuildBehaviour(
StatsMixin, MakeOCIBuildMixin, TestCaseWithFactory):
@@ -279,7 +364,14 @@ class TestAsyncOCIRecipeBuildBehaviour(
"revocation_endpoint": RevocationEndpointMatcher(job, self.now),
"series": Equals(job.build.distro_arch_series.distroseries.name),
"trusted_keys": Equals(expected_trusted_keys),
- }))
+ # 'metadata' has detailed tests at TestOCIBuildBehaviour class.
+ "metadata": ContainsDict({
+ "architectures": Equals(["386"]),
+ "build_request_id": Equals(None),
+ "build_request_timestamp": Equals(None),
+ "build_urls": Equals({"386": canonical_url(job.build)})
+ })
+ }))
@defer.inlineCallbacks
def test_extraBuildArgs_git_HEAD(self):
@@ -311,7 +403,14 @@ class TestAsyncOCIRecipeBuildBehaviour(
"revocation_endpoint": RevocationEndpointMatcher(job, self.now),
"series": Equals(job.build.distro_arch_series.distroseries.name),
"trusted_keys": Equals(expected_trusted_keys),
- }))
+ # 'metadata' has detailed tests at TestOCIBuildBehaviour class.
+ "metadata": ContainsDict({
+ "architectures": Equals(["386"]),
+ "build_request_id": Equals(None),
+ "build_request_timestamp": Equals(None),
+ "build_urls": Equals({"386": canonical_url(job.build)})
+ })
+ }))
@defer.inlineCallbacks
def test_composeBuildRequest_proxy_url_set(self):