From: Michael Tremer Date: Thu, 6 Mar 2025 11:42:50 +0000 (+0000) Subject: jenkins: Initial import X-Git-Tag: 0.9.18~36 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5c995ee5f782b96674885782bc1b07dcaaf40520;p=location%2Flibloc.git jenkins: Initial import Signed-off-by: Michael Tremer --- diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..6614a69 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,662 @@ +pipeline { + agent none + + stages { + /* + Run the build and test suite on various distributions... + */ + stage("Run Tests on Multiple Distributions") { + matrix { + axes { + axis { + name "DISTRO" + values \ + "archlinux:base-devel", \ + "debian:trixie", \ + "debian:bookworm", \ + "fedora:41", \ + "fedora:42", \ + "ubuntu:24.10", \ + "ubuntu:25.04" + } + + axis { + name "COMPILER" + values "gcc", "clang" + } + } + + agent { + docker { + image "${DISTRO}" + + // Run as root inside the containers to install dependencies + args "-u root" + + customWorkspace "${JOB_NAME}/${BUILD_ID}/${env.DISTRO.replace(":", "-")}/${env.COMPILER}" + } + } + + stages { + stage("Install Dependencies") { + steps { + script { + // Arch Linux + if (env.DISTRO.contains("archlinux")) { + installBuildDepsArchLinux(env.DISTRO, env.COMPILER) + + // Fedora, etc. + } else if (env.DISTRO.contains("fedora")) { + installBuildDepsRedHat(env.DISTRO, env.COMPILER) + + // Debian & Ubuntu + } else if (env.DISTRO.contains("debian") || env.DISTRO.contains("ubuntu")) { + installBuildDepsDebian(env.DISTRO, env.COMPILER, "amd64") + } + } + } + } + + stage("Configure") { + steps { + // Run autogen + sh "./autogen.sh" + + // Run ./configure... + sh "CC=${env.COMPILER} ./configure --prefix=/usr --enable-debug --enable-perl" + } + + post { + failure { + archiveArtifacts artifacts: "config.log", + allowEmptyArchive: true + + echo "config.log has been archived" + } + } + } + + stage("Build") { + steps { + sh "make" + } + } + + stage("Check") { + steps { + script { + try { + sh "make check" + } catch (Exception e) { + unstable("Failed on ${env.DISTRO} with ${env.COMPILER}...") + } + } + } + + post { + always { + // Copy test logs into a special directory + sh """ + mkdir -pv tests/${DISTRO}/${COMPILER} + find tests -name "*.log" | xargs --no-run-if-empty \ + cp --verbose --parents --target-directory=tests/${DISTRO}/${COMPILER}/ + """ + + // Archive the logs only if the stage fails + archiveArtifacts artifacts: "tests/${DISTRO}/${COMPILER}/**/*" + + echo "The test logs have been archived" + } + } + } + } + + // Cleanup the workspace afterwards + post { + always { + cleanWs() + } + } + } + } + + stage("Coverage Tests") { + parallel { + stage("Address Sanitizer") { + agent { + docker { + image "debian:trixie" + + // Run as root inside the containers to install dependencies + args "-u root" + + customWorkspace "${JOB_NAME}/${BUILD_ID}/asan" + } + } + + stages { + stage("Install Dependencies") { + steps { + script { + installBuildDepsDebian("trixie", "gcc", "amd64") + } + } + } + + stage("Configure") { + steps { + sh "./autogen.sh" + sh """ + ./configure \ + --prefix=/usr \ + --enable-asan \ + --enable-debug + """ + } + } + + stage("Build") { + steps { + sh "make -j\$(nproc)" + } + } + + stage("Check") { + steps { + script { + try { + sh "make check" + } catch (Exception e) { + unstable("Address Sanitizer checks failed") + } + } + } + + post { + unstable { + // Copy test logs into a special directory + sh """ + mkdir -pv asan + find tests -name "*.log" | xargs --no-run-if-empty \ + cp --verbose --parents --target-directory=asan/ + """ + + // Archive the logs only if the stage fails + archiveArtifacts artifacts: "asan/**/*" + + echo "The test logs have been archived" + } + } + } + } + + // Cleanup the workspace afterwards + post { + always { + cleanWs() + } + } + } + + /* + Run Pakfire through Clang's Static Analyzer... + */ + stage("Clang Static Analyzer") { + agent { + docker { + image "debian:trixie" + + // Run as root inside the containers to install dependencies + args "-u root" + + customWorkspace "${JOB_NAME}/${BUILD_ID}/clang-static-analyzer" + } + } + + stages { + stage("Install Dependencies") { + steps { + script { + installBuildDepsDebian("trixie", "clang", "amd64") + + // Install Clang Tools + sh "apt-get install -y clang-tools" + } + } + } + + stage("Configure") { + steps { + sh "./autogen.sh" + sh "scan-build ./configure --prefix=/usr --enable-debug" + } + } + + stage("Build") { + steps { + sh "scan-build -o scan-build-output make -j\$(nproc)" + } + } + + stage("Publish Report") { + steps { + archiveArtifacts artifacts: "scan-build-output/**/*" + } + } + } + + // Cleanup the workspace afterwards + post { + always { + cleanWs() + } + } + } + + stage("LCOV") { + agent { + docker { + image "debian:bookworm" + + // Run as root inside the containers to install dependencies + args "-u root" + + customWorkspace "${JOB_NAME}/${BUILD_ID}/lcov" + } + } + + stages { + stage("Install Dependencies") { + steps { + script { + installBuildDepsDebian("bookworm", "gcc", "amd64") + + // Install lcov + sh "apt-get install -y lcov" + } + } + } + + stage("Configure") { + steps { + sh "./autogen.sh" + sh """ + ./configure \ + --prefix=/usr \ + --enable-coverage \ + --enable-debug + """ + } + } + + stage("Build") { + steps { + sh "make -j\$(nproc)" + } + } + + stage("Check") { + steps { + sh "make check || true" + } + } + + stage("Publish Report") { + steps { + // Capture coverage data + sh """ + lcov \ + --capture \ + --directory . \ + --output-file coverage.info + """ + + // Generate HTML report + sh """ + genhtml \ + coverage.info \ + --output-directory lcov + """ + + // Upload the report + archiveArtifacts artifacts: "lcov/**/*" + } + } + } + + // Cleanup the workspace afterwards + post { + always { + cleanWs() + } + } + } + } + } + + stage("Debian Packages") { + // Only build packages when we are in the master branch + // when { + // expression { + // env.GIT_BRANCH == "origin/master" + // } + // } + + stages { + stage("Build Debian Packages") { + matrix { + axes { + axis { + name "IMAGE" + values "debian:trixie", "debian:bookworm" + } + + axis { + name "ARCH" + values "amd64", "arm64" + } + } + + agent { + docker { + image "${IMAGE}" + + // Run as root inside the containers to install dependencies + args "-u root" + + customWorkspace "${JOB_NAME}/${BUILD_ID}/${IMAGE.replace(":", "-")}/${ARCH}" + } + } + + stages { + stage("Setup Build Environment") { + steps { + // Add the architecture + sh "dpkg --add-architecture ${env.ARCH}" + sh "apt-get update" + + // Install required packages + sh """ + apt-get install -y \ + apt-utils \ + build-essential \ + crossbuild-essential-${env.ARCH} \ + devscripts \ + qemu-user-static + """ + } + } + + stage("Install Build Dependencies") { + steps { + // Install all build dependencies + sh "apt-get build-dep -y -a${env.ARCH} ." + } + } + + stage("Tag") { + steps { + sh "dch -m \"Jenkins Build ${BUILD_ID}\" -l .build-${BUILD_ID}." + } + } + + stage("Build") { + environment { + VERSION = "" + } + + steps { + // Create the source tarball from the checked out source + sh """ + version="\$(dpkg-parsechangelog --show-field Version | sed "s/-[^-]*\$//")"; + tar \ + --create \ + --verbose \ + --xz \ + --file="../libloc_\$version.orig.tar.xz" \ + --transform="s|^|libloc-\$version/|" \ + * + """ + + // Build the packages + sh """ + dpkg-buildpackage \ + --host-arch ${env.ARCH} \ + --build=full + """ + } + } + + stage("Create Repository") { + environment { + DISTRO = "${IMAGE.replace("debian:", "")}" + } + + steps { + // Create a repository and generate Packages + sh "mkdir -pv \ + packages/debian/dists/${DISTRO}/main/binary-${ARCH} \ + packages/debian/dists/${DISTRO}/main/source \ + packages/debian/pool/${DISTRO}/main/${ARCH}" + + // Copy all packages + sh "cp -v ../*.deb packages/debian/pool/${DISTRO}/main/${ARCH}" + + // Generate Packages + sh "cd packages/debian && apt-ftparchive packages pool/${DISTRO}/main/${ARCH} \ + > dists/${DISTRO}/main/binary-${ARCH}/Packages" + + // Compress Packages + sh "xz -v9 < packages/debian/dists/${DISTRO}/main/binary-${ARCH}/Packages \ + > packages/debian/dists/${DISTRO}/main/binary-${ARCH}/Packages.xz" + + // Generate Sources + sh "cd packages/debian && apt-ftparchive sources pool/${DISTRO}/main/${ARCH} \ + > dists/${DISTRO}/main/source/Sources" + + // Compress Sources + sh "xz -v9 < packages/debian/dists/${DISTRO}/main/source/Sources \ + > packages/debian/dists/${DISTRO}/main/source/Sources.xz" + + // Generate Contents + sh "cd packages/debian && apt-ftparchive contents pool/${DISTRO}/main/${ARCH} \ + > dists/${DISTRO}/main/Contents-${ARCH}" + + // Compress Contents + sh "xz -v9 < packages/debian/dists/${DISTRO}/main/Contents-${ARCH} \ + > packages/debian/dists/${DISTRO}/main/Contents-${ARCH}.xz" + + // Stash the packages + stash includes: "packages/debian/**/*", name: "${DISTRO}-${ARCH}" + } + } + } + + // Cleanup the workspace afterwards + post { + always { + cleanWs() + } + } + } + } + + stage("Master Debian Repository") { + agent any + + // We don't need to check out the source for this stage + options { + skipDefaultCheckout() + } + + environment { + GNUPGHOME = "${WORKSPACE}/.gnupg" + KRB5CCNAME = "${WORKSPACE}/.krb5cc" + + // Our signing key + GPG_KEY_ID = "E4D20FA6FAA108D54ABDFC6541836ADF9D5E2AD9" + } + + steps { + // Cleanup the workspace + cleanWs() + + // Create the GPG stash directory + sh """ + mkdir -p $GNUPGHOME + chmod 700 $GNUPGHOME + """ + + // Import the GPG key + withCredentials([file(credentialsId: "${env.GPG_KEY_ID}", variable: "GPG_KEY_FILE")]) { + // Jenkins prefers to have single quotes here so that $GPG_KEY_FILE won't be expanded + sh 'gpg --import --batch < $GPG_KEY_FILE' + } + + // Unstash all stashed packages from the matrix build + script { + for (distro in ["trixie", "bookworm"]) { + for (arch in ["amd64", "arm64"]) { + unstash "${distro}-${arch}" + } + + // Create the Release file + sh """ + ( + echo "Origin: Pakfire Repository" + echo "Label: Pakfire Repository" + echo "Suite: stable" + echo "Codename: $distro" + echo "Version: 1.0" + echo "Architectures: amd64 arm64" + echo "Components: main" + echo "Description: Pakfire Jenkins Repository" + + # Do the rest automatically + cd packages/debian && apt-ftparchive release dists/$distro + ) >> packages/debian/dists/$distro/Release + """ + + // Create InRelease + sh """ + gpg --batch \ + --clearsign \ + --local-user ${env.GPG_KEY_ID} \ + --output packages/debian/dists/$distro/InRelease \ + packages/debian/dists/$distro/Release + """ + + // Create Release.gpg + sh """ + gpg --batch \ + --armor \ + --detach-sign \ + --local-user ${env.GPG_KEY_ID} \ + --output packages/debian/dists/$distro/Release.gpg \ + packages/debian/dists/$distro/Release + """ + } + } + + // Export the public key + sh "gpg --batch --export --armor ${env.GPG_KEY_ID} \ + > packages/debian/${env.GPG_KEY_ID}.asc" + + // Remove the GPG key material as soon as possible + sh "rm -rf $GNUPGHOME" + + // Upload everything again + archiveArtifacts artifacts: "packages/debian/**/*" + + // Fetch a Kerberos ticket + withCredentials([file(credentialsId: "jenkins.keytab", variable: "KEYTAB")]) { + sh 'kinit -kV -t $KEYTAB jenkins@IPFIRE.ORG' + } + + // Publish files + sh """ + rsync \ + --verbose \ + --recursive \ + --delete \ + --delete-excluded \ + --delay-updates \ + packages/debian/ \ + pakfire@fs01.haj.ipfire.org:/pub/mirror/packages/debian/libloc + """ + + // Destroy the Kerberos credentials + sh "kdestroy" + } + } + } + } + } +} + +// Installs everything we need on RHEL/Fedora/etc. +def installBuildDepsRedHat(distro, compier) { + // Install basic development tools + sh "dnf group install -y development-tools" + + // Install our own build and runtime dependencies + sh """ + dnf install -y \ + asciidoc \ + autoconf \ + automake \ + intltool \ + libtool \ + pkg-config \ + ${compiler} \ + \ + openssl-devel \ + perl-devel \ + python3-devel \ + systemd-devel + """ +} + +// Installs everything we need on Arch Linux +def installBuildDepsArchLinux(distro, compiler) { + sh "pacman -Syu --noconfirm" + sh """ + pacman -Sy \ + --needed \ + --noconfirm \ + asciidoc \ + autoconf \ + automake \ + intltool \ + libtool \ + pkg-config \ + ${compiler} \ + \ + openssl \ + perl \ + python3 \ + systemd + """ +} + +// Installs everything we need on Debian +def installBuildDepsDebian(distro, compiler, arch) { + sh "apt-get update" + sh """ + apt-get install -y \ + --no-install-recommends \ + asciidoc \ + autoconf \ + automake \ + build-essential \ + intltool \ + libtool \ + pkg-config \ + ${compiler} \ + \ + libperl-dev \ + libpython3-dev \ + libssl-dev \ + libsystemd-dev + """ +}