boolean targetNeedsBuild(targetName) { // matches an exact path name rebuildWhenFileModified = [ "modules", "Makefile", "targets/${targetName}", "${targetName.split('-')[0]}.inc", "contrib/ci/Jenkinsfile" ] // matches a path by its prefix rebuildWhenPathModified = [ "patches/", "scripts/", ] if (targetName == "x86-64") { rebuildWhenPathModified.addAll([ "package/", "tests/" ]) } result = false for (changeLogSet in currentBuild.changeSets) { for (entry in changeLogSet.getItems()) { for (file in entry.getAffectedFiles()) { if (file.getPath() in rebuildWhenFileModified) { println("file ${file.getPath()} modified, rebuild ${targetName}") result = true } for (path in rebuildWhenPathModified) { if (file.getPath().startsWith(path)) { println("path ${path} with file ${file.getPath()} modified, rebuild ${targetName}") result = true } } } } } return result } pipeline { agent none environment { GLUON_BRANCH = "ci" GLUON_DEPRECATED = "full" GLUON_RELEASE = "fixed" GLUON_SITEDIR = "contrib/ci/minimal-site" BROKEN = "1" BUILD_LOG = "1" } stages { stage('lint') { parallel { stage('lint-lua') { agent { label 'gluon-docker' } steps { sh label: 'Identify runner', script: 'echo $SLAVE_NAME' sh 'make lint-lua' } } stage('lint-sh') { agent { label 'gluon-docker-v1' } steps { sh label: 'Identify runner', script: 'echo $SLAVE_NAME' sh 'make lint-sh' } } } } stage('docs') { agent { label 'gluon-docker' } steps { sh label: 'Identify runner', script: 'echo $SLAVE_NAME' sh 'make -C docs html' } } stage('debug') { agent { label "gluon-docker-v2" } steps { script { for (changeLogSet in currentBuild.changeSets) { for (entry in changeLogSet.getItems()) { for (file in entry.getAffectedFiles()) { println("${file.getPath()} modified") } } } } } } stage('build') { agent { label "gluon-docker-v2" } steps { script { def jobs = [:] for (target in findFiles(glob: "targets/*")) { def targetName = target.name if (targetName == "generic" || targetName.endsWith(".inc") || targetName.endsWith(".mk")) { continue } if (!targetNeedsBuild(targetName)) { continue } jobs[targetName] = { node (label: "gluon-docker-v2") { stage(targetName) { checkout scm sh label: 'Identify runner', script: 'echo $SLAVE_NAME' targetNeedsBuild(targetName) sh 'make update' sh label: ' Symlink download cache', script: 'test -d /dl_cache && ln -s /dl_cache openwrt/dl || true' timeout(time: 2, unit: "HOURS") { sh label: "Build ${targetName}", script: "make -j\$(nproc) GLUON_TARGET=${targetName} V=s" } sh 'make manifest' sh 'cat output/images/sysupgrade/*.manifest' script { if (targetName == "x86-64") { stash includes: '**/output/images/factory/*-x86-64.img.gz', name: 'gluon-x86-64-factory' } } } } } } if (jobs.isEmpty()) { println("No targets required a rebuild") } parallel jobs } } } stage('test') { agent { label 'gluon-docker-v2' } steps { sh label: 'Identify runner', script: 'echo $SLAVE_NAME' script { try { unstash 'gluon-x86-64-factory' } catch (err) { echo err.getMessage() // Abort here, if we don't have an x86-64 factory image we can't run tests currentBuild.result = 'ABORTED' return } sh label: 'Unpack image', script: 'gunzip -cd ./output/images/factory/*x86-64*.img.gz > ./image.img' sh label: 'Print python environment', script: 'python3 -m pip freeze' for (f in findFiles(glob: 'tests/*.py')) { timeout(time: 10, unit: "MINUTES") { sh label: "Test ${f.name}", script: "python3 tests/${f.name} --use-tmp-workdir" } } } } } } } /* api-history: Every time the build dependencies of gluon change, the version every container has to be rebuilt. Therefore, we use Jenkins labels which intoduce a version number which is documented here. As soon, as you properly rebuilt your docker container, you can notify lemoer, that you have updated your node. - gluon-docker-v1: - add shellcheck binary to the build environment - gluon-docker-v2: - add qemu-testlab testing, requires KVM virtualization support - require rsync dependency to be able to build the next branch */