You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
8.8 KiB

#!/usr/bin/env groovy
def boards = []
def examples = []
def tests = []
def driver_tests = []
def pkg_tests = []
def periph_tests = []
def other_tests = []
def unittests = []
/* stop running jobs */
abortPreviousBuilds()
stage('setup') {
node ('master') {
sh '(( "\${RIOT_MIRROR}" )) && git -C "\${RIOT_MIRROR_DIR}" fetch --all'
deleteDir()
fetchPR(env.CHANGE_ID, "--depth=1", "")
/* get all boards */
boards = sh(returnStdout: true,
script: 'find $(pwd)/boards/* -maxdepth 0 -type d \\! -name "*-common" -exec basename {} \\;'
).trim().split('\n')
/* get all examples */
examples = sh(returnStdout: true,
script: 'find examples/* -maxdepth 1 -name Makefile -print0 | xargs -0 -n1 dirname'
).trim().split('\n')
/* get all tests */
tests = sh(returnStdout: true,
script: 'find tests/* -maxdepth 1 -name Makefile -print0 | xargs -0 -n1 dirname'
).trim().split('\n')
/* split tests into smaller sets */
for (int i=0; i < tests.size(); i++) {
if (tests[i].startsWith("tests/driver_")) {
driver_tests << tests[i]
}
else if (tests[i].startsWith("tests/pkg_")) {
pkg_tests << tests[i]
}
else if (tests[i].startsWith("tests/periph_")) {
periph_tests << tests[i]
}
else if (tests[i].startsWith("tests/unittests")) {
unittests << tests[i]
}
else {
other_tests << tests[i]
}
}
deleteDir()
}
}
stage('static-tests') {
node('linux && boards') {
deleteDir()
fetchPR(env.CHANGE_ID, "", "master:master")
def ret = sh(returnStatus: true,
script: """#!/bin/bash +x
declare -i RESULT=0
./dist/tools/static-tests.sh >> success_static-tests.log 2>&1 || RESULT=1
if ((\$RESULT)); then
mv success_static-tests.log error_static-tests.log;
fi;
exit \$RESULT""")
if (ret) {
currentBuild.result = 'UNSTABLE'
}
step([$class: 'ArtifactArchiver', artifacts: "*_static-tests.log", fingerprint: true, allowEmptyArchive: true])
deleteDir()
}
}
stage("unittests") {
def builds = [:]
/* setup all concurrent builds */
def boardName = ""
for (int i=0; i < boards.size(); i++) {
boardName = boards[i]
builds['linux_unittests_' + boardName] = make_build("linux && boards && native", boardName, "linux_unittests", unittests)
}
/* distribute all builds to the slaves */
parallel (builds)
abortOnError("unittests failed")
}
stage("tests") {
def builds = [:]
/* setup all concurrent builds */
def boardName = ""
for (int i=0; i < boards.size(); i++) {
boardName = boards[i]
builds['linux_driver_tests_' + boardName] = make_build("linux && boards && native", boardName, "linux_driver_tests", driver_tests)
builds['linux_pkg_tests_' + boardName] = make_build("linux && boards && native", boardName, "linux_pkg_tests", pkg_tests)
builds['linux_periph_tests_' + boardName] = make_build("linux && boards && native", boardName, "linux_periph_tests", periph_tests)
builds['linux_other_tests_' + boardName] = make_build("linux && boards && native", boardName, "linux_other_tests", other_tests)
}
/* ignore macOS builds for now - macOS is currently broken for native
builds['macOS_driver_tests_native'] = make_build("macOS && native", "native", "macOS_driver_tests", driver_tests)
builds['macOS_pkg_tests_native'] = make_build("macOS && native", "native", "macOS_pkg_tests", pkg_tests)
builds['macOS_periph_tests_native'] = make_build("macOS && native", "native", "macOS_periph_tests", periph_tests)
builds['macOS_other_tests_native'] = make_build("macOS && native", "native", "macOS_other_tests", other_tests)
*/
/* ignore raspi builds for now - slows down the build (needs investigation)
builds['raspi_driver_tests_native'] = make_build("raspi && native", "native", "raspi_driver_tests", driver_tests)
builds['raspi_pkg_tests_native'] = make_build("raspi && native", "native", "raspi_pkg_tests", pkg_tests)
builds['raspi_periph_tests_native'] = make_build("raspi && native", "native", "raspi_periph_tests", periph_tests)
builds['raspi_other_tests_native'] = make_build("raspi && native", "native", "raspi_other_tests", other_tests)
*/
/* distribute all builds to the slaves */
parallel (builds)
abortOnError("tests failed")
}
stage("examples") {
def builds = [:]
/* setup all concurrent builds */
def boardName = ""
for (int i=0; i < boards.size(); i++) {
boardName = boards[i]
builds['linux_examples_' + boardName] = make_build("linux && boards && native", boardName, "linux_examples", examples)
}
/* ignore macOS builds for now - macOS is currently broken for native
builds['macOS_examples_native'] = make_build("macOS && native", "native", "macOS_examples", examples)
*/
/* ignore raspi builds for now - slows down the build (needs investigation)
builds['raspi_examples_native'] = make_build("raspi && native", "native", "raspi_examples", examples)
*/
/* distribute all builds to the slaves */
parallel (builds)
abortOnError("examples failed")
}
if (currentBuild.result == null) {
currentBuild.result = 'SUCCESS'
}
/* create a job */
def make_build(label, board, desc, arg)
{
return {
node(label) {
try {
deleteDir()
fetchPR(env.CHANGE_ID, "--depth=1", "")
def build_dir = pwd()
sh "./dist/tools/git/git-cache init"
timestamps {
def apps = arg.join(' ')
echo "building ${apps} for ${board} on nodes with ${label}"
withEnv([
"BOARD=${board}",
"CCACHE_BASEDIR=${build_dir}",
"RIOT_CI_BUILD=1"]) {
def ret = sh(returnStatus: true,
script: """#!/bin/bash +ex
declare -i RESULT=0
for app in ${apps}; do
if [[ \$(make -sC \$app info-boards-supported | tr ' ' '\n' | sed -n '/^${board}\$/p') ]]; then
echo \"\n\nBuilding \$app for ${board}\" >> success_${board}_${desc}.log
rm -rf jenkins_bin; mkdir jenkins_bin
CFLAGS_DBG=\"\" BINDIR=\$(pwd)/jenkins_bin make -j\${NPROC} -C \$app all >> success_${board}_${desc}.log 2>&1 || RESULT=1
fi;
done;
if ((\$RESULT)); then
mv success_${board}_${desc}.log error_${board}_${desc}.log
fi;
exit \$RESULT""")
if (ret) {
currentBuild.result = 'FAILURE'
}
step([$class: 'ArtifactArchiver', artifacts: "*_${board}_${desc}.log", fingerprint: true, allowEmptyArchive: true])
}
}
} catch(e) {
echo "${e.toString()}"
currentBuild.result = 'FAILURE'
} finally {
deleteDir()
}
}
}
}
/* abort previous, running builds */
def abortPreviousBuilds()
{
def buildnum = env.BUILD_NUMBER.toInteger()
def job = Jenkins.instance.getItemByFullName(env.JOB_NAME)
for (build in job.builds) {
if (!build.isBuilding() || (buildnum == build.getNumber().toInteger())) {
continue;
}
build.doStop();
}
}
def abortOnError(msg)
{
if ((currentBuild.result != null) && (currentBuild.result == 'FAILURE')) {
error msg
}
}
def fetchPR(prNum, fetchArgs, extraRefSpec)
{
sh """git init
if (( "\${RIOT_MIRROR}" )); then RIOT_URL="\${RIOT_MIRROR_URL}"; else RIOT_URL="https://github.com/RIOT-OS/RIOT"; fi
git remote add origin "\${RIOT_URL}"
for RETRIES in {1..3}; do
timeout 30 git fetch -u -n ${fetchArgs} origin ${extraRefSpec} pull/${prNum}/merge:pull_${prNum} && break
done
[[ "\$RETRIES" -eq 3 ]] && exit 1
git checkout pull_${prNum}"""
}