Skip to content
Snippets Groups Projects
.murdock 6.48 KiB
Newer Older
  • Learn to ignore specific revisions
  • : ${TEST_BOARDS_AVAILABLE:="samr21-xpro"}
    
    : ${TEST_BOARDS_LLVM_COMPILE:="iotlab-m3 native nrf52dk mulle nucleo-f401re samr21-xpro slstk3402a"}
    
    export RIOT_CI_BUILD=1
    export STATIC_TESTS=${STATIC_TESTS:-1}
    export CFLAGS_DBG=""
    
    export DLCACHE_DIR=${DLCACHE_DIR:-~/.dlcache}
    
    NIGHTLY=${NIGHTLY:-0}
    RUN_TESTS=${RUN_TESTS:-${NIGHTLY}}
    
    
    DWQ_ENV="-E BOARDS -E APPS -E NIGHTLY -E RUN_TESTS"
    
    
    check_label() {
        local label="${1}"
        [ -z "${CI_PULL_LABELS}" ] && return 1
        echo "${CI_PULL_LABELS}" | grep -q "${label}"
        return $?
    }
    
    [ "$RUN_TESTS" != "1" ] && {
        check_label "CI: run tests" && RUN_TESTS=1
    }
    
    
    error() {
        echo "$@"
        exit 1
    }
    
    
    # if MURDOCK_HOOK is set, this function will execute it and pass on all it's
    # parameters. should the hook script exit with negative exit code, hook() makes
    # this script exit with error, too.
    # hook() will be called from different locations of this script.
    # currently, the only caller is "run_test", which calls "hook run_test_pre".
    # More hooks will be added as needed.
    hook() {
        if [ -n "${MURDOCK_HOOK}" ]; then
            echo "- executing hook $1"
            "${MURDOCK_HOOK}" "$@" || {
                error "$0: hook \"${MURDOCK_HOOK} $@\" failed!"
            }
            echo "- hook $1 finished"
        fi
    }
    
    
    # true if word "$1" is in list of words "$2", false otherwise
    # uses grep -w, thus only alphanum and "_" count as word bounderies
    # (word "def" matches "abc-def")
    is_in_list() {
        [ $# -ne 2 ] && return 1
    
        local needle="$1"
        local haystack="$2"
    
        echo "$haystack" | grep -q -w "$needle"
    }
    
    
    _greplist() {
        if [ $# -eq 0 ]; then
            echo cat
        else
            echo -n "grep -E ($1"
            shift
            for i in $*; do
                echo -n "|$i"
            done
            echo ")"
        fi
    }
    
    # get list of all app directories
    get_apps() {
    
        make -f makefiles/app_dirs.inc.mk info-applications \
            | $(_greplist $APPS) | sort
    
    }
    
    # take app dir as parameter, print all boards that are supported
    # Only print for boards in $BOARDS.
    get_supported_boards() {
        local appdir=$1
    
        local boards="$(make --no-print-directory -C$appdir info-boards-supported 2>/dev/null || echo broken)"
    
        if [ "$boards" = broken ]; then
            echo "makefile_broken"
            return
        fi
    
        for board in $boards
    
        do
            echo $board
        done | $(_greplist $BOARDS)
    }
    
    
    get_supported_toolchains() {
        local appdir=$1
        local board=$2
        local toolchains="gnu"
    
        if is_in_list "${board}" "${TEST_BOARDS_LLVM_COMPILE}"; then
            toolchains="$(make -s --no-print-directory -C${appdir} BOARD=${board} \
                          info-toolchains-supported 2> /dev/null | grep -o -e "llvm" -e "gnu")"
        fi
        echo "${toolchains}"
    }
    
    # given an app dir as parameter, print "$appdir $board:$toolchain" for each
    # supported board and toolchain. Only print for boards in $BOARDS.
    get_app_board_toolchain_pairs() {
    
        local appdir=$1
        for board in $(get_supported_boards $appdir)
        do
    
            for toolchain in $(get_supported_toolchains $appdir $board)
            do
                echo $appdir $board:$toolchain
            done
    
    # use dwqc to create full "appdir board toolchain" compile job list
    
    get_compile_jobs() {
        get_apps | \
    
            "$0 get_app_board_toolchain_pairs \${1}" \
    
            | xargs '-d\n' -n 1 echo $0 compile
    }
    
    
    print_worker() {
        [ -n "$DWQ_WORKER" ] && \
            echo "-- running on worker ${DWQ_WORKER} thread ${DWQ_WORKER_THREAD}, build number $DWQ_WORKER_BUILDNUM."
    }
    
    
    # compile one app for one board with one toolchain. delete intermediates.
    
    compile() {
        local appdir=$1
    
        local board=$(echo $2 | cut -f 1 -d':')
        local toolchain=$(echo $2 | cut -f 2 -d':')
    
        [ "$board" = "makefile_broken" ] && error "$0: Makefile in \"$appdir\" seems to be broken!"
    
    
        # set build directory. CI ensures only one build at a time in $(pwd).
        export BINDIR="$(pwd)/build"
        export PKGDIRBASE="${BINDIR}/pkg"
    
    
        # Pre-build cleanup
        rm -rf ${BINDIR}
    
    
    
        # sanity checks
    
        [ $# -ne 2 ] && error "$0: compile: invalid parameters (expected \$appdir \$board:\$toolchain)"
    
        [ ! -d "$appdir" ] && error "$0: compile: error: application directory \"$appdir\" doesn't exist"
        [ ! -d "boards/$board" ] && error "$0: compile: error: board directory \"boards/$board\" doesn't exist"
    
    
        CCACHE_BASEDIR="$(pwd)" BOARD=$board TOOLCHAIN=$toolchain RIOT_CI_BUILD=1 \
    
            make -C${appdir} clean all -j${JOBS:-4}
        RES=$?
    
    
        if [ $RES -eq 0 ]; then
    
            if [ $RUN_TESTS -eq 1 -o "$board" = "native" ]; then
                if [ -f "${BINDIR}/.test" ]; then
                    if [ "$board" = "native" ]; then
                        BOARD=$board make -C${appdir} test
                        RES=$?
                    elif is_in_list "$board" "$TEST_BOARDS_AVAILABLE"; then
    
                        BOARD=$board TOOLCHAIN=$toolchain make -C${appdir} test-murdock
    
        if [ -d ${BINDIR} ]
        then
            echo "-- build directory size: $(du -sh ${BINDIR} | cut -f1)"
    
            # cleanup
            rm -rf ${BINDIR}
        fi
    
    test_job() {
        local appdir=$1
    
        local board=$(echo $2 | cut -f 1 -d':')
        local toolchain=$(echo $2 | cut -f 2 -d':')
    
        local flashfile="$3"
    
        [ ! -f "$flashfile" ] && {
            echo "$0: _test(): flashfile \"$flashfile\" doesn't exist!"
            return 1
        }
    
        dwqc \
    
            ${DWQ_JOBID:+--subjob} \
            --file $flashfile:$appdir/bin/${board}/$(basename $flashfile) \
            --queue ${TEST_QUEUE:-$board} \
            --maxfail 1 \
    
            "./.murdock run_test $appdir $board:$toolchain"
    
        local board=$(echo $2 | cut -f 1 -d':')
        local toolchain=$(echo $2 | cut -f 2 -d':')
    
        echo "-- executing tests for $appdir on $board (compiled with $toolchain toolchain):"
    
        hook run_test_pre
    
        BOARD=$board TOOLCHAIN=${toolchain} make -C$appdir flash-only test
    
    # execute static tests
    static_tests() {
        local repo=${CI_BASE_REPO:-https://github.com/RIOT-OS/RIOT}
        local branch=${CI_BASE_BRANCH:-master}
    
    
        OUT="$(git remote add upstream $repo 2>&1 && git fetch upstream ${branch}:${branch} 2>&1)"
        RES=$?
        if [ $RES -ne 0 ]; then
            echo "$OUT"
            exit 1
        fi
    
        BUILDTEST_MCU_GROUP=static-tests ./dist/tools/ci/build_and_test.sh
    }
    
    get_jobs() {
        [ "$STATIC_TESTS" = "1" ] && \
            echo "$0 static_tests###{ \"jobdir\" : \"exclusive\" }"
        get_compile_jobs
    }
    
    $*