From 7792b66de8a40c83e0db56316155cec9e25e322d Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sun, 23 Nov 2025 11:04:36 -0600 Subject: [PATCH] fedoraBuild: Add function for building for Fedora When we want to build an RPM for Fedora, we usually need to build one per Fedora release. This is cumbersome, and typically requires changing the list of release versions to target every six months. To make this easier, I've added a `fedoraBuild` shared library function. This function will generate a matrix pipeline that runs the provided closure for every supported Fedora version+architecture combination. By default, it will run for _amd64_ and _arm64_, but callers can provide an alternate list with the `architectures` argument. The supplied closure must accept two arguments, `arch`, and `fedoraVersion`. This allows the code inside the closure to use those values, e.g. in stage names or to perform conditional build steps based on the target. By default, a node will be allocated for each target using the approproate Fedora container image. An alternate image can be supplied with the `containerImage` argument. This argument takes either a string, which will cause all containers to use the same image, or a closure that accepts the same `arch` and `fedoraVersion` variables, and returns a container image name. Example: ```groovy fedoraBuild { container('build') { sh 'echo hello from ${FEDORA}' } } ``` This will run the `sh` step in the `build` container for every currently-supported version of Fedora on _amd64_ and _arm64_ nodes. --- resources/fedoraBuild/podTemplate.yaml | 8 +++ vars/fedoraBuild.groovy | 70 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 resources/fedoraBuild/podTemplate.yaml create mode 100644 vars/fedoraBuild.groovy diff --git a/resources/fedoraBuild/podTemplate.yaml b/resources/fedoraBuild/podTemplate.yaml new file mode 100644 index 0000000..43072a0 --- /dev/null +++ b/resources/fedoraBuild/podTemplate.yaml @@ -0,0 +1,8 @@ +spec: + containers: + - name: build + command: + - cat + stdin: true + tty: true + hostUsers: false diff --git a/vars/fedoraBuild.groovy b/vars/fedoraBuild.groovy new file mode 100644 index 0000000..cb91251 --- /dev/null +++ b/vars/fedoraBuild.groovy @@ -0,0 +1,70 @@ +def call(block) { + call(null, block) +} + +def call(args, block) { + def podTemplateFile = args?.podTemplate + def architectures = args?.architectures + def buildContainer = args?.buildContainer ?: 'build' + def containerImage = args?.containerImage + if (architectures == null) { + architectures = ['amd64', 'arm64'] + } + + def podTemplateYaml + if (podTemplateFile == null) { + podTemplateYaml = libraryResource('fedoraBuild/podTemplate.yaml') + } else { + podTemplateYaml = readTrusted(podTemplateFile) + } + + def versions = getVersions() + matrixBuild(architectures, versions) { arch, fedoraVersion -> + def tmpl = readYaml(text: podTemplateYaml) + tmpl.spec.containers.each { container -> + if (container.name == buildContainer) { + if (containerImage == null) { + container.image = "registry.fedoraproject.org/fedora:${fedoraVersion}" + } else if (containerImage instanceof String) { + container.image = containerImage + } else { + container.image = containerImage(arch, fedoraVersion) + } + } + } + podTemplate( + yaml: writeYaml(data: tmpl, returnText: true), + yamlMergeStrategy: merge(), + nodeSelector: "kubernetes.io/arch=${arch}" + ) { + node(POD_LABEL) { + env.FEDORA = fedoraVersion + block(arch, fedoraVersion) + } + } + } +} + +def getVersions() { + def response = httpRequest( + url: 'https://bodhi.fedoraproject.org/releases?state=current', + acceptType: 'APPLICATION_JSON', + ) + def content = readJSON(text: response.content) + return content.releases. + findAll { it.id_prefix == "FEDORA" }. + collect { it.version } +} + +def matrixBuild(architectures, fedoraVersions, block) { + echo "Building for Fedora ${fedoraVersions}, architectures ${architectures}" + parallel architectures.collectMany { arch -> + fedoraVersions.collect { version -> + [arch, version] + } + }.collectEntries { + def arch = it[0] + def version = it[1] + ["f${version}/${arch}", { block(arch, version) }] + } +}