// declarative pipeline pipeline { agent { node { label 'lxbuild4' } } parameters { choice(name: 'MACHINE_TYPE', choices: ['select...', 'am335x-nrhw20', 'am335x-nmhw21', 'imx8-nmhw23', 'am335x-nmhw24', 'am335x-hw25', 'am335x-hw26'], description: 'choose target platform') choice(name: 'IMAGE_TYPE', choices: ['bootloader', 'release', 'dev', 'vcu', 'lava', 'fct', 'minimal', 'sdk'], description: 'choose target platform') string(name: 'RLS_VERSION', defaultValue: '', description: 'Set the version to build and use committed submodules') booleanParam(name: 'COLLECT_REV', defaultValue: false, description: 'collect the used revisions') booleanParam(name: 'CLEAN_BUILD', defaultValue: false, description: 'clean all temp directories before build starts') } environment { PACKAGE_NAME = 'nm-os' MACHINE = "${MACHINE_TYPE}" SHARED_BUILD = "${WORKSPACE}/build" build_deploy = "${SHARED_BUILD}/tmp/deploy/images/${MACHINE}" build_licenses = "${SHARED_BUILD}/tmp/deploy/licenses" buildhistory = "${SHARED_BUILD}/buildhistory" DISTO_VERSION_FILE = "${SHARED_BUILD}/conf/distro_version.inc" SUBMODULE_VERION_FILE = "submodule_revisions" AUTOREV_VERSION_FILE = "autorev_revisions.inc" } options { timeout(time: 8, unit: 'HOURS') buildDiscarder( logRotator(numToKeepStr: '50', daysToKeepStr: '1', artifactNumToKeepStr: '50', artifactDaysToKeepStr: '1' ) ) disableConcurrentBuilds() } stages { stage('prepare') { steps { script { if("${params.MACHINE_TYPE}" == "select...") { error("Missing machine type --> select parameter MACHINE_TYPE for a proper build") } handle_submodules("${params.RLS_VERSION}") version = build_version("${params.RLS_VERSION}") println "----------------------------------\n Job Parameters:\n----------------------------------\n\ MACHINE_TYPE = ${params.MACHINE_TYPE}\n\ IMAGE_TYPE = ${params.IMAGE_TYPE}\n\ CLEAN_BUILD = ${params.CLEAN_BUILD}\n\ COLLECT_REV = ${params.COLLECT_REV}\n\ RLS_VERSION = ${params.RLS_VERSION}\n\ --> version = ${version}\n\ ----------------------------------\n" env.BUILD_VERSION = "${version}" currentBuild.displayName = "${version}-${MACHINE}-${IMAGE_TYPE}" //replace Bitbake timestamp after building change_distro_version("${version}") } writeFile file: 'VERSION', text: "${PACKAGE_NAME}: ${BUILD_VERSION}" } } stage('clean') { when { expression { return params.CLEAN_BUILD } } steps { dir ("${SHARED_BUILD}/tmp") { deleteDir() } dir ("${SHARED_BUILD}/tmp-glibc") { deleteDir() } } } stage('collect versions') { when { expression { return params.COLLECT_REV } } steps { script { revisions = getAutoRevHashes() writeFile(file: "${env.AUTOREV_VERSION_FILE}", text: "${revisions}") } } post { success { archiveArtifacts(artifacts: "${env.SUBMODULE_VERION_FILE}, ${env.AUTOREV_VERSION_FILE}, ${env.DISTO_VERSION_FILE}", onlyIfSuccessful: false) } } } stage('build') { steps { script { build_and_archive() } dir ('tmp/artifacts') { zip archive: true, dir: "${WORKSPACE}/tmp/build-output", glob: "*", zipFile: "${PACKAGE_NAME}-${BUILD_VERSION}-${machine}-${IMAGE_TYPE}.zip" } sh "rm -rf ${WORKSPACE}/tmp" } } } // stages } def isRelease(versionParam) { if((versionParam == "") || (versionParam == "latest")) { return false } return true } def handle_submodules(versionParam) { sh 'git submodule init' if(isRelease(versionParam)) { sh 'git submodule update' // set all submodules to freezed commit } else { sh 'git submodule update --remote --rebase' // update all submodules to HEAD } submoduleStatus = sh(returnStdout: true, script: "git submodule status").trim() // print submodule hashes to jenkins log println "${submoduleStatus}" writeFile(file: "${env.SUBMODULE_VERION_FILE}", text: "${submoduleStatus}") } def build_version(versionParam) { sh 'git fetch -p' sh 'git fetch -t' def gitCmd = "git describe --tags" if(!isRelease(versionParam)) { gitCmd = "${gitCmd} --dirty" } gitversion = sh(returnStdout: true, script: "${gitCmd}").trim() String[] versionArr = "${gitversion}".split("-") if(isRelease(versionParam)) { String newVersionStr = versionParam versionArr[0] = newVersionStr } else { def buildnbr = getTopUpstreamBuildNumber() String nightlyPart = versionArr[0] + ".Test${buildnbr}" versionArr[0] = nightlyPart } rlsVersion = versionArr.join("-") return rlsVersion } def change_distro_version(versionString){ println "Set the distro version to ${versionString}..." def versionTag = "DISTRO_VERSION = \"${versionString}\"" writeFile(file: "${env.DISTO_VERSION_FILE}", text: "${versionTag}") } def cleanup_distro_version() { println "cleaning repository regarding distro version..." sh(script:"git clean -f ${env.DISTO_VERSION_FILE}") } def build_and_archive() { if (params.IMAGE_TYPE == 'sdk') { sh "bash -c '. ./env.image-ostree && bitbake -k netmodule-linux-image -c populate_sdk'" zip archive: true, dir: "${HOME}/yocto-share/build/tmp/deploy/sdk", glob: '*.sh', zipFile: "${PACKAGE_NAME}-${BUILD_VERSION}-${MACHINE}-sdk.zip" } else if (params.IMAGE_TYPE == 'bootloader') { sh "bash -c '. ./env.common && bitbake virtual/bootloader'" dir ('tmp/build-output') { sh 'cp ${build_deploy}/*u-boot-${MACHINE_TYPE}.img . || true' sh 'cp ${build_deploy}/*u-boot-${MACHINE_TYPE}.xmodem.bin . || true' sh 'cp ${build_deploy}/imx-boot . || true' sh 'cp ${build_deploy}/imx-boot.sd . || true' } } else if (params.IMAGE_TYPE == 'vcu') { build('vcu', 'vcu', false) archive('vcu', false) } else if (params.IMAGE_TYPE == 'lava' || params.IMAGE_TYPE == 'fct' || params.IMAGE_TYPE == 'minimal') { build(params.IMAGE_TYPE, params.IMAGE_TYPE, true) archive(params.IMAGE_TYPE, true) } else if (params.IMAGE_TYPE == 'release') { build('ostree', '', false) archive('', false) } else { build('ostree', params.IMAGE_TYPE, false) archive(params.IMAGE_TYPE, false) } } def build(env_in, image_type_in, single_fitImage) { def env = "${env_in}" == "" ? "" : "-${env_in}" def image_type = "${image_type_in}" == "" ? "" : "-${image_type_in}" if (single_fitImage) { sh "bash -c '. ./env.image${env} && bitbake -k virtual/netmodule-image'" } else { /* The following workaround can be removed once the explanation for the missing lic has been found */ if (! fileExists("build/tmp/deploy/licenses/gpsd")) sh "bash -c '. ./env.image${env} && bitbake -fc populate_lic gpsd'" if (! fileExists("build/tmp/deploy/licenses/ostree-kernel-initramfs")) sh "bash -c '. ./env.image${env} && bitbake -fc populate_lic ostree-kernel-initramfs'" sh "bash -c '. ./env.image${env} && bitbake -k netmodule-linux-image${image_type}'" } } def archive(image_type_in, single_fitImage) { def image_type = "${image_type_in}" == "" ? "" : "-${image_type_in}" dir ("tmp/build-output") { def image_basename = "netmodule-linux-image${image_type}-${MACHINE}" def basename_in = "${build_deploy}/${image_basename}" def basename_out = "./image${image_type}-${MACHINE}" sh "cp ${basename_in}.manifest ${basename_out}.manifest" sh "bash -c '${WORKSPACE}/openembedded-core/scripts/buildhistory-collect-srcrevs -p ${buildhistory} > srcrev-${MACHINE}${image_type}.inc'" sh label: 'Copy License Manifest', returnStatus: true, script: """ LATEST_LICENSE_DIR=\$(ls -Artd ${build_licenses}/netmodule-linux-image${image_type}* | tail -n 1) cp \$LATEST_LICENSE_DIR/license.manifest ${basename_out}_license.manifest""" if (single_fitImage == false) { sh label: 'Copy initramfs License Manifest', returnStatus: true, script: """ LATEST_LICENSE_DIR=\$(ls -Artd ${build_licenses}/initramfs-ostree-image-${MACHINE}-* | tail -n 1) cp \$LATEST_LICENSE_DIR/license.manifest initramfs-ostree-image_license.manifest """ } if(single_fitImage){ if(image_type_in == "minimal") sh "cp ${build_deploy}/initramfs-linux/fitImage-${image_basename}-${MACHINE} fitImage-${image_basename}" else sh "cp ${build_deploy}/fct-linux/fitImage-${image_basename}-${MACHINE} fitImage-${image_basename}" sh "cp ${basename_in}.tar.gz ${basename_out}.tar.gz" } else { sh "cp ${build_deploy}/fitImage-${MACHINE}.bin ." sh "cp ${basename_in}.ota-ext4 ${basename_out}.ota-ext4" sh "cp ${basename_in}.wic ${basename_out}.wic" def ostree_archive = "ostree_repo${image_type}.tar.gz" sh "tar czf ./${ostree_archive} -C ${build_deploy}/ostree_repo ." archiveArtifacts artifacts: "${ostree_archive}", onlyIfSuccessful: true sh "rm -f ./${ostree_archive}" } } } def getTopUpstreamBuildNumber() { // Iterating though all upstream jobs: // currentBuild.upstreamBuilds.each { item -> // echo "upstream build: ${item}" // def nbr = item.getNumber() // echo "nbr=${nbr}" // } def upstreamJobList = currentBuild.upstreamBuilds def nbrOfUpstreamJobs = upstreamJobList.size() if (nbrOfUpstreamJobs == 0) return 0; def topJob = upstreamJobList[nbrOfUpstreamJobs-1] println "Top upstream project: " + topJob.getFullDisplayName() def topJobNbr = topJob.getNumber() println "Top upstream job build Number = ${topJobNbr}" return topJobNbr } def getAutoRevHashes() { sh(script: "bash -c '. ./env.image-ostree && bitbake netmodule-linux-image-dev --runall=fetch'") def revs = sh(returnStdout: true, script: "bash -c \". ./env.image-ostree > /dev/null && buildhistory-collect-srcrevs\"").trim() return revs }