Allow building compose with scratch builds defined by `pkgset_koji_scratch_tasks`.

Signed-off-by: Jan Kaluza <jkaluza@redhat.com>
This commit is contained in:
Jan Kaluza 2020-06-08 08:00:41 +02:00 committed by lsedlar
parent b59bdcea92
commit 4a15d1351a
6 changed files with 162 additions and 2 deletions

View File

@ -522,6 +522,13 @@ Options
**pkgset_koji_builds** **pkgset_koji_builds**
(*str|[str]*) -- extra build(s) to include in a package set defined as NVRs. (*str|[str]*) -- extra build(s) to include in a package set defined as NVRs.
**pkgset_koji_scratch_tasks**
(*str|[str]*) -- RPM scratch build task(s) to include in a package set,
defined as task IDs. This option can be used only when ``compose_type``
is set to ``test``. The RPM still needs to have higher NVR than any
other RPM with the same name comming from other sources in order to
appear in the resulting compose.
**pkgset_koji_module_tag** **pkgset_koji_module_tag**
(*str|[str]*) -- tags to read module from. This option works similarly to (*str|[str]*) -- tags to read module from. This option works similarly to
listing tags in variants XML. If tags are specified and variants XML listing tags in variants XML. If tags are specified and variants XML

View File

@ -778,6 +778,7 @@ def make_schema():
"koji_event": {"type": "number"}, "koji_event": {"type": "number"},
"pkgset_koji_tag": {"$ref": "#/definitions/strings"}, "pkgset_koji_tag": {"$ref": "#/definitions/strings"},
"pkgset_koji_builds": {"$ref": "#/definitions/strings"}, "pkgset_koji_builds": {"$ref": "#/definitions/strings"},
"pkgset_koji_scratch_tasks": {"$ref": "#/definitions/strings"},
"pkgset_koji_module_tag": {"$ref": "#/definitions/strings", "default": []}, "pkgset_koji_module_tag": {"$ref": "#/definitions/strings", "default": []},
"pkgset_koji_inherit": {"type": "boolean", "default": True}, "pkgset_koji_inherit": {"type": "boolean", "default": True},
"pkgset_koji_inherit_modules": {"type": "boolean", "default": False}, "pkgset_koji_inherit_modules": {"type": "boolean", "default": False},

View File

@ -328,6 +328,7 @@ class KojiPackageSet(PackageSetBase):
populate_only_packages=False, populate_only_packages=False,
cache_region=None, cache_region=None,
extra_builds=None, extra_builds=None,
extra_tasks=None,
): ):
""" """
Creates new KojiPackageSet. Creates new KojiPackageSet.
@ -357,6 +358,9 @@ class KojiPackageSet(PackageSetBase):
again. again.
:param list extra_builds: Extra builds NVRs to get from Koji and include :param list extra_builds: Extra builds NVRs to get from Koji and include
in the package set. in the package set.
:param list extra_tasks: Extra RPMs defined as Koji task IDs to get from Koji
and include in the package set. Useful when building testing compose
with RPM scratch builds.
""" """
super(KojiPackageSet, self).__init__( super(KojiPackageSet, self).__init__(
name, name,
@ -371,6 +375,7 @@ class KojiPackageSet(PackageSetBase):
self.populate_only_packages = populate_only_packages self.populate_only_packages = populate_only_packages
self.cache_region = cache_region self.cache_region = cache_region
self.extra_builds = extra_builds or [] self.extra_builds = extra_builds or []
self.extra_tasks = extra_tasks or []
self.reuse = None self.reuse = None
def __getstate__(self): def __getstate__(self):
@ -413,6 +418,53 @@ class KojiPackageSet(PackageSetBase):
rpms += rpms_in_build rpms += rpms_in_build
return rpms, builds return rpms, builds
def get_extra_rpms_from_tasks(self):
"""
Returns manually constructed RPM infos from the Koji tasks defined
in `self.extra_tasks`.
:rtype: list
:return: List with RPM infos defined as dicts with following keys:
- name, version, release, arch, src - as returned by parse_nvra.
- path_from_task - Full path to RPM on /mnt/koji.
- build_id - Always set to None.
"""
if not self.extra_tasks:
return []
# Get the IDs of children tasks - these are the tasks containing
# the resulting RPMs.
children_tasks = self.koji_wrapper.retrying_multicall_map(
self.koji_proxy,
self.koji_proxy.getTaskChildren,
list_of_args=self.extra_tasks,
)
children_task_ids = []
for tasks in children_tasks:
children_task_ids += [t["id"] for t in tasks]
# Get the results of these children tasks.
results = self.koji_wrapper.retrying_multicall_map(
self.koji_proxy,
self.koji_proxy.getTaskResult,
list_of_args=children_task_ids,
)
rpms = []
for result in results:
rpms += result.get("rpms", [])
rpms += result.get("srpms", [])
rpm_infos = []
for rpm in rpms:
rpm_info = kobo.rpmlib.parse_nvra(os.path.basename(rpm))
rpm_info["path_from_task"] = os.path.join(
self.koji_wrapper.koji_module.pathinfo.work(), rpm
)
rpm_info["build_id"] = None
rpm_infos.append(rpm_info)
return rpm_infos
def get_latest_rpms(self, tag, event, inherit=True): def get_latest_rpms(self, tag, event, inherit=True):
if not tag: if not tag:
return [], [] return [], []
@ -443,6 +495,18 @@ class KojiPackageSet(PackageSetBase):
def get_package_path(self, queue_item): def get_package_path(self, queue_item):
rpm_info, build_info = queue_item rpm_info, build_info = queue_item
# Check if this RPM is comming from scratch task. In this case, we already
# know the path and we must ensure unsigned packages are allowed.
if "path_from_task" in rpm_info:
if None in self.sigkey_ordering or "" in self.sigkey_ordering:
return rpm_info["path_from_task"]
else:
self.log_error(
"Scratch RPM %s cannot be used in signed compose." % (rpm_info)
)
return None
pathinfo = self.koji_wrapper.koji_module.pathinfo pathinfo = self.koji_wrapper.koji_module.pathinfo
paths = [] paths = []
for sigkey in self.sigkey_ordering: for sigkey in self.sigkey_ordering:
@ -521,6 +585,9 @@ class KojiPackageSet(PackageSetBase):
else: else:
builds_by_id.setdefault(build_id, build_info) builds_by_id.setdefault(build_id, build_info)
# Get extra RPMs from tasks.
rpms += self.get_extra_rpms_from_tasks()
skipped_arches = [] skipped_arches = []
skipped_packages_count = 0 skipped_packages_count = 0
# We need to process binary packages first, and then source packages. # We need to process binary packages first, and then source packages.
@ -560,14 +627,20 @@ class KojiPackageSet(PackageSetBase):
skipped_packages_count += 1 skipped_packages_count += 1
continue continue
build_info = builds_by_id[rpm_info["build_id"]] build_info = builds_by_id.get(rpm_info["build_id"], None)
if _is_src(rpm_info): if _is_src(rpm_info):
result_srpms.append((rpm_info, build_info)) result_srpms.append((rpm_info, build_info))
else: else:
result_rpms.append((rpm_info, build_info)) result_rpms.append((rpm_info, build_info))
if self.populate_only_packages and self.packages: if self.populate_only_packages and self.packages:
# Only add the package if we already have some whitelist. # Only add the package if we already have some whitelist.
self.packages.add(build_info["name"]) if build_info:
self.packages.add(build_info["name"])
else:
# We have no build info and therefore no Koji package name,
# we can only guess that the Koji package name would be the same
# one as the RPM name.
self.packages.add(rpm_info["name"])
if skipped_packages_count: if skipped_packages_count:
self.log_debug( self.log_debug(

View File

@ -641,8 +641,10 @@ def populate_global_pkgset(compose, koji_wrapper, path_prefix, event):
compose.log_info("Loading package set for tag %s", compose_tag) compose.log_info("Loading package set for tag %s", compose_tag)
if compose_tag in pkgset_koji_tags: if compose_tag in pkgset_koji_tags:
extra_builds = force_list(compose.conf.get("pkgset_koji_builds", [])) extra_builds = force_list(compose.conf.get("pkgset_koji_builds", []))
extra_tasks = force_list(compose.conf.get("pkgset_koji_scratch_tasks", []))
else: else:
extra_builds = [] extra_builds = []
extra_tasks = []
pkgset = pungi.phases.pkgset.pkgsets.KojiPackageSet( pkgset = pungi.phases.pkgset.pkgsets.KojiPackageSet(
compose_tag, compose_tag,
@ -655,6 +657,7 @@ def populate_global_pkgset(compose, koji_wrapper, path_prefix, event):
populate_only_packages=populate_only_packages_to_gather, populate_only_packages=populate_only_packages_to_gather,
cache_region=compose.cache_region, cache_region=compose.cache_region,
extra_builds=extra_builds, extra_builds=extra_builds,
extra_tasks=extra_tasks,
) )
# Check if we have cache for this tag from previous compose. If so, use # Check if we have cache for this tag from previous compose. If so, use

View File

@ -232,6 +232,12 @@ def main():
if compose_type == "production" and not opts.label and not opts.no_label: if compose_type == "production" and not opts.label and not opts.no_label:
abort("must specify label for a production compose") abort("must specify label for a production compose")
if (
compose_type != "test"
and conf.get("pkgset_koji_scratch_tasks", None) is not None
):
abort('pkgset_koji_scratch_tasks can be used only for "test" compose type')
# check if all requirements are met # check if all requirements are met
import pungi.checks import pungi.checks

View File

@ -33,6 +33,9 @@ class MockPathInfo(object):
def rpm(self, rpm_info): def rpm(self, rpm_info):
return os.path.join("rpms", self.get_filename(rpm_info)) return os.path.join("rpms", self.get_filename(rpm_info))
def work(self):
return "work"
class MockFile(object): class MockFile(object):
def __init__(self, path): def __init__(self, path):
@ -380,6 +383,73 @@ class TestKojiPkgset(PkgsetCompareMixin, helpers.PungiTestCase):
}, },
) )
def test_get_extra_rpms_from_tasks(self):
pkgset = pkgsets.KojiPackageSet(
"pkgset",
self.koji_wrapper,
[None],
arches=["x86_64"],
extra_tasks=["123", "456"],
)
children_tasks = [[{"id": 1}, {"id": 2}], [{"id": 3}, {"id": 4}]]
task_results = [
{
"logs": [
"tasks/root.log",
"tasks/hw_info.log",
"tasks/state.log",
"tasks/build.log",
"tasks/mock_output.log",
"tasks/noarch_rpmdiff.json",
],
"rpms": ["tasks/pungi-4.1.39-5.f30.noarch.rpm"],
"srpms": ["tasks/pungi-4.1.39-5.f30.src.rpm"],
},
{
"logs": [
"tasks/5478/29155478/root.log",
"tasks/5478/29155478/hw_info.log",
"tasks/5478/29155478/state.log",
"tasks/5478/29155478/build.log",
],
"source": {
"source": "pungi-4.1.39-5.f30.src.rpm",
"url": "pungi-4.1.39-5.f30.src.rpm",
},
"srpm": "tasks/5478/29155478/pungi-4.1.39-5.f30.src.rpm",
},
]
self.koji_wrapper.retrying_multicall_map.side_effect = [
children_tasks,
task_results,
]
expected_rpms = [
{
"arch": "noarch",
"build_id": None,
"epoch": "",
"name": "pungi",
"path_from_task": "work/tasks/pungi-4.1.39-5.f30.noarch.rpm",
"release": "5.f30",
"src": False,
"version": "4.1.39",
},
{
"arch": "src",
"build_id": None,
"epoch": "",
"name": "pungi",
"path_from_task": "work/tasks/pungi-4.1.39-5.f30.src.rpm",
"release": "5.f30",
"src": True,
"version": "4.1.39",
},
]
rpms = pkgset.get_extra_rpms_from_tasks()
self.assertEqual(rpms, expected_rpms)
def test_get_latest_rpms_cache(self): def test_get_latest_rpms_cache(self):
self._touch_files( self._touch_files(
[ [