mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
17dcb97571
This tests if the latest manifest on dockerhub matches the pinned version. The idea is that PRs are not merged until the pinning is fixed, so that we can ensure that `make BUILD_IN_DOCKER=1` will always succeed with the pinned version.
438 lines
16 KiB
Bash
Executable File
438 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Copyright (C) 2018 Gaëtan Harter <gaetan.harter@fu-berlin.de>
|
|
#
|
|
# This file is subject to the terms and conditions of the GNU Lesser
|
|
# General Public License v2.1. See the file LICENSE in the top level
|
|
# directory for more details.
|
|
#
|
|
|
|
#
|
|
# Central test script to have sanity checks for the build system
|
|
# It is run unconditionally on all files.
|
|
#
|
|
#
|
|
|
|
: "${RIOTBASE:="$(cd "$(dirname "$0")/../../../" || exit; pwd)"}"
|
|
|
|
: "${RIOTTOOLS:=${RIOTBASE}/dist/tools}"
|
|
: "${RIOTMAKE:=${RIOTBASE}/makefiles}"
|
|
# not running shellcheck with -x in the CI --> disable SC1091
|
|
# shellcheck disable=SC1091
|
|
. "${RIOTTOOLS}"/ci/github_annotate.sh
|
|
|
|
SCRIPT_PATH=dist/tools/buildsystem_sanity_check/check.sh
|
|
|
|
error_with_message() {
|
|
while read -r INPUT; do
|
|
MESSAGE="${1}"
|
|
if github_annotate_is_on; then
|
|
FILE=$(echo "${INPUT}" | cut -d: -f1)
|
|
LINE=$(echo "${INPUT}" | cut -d: -f2)
|
|
MATCH=$(echo "${INPUT}" | cut -d: -f3)
|
|
if [[ ! $LINE =~ ^[0-9]+$ ]] || [ -z "$MATCH" ]; then
|
|
# line is not provided in grep pattern
|
|
LINE=0
|
|
fi
|
|
github_annotate_error "$FILE" "$LINE" "$MESSAGE"
|
|
fi
|
|
|
|
printf "%s:\n\t%s\n\n" "${MESSAGE}" "${INPUT}"
|
|
done
|
|
}
|
|
|
|
# Modules should not check the content of FEATURES_PROVIDED/_REQUIRED/OPTIONAL
|
|
# Handling specific behaviors/dependencies should by checking the content of:
|
|
# * `USEMODULE`
|
|
# * maybe `FEATURES_USED` if it is not a module (== not a periph_)
|
|
check_not_parsing_features() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e 'if.*filter.*FEATURES_PROVIDED')
|
|
patterns+=(-e 'if.*filter.*FEATURES_REQUIRED')
|
|
patterns+=(-e 'if.*filter.*FEATURES_OPTIONAL')
|
|
|
|
# Pathspec with exclude should start by an inclusive pathspec in git 2.7.4
|
|
pathspec+=('*')
|
|
|
|
# Ignore this file when matching as it self matches
|
|
pathspec+=(":!${SCRIPT_PATH}")
|
|
|
|
# These two files contain sanity checks using FEATURES_ so are allowed
|
|
pathspec+=(':!Makefile.include' ':!makefiles/info-global.inc.mk')
|
|
|
|
# We extend FEATURES_PROVIDED in Makefile.features based on what is
|
|
# already provided to avoid clutter in each boards Makefile.features.
|
|
# E.g. `periph_eth` will pull in `netif_ethernet`, which
|
|
# will pull in `netif`.
|
|
pathspec+=(':!Makefile.features')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'Modules should not check the content of FEATURES_PROVIDED/REQUIRED/OPTIONAL'
|
|
}
|
|
|
|
# Providing features for boards and CPUs should only be done in
|
|
# Makefile.features
|
|
check_providing_features_only_makefile_features() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e '^[ ]*FEATURES_PROVIDED *+= *')
|
|
|
|
pathspec+=("*Makefile\.*")
|
|
|
|
pathspec+=(":!*Makefile.features")
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'Features should only be provided in Makefile.features files'
|
|
}
|
|
|
|
# Some variables do not need to be exported and even cause issues when being
|
|
# exported because they are evaluated even when not needed.
|
|
#
|
|
# Currently this blacklists exported variables instead of whitelisting or
|
|
# providing a mechanism for handling it.
|
|
# It just keep things not exported anymore in the future.
|
|
UNEXPORTED_VARIABLES=()
|
|
UNEXPORTED_VARIABLES+=('FLASHFILE')
|
|
UNEXPORTED_VARIABLES+=('TERMPROG' 'TERMFLAGS')
|
|
UNEXPORTED_VARIABLES+=('FLASHER' 'FFLAGS')
|
|
UNEXPORTED_VARIABLES+=('RESET' 'RESETFLAGS')
|
|
UNEXPORTED_VARIABLES+=('DEBUGGER' 'DEBUGGER_FLAGS')
|
|
UNEXPORTED_VARIABLES+=('DEBUGSERVER' 'DEBUGSERVER_FLAGS')
|
|
UNEXPORTED_VARIABLES+=('DEBUGCLIENT' 'DEBUGCLIENT_FLAGS')
|
|
UNEXPORTED_VARIABLES+=('PREFLASHER' 'PREFFLAGS' 'FLASHDEPS')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_DEBUG_ADAPTER' 'DEBUG_ADAPTER_ID')
|
|
UNEXPORTED_VARIABLES+=('PROGRAMMER_SERIAL')
|
|
UNEXPORTED_VARIABLES+=('STLINK_VERSION')
|
|
UNEXPORTED_VARIABLES+=('PORT_LINUX' 'PORT_DARWIN')
|
|
UNEXPORTED_VARIABLES+=('PORT[ ?=:]' 'PORT$')
|
|
UNEXPORTED_VARIABLES+=('LINKFLAGS' 'LINKER_SCRIPT')
|
|
UNEXPORTED_VARIABLES+=('USEMODULE_INCLUDES')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_ADAPTER_INIT')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_CONFIG')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_RESET_USE_CONNECT_ASSERT_SRST')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_CMD_RESET_RUN')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_PRE_FLASH_CMDS' 'OPENOCD_PRE_VERIFY_CMDS')
|
|
UNEXPORTED_VARIABLES+=('OPENOCD_PRE_FLASH_CHECK_SCRIPT')
|
|
UNEXPORTED_VARIABLES+=('PYOCD_FLASH_TARGET_TYPE')
|
|
UNEXPORTED_VARIABLES+=('PYOCD_ADAPTER_INIT')
|
|
UNEXPORTED_VARIABLES+=('JLINK_DEVICE' 'JLINK_IF')
|
|
UNEXPORTED_VARIABLES+=('JLINK_PRE_FLASH' 'JLINK_RESET_FILE')
|
|
UNEXPORTED_VARIABLES+=('GIT_CACHE' 'GIT_CACHE_DIR')
|
|
UNEXPORTED_VARIABLES+=('LINKXX')
|
|
UNEXPORTED_VARIABLES+=('APPDEPS' 'BUILDDEPS' 'DEBUGDEPS')
|
|
UNEXPORTED_VARIABLES+=('EMULATOR' 'EMULATOR_FLAGS')
|
|
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS=()
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('CPU_ARCH')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('CPU_CORE')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('CPU_FAM')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('NATIVEINCLUDES')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('UNDEF')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('USEMODULE')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('TARGET_ARCH')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('TOOLCHAIN')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('WERROR')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('WPEDANTIC')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('CC[ =]' 'CXX' 'CCAS')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('AR[ =]' 'RANLIB')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('AS' 'NM' 'SIZE' 'LINK')
|
|
EXPORTED_VARIABLES_ONLY_IN_VARS+=('OBJDUMP' 'OBJCOPY')
|
|
|
|
check_not_exporting_variables() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
for variable in "${UNEXPORTED_VARIABLES[@]}"; do
|
|
patterns+=(-e "export[[:blank:]]\+${variable}")
|
|
done
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" \
|
|
| error_with_message 'Variables must not be exported'
|
|
|
|
# Some variables may still be exported in 'makefiles/vars.inc.mk' as the
|
|
# only place that should export common variables
|
|
pathspec+=('*')
|
|
pathspec+=(':!makefiles/vars.inc.mk')
|
|
pathspec+=(':!**/Vagrantfile')
|
|
|
|
patterns=()
|
|
for variable in "${EXPORTED_VARIABLES_ONLY_IN_VARS[@]}"; do
|
|
patterns+=(-e "export[[:blank:]]\+${variable}")
|
|
done
|
|
|
|
# Only run if there are patterns, otherwise it matches everything
|
|
if [ ${#patterns[@]} -ne 0 ]; then
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Variables must only be exported in \`makefiles/vars.inc.mk\`"
|
|
fi
|
|
}
|
|
|
|
# Deprecated variables or patterns
|
|
# Prevent deprecated variables or patterns to re-appear after cleanup
|
|
check_deprecated_vars_patterns() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e 'FEATURES_MCU_GROUP')
|
|
patterns+=(-e 'TEST_ON_CI_WHITELIST += all')
|
|
|
|
# Pathspec with exclude should start by an inclusive pathspec in git 2.7.4
|
|
pathspec+=('*')
|
|
|
|
# Ignore this file when matching as it self matches
|
|
pathspec+=(":!${SCRIPT_PATH}")
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'Deprecated variables or patterns'
|
|
}
|
|
|
|
# Makefile files cpu must not be included by the board anymore
|
|
# They are included by the main Makefile.include/Makefile.features/Makefile.dep
|
|
check_board_do_not_include_cpu_features_dep() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e "include \$(RIOTCPU)/.*/Makefile\..*")
|
|
|
|
pathspec+=('boards/')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'Makefiles files from cpu must not be included by the board anymore'
|
|
}
|
|
|
|
# CPU and CPU_MODEL definition have been moved to 'BOARD|CPU/Makefile.features'
|
|
check_cpu_cpu_model_defined_in_makefile_features() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
# With our without space and with or without ?=
|
|
patterns+=(-e '^ *\(export\)\? *CPU \??\?=')
|
|
patterns+=(-e '^ *\(export\)\? *CPU_MODEL \??\?=')
|
|
pathspec+=(':!**.md')
|
|
pathspec+=(':!boards/**/Makefile.features')
|
|
pathspec+=(':!cpu/**/Makefile.features')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'CPU and CPU_MODEL definition must be done by board/BOARD/Makefile.features, board/common/**/Makefile.features or cpu/CPU/Makefile.features'
|
|
}
|
|
|
|
# Applications Makefile must not set 'BOARD =' unconditionally
|
|
check_not_setting_board_equal() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e '^[[:space:]]*BOARD[[:space:]]*=')
|
|
|
|
pathspec+=('**/Makefile')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'Applications Makefile should use "BOARD ?="'
|
|
}
|
|
|
|
# Examples must not provide BOARD_INSUFFICIENT_MEMORY in Makefile, but in
|
|
# Makefile.ci
|
|
check_board_insufficient_memory_not_in_makefile() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e '^[[:space:]]*BOARD_INSUFFICIENT_MEMORY[[:space:]:+]*=')
|
|
|
|
pathspec+=('**/Makefile')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message 'Move BOARD_INSUFFICIENT_MEMORY to Makefile.ci'
|
|
}
|
|
|
|
# Test applications must not define the APPLICATION variable
|
|
checks_tests_application_not_defined_in_makefile() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e '^[[:space:]]*APPLICATION[[:space:]:+]=')
|
|
|
|
pathspec+=('tests/**/Makefile')
|
|
pathspec+=(':!tests/build_system/external_board_native/Makefile')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Don't define APPLICATION in test Makefile"
|
|
}
|
|
|
|
# Develhelp should not be set via CFLAGS
|
|
checks_develhelp_not_defined_via_cflags() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e '^[[:space:]]*CFLAGS[[:space:]:+]+=[[:space:]:+]-DDEVELHELP')
|
|
|
|
pathspec+=('**/Makefile')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Use DEVELHELP ?= 1 instead of using CFLAGS directly"
|
|
}
|
|
|
|
|
|
# Common code in boards should not use $(BOARD) to reference files
|
|
check_files_in_boards_not_reference_board_var() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e "/\$(BOARD)/")
|
|
|
|
pathspec+=('boards/')
|
|
# boards/common/nrf52 uses a hack to resolve dependencies early
|
|
pathspec+=(':!boards/common/nrf52/Makefile.include')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Code in boards/ should not use \$(BOARDS) to reference files since this breaks external BOARDS changing BOARDSDIR"
|
|
}
|
|
|
|
check_no_pseudomodules_in_makefile_dep() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e 'PSEUDOMODULES[\t ]*[+:]*=')
|
|
|
|
pathspec+=('**/Makefile.dep')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Don't define PSEUDOMODULES in Makefile.dep"
|
|
}
|
|
|
|
check_no_usemodules_in_makefile_include() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e 'USEMODULE[\t ]*[+:]*=')
|
|
|
|
pathspec+=('**/Makefile.include')
|
|
pathspec+=(':!Makefile.include')
|
|
pathspec+=(':!tests/**/Makefile.include')
|
|
pathspec+=(':!examples/**/Makefile.include')
|
|
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Don't include USEMODULE in Makefile.include"
|
|
}
|
|
|
|
check_no_pkg_source_local() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e 'PKG_SOURCE_LOCAL')
|
|
|
|
pathspec+=('pkg/*/Makefile')
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Don't push PKG_SOURCE_LOCAL definitions upstream"
|
|
}
|
|
|
|
check_no_riot_config() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e 'RIOT_CONFIG_.*')
|
|
|
|
pathspec+=('Makefile*')
|
|
pathspec+=('**/Makefile*')
|
|
pathspec+=('**/*.mk')
|
|
pathspec+=(':!makefiles/kconfig.mk')
|
|
pathspec+=(':!makefiles/docker.inc.mk')
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Don't push RIOT_CONFIG_* definitions upstream. Rather define configuration via Kconfig"
|
|
}
|
|
|
|
check_stderr_null() {
|
|
local patterns=()
|
|
local pathspec=()
|
|
|
|
patterns+=(-e '2>[[:blank:]]*&1[[:blank:]]*>[[:blank:]]*/dev/null')
|
|
|
|
pathspec+=('Makefile*')
|
|
pathspec+=('**/Makefile*')
|
|
pathspec+=('**/*.mk')
|
|
git -C "${RIOTBASE}" grep -n "${patterns[@]}" -- "${pathspec[@]}" \
|
|
| error_with_message "Redirecting stderr and stdout to /dev/null is \`>/dev/null 2>&1\`; the other way round puts the old stderr to the new stdout."
|
|
}
|
|
|
|
# Test application directories that starts by the following strings are invalid
|
|
# and should moved to the corresponding tests subdirectory.
|
|
FORBIDDEN_TEST_DIRS=()
|
|
FORBIDDEN_TEST_DIRS+=('build_system')
|
|
FORBIDDEN_TEST_DIRS+=('core') # => move under tests/core
|
|
FORBIDDEN_TEST_DIRS+=('cpu') # => move under tests/cpu
|
|
FORBIDDEN_TEST_DIRS+=('driver') # => move under tests/drivers
|
|
FORBIDDEN_TEST_DIRS+=('gnrc') # => move under tests/net
|
|
FORBIDDEN_TEST_DIRS+=('periph') # => move under tests/periph
|
|
FORBIDDEN_TEST_DIRS+=('net') # => move under tests/net
|
|
FORBIDDEN_TEST_DIRS+=('pkg') # => move under tests/pkg
|
|
FORBIDDEN_TEST_DIRS+=('sys') # => move under tests/sys
|
|
FORBIDDEN_TEST_DIRS+=('vfs') # => move under tests/sys
|
|
FORBIDDEN_TEST_DIRS+=('xtimer') # => move under tests/sys
|
|
FORBIDDEN_TEST_DIRS+=('ztimer') # => move under tests/sys
|
|
|
|
check_tests_application_path() {
|
|
local patterns=()
|
|
patterns+=(-regex "^tests/bench_.*/Makefile")
|
|
for forbidden in "${FORBIDDEN_TEST_DIRS[@]}"; do
|
|
patterns+=(-o -regex "^tests/${forbidden}_.*/Makefile")
|
|
done
|
|
|
|
find tests/ -type f "${patterns[@]}" | error_with_message "Invalid application path in tests/"
|
|
}
|
|
|
|
check_pinned_docker_version_is_up_to_date() {
|
|
local pinned_digest
|
|
local pinned_repo_digest
|
|
local upstream_digest
|
|
local upstream_repo_digest
|
|
pinned_digest="$(awk '/^DOCKER_TESTED_IMAGE_ID := (.*)$/ { print substr($0, index($0, $3)); exit }' "$RIOTMAKE/docker.inc.mk")"
|
|
pinned_repo_digest="$(awk '/^DOCKER_TESTED_IMAGE_REPO_DIGEST := (.*)$/ { print substr($0, index($0, $3)); exit }' "$RIOTMAKE/docker.inc.mk")"
|
|
# not using docker and jq here but a python script to not have to install
|
|
# more stuff for the static test docker image
|
|
IFS=' ' read -r upstream_digest upstream_repo_digest <<< "$("$RIOTTOOLS/buildsystem_sanity_check/get_dockerhub_digests.py" "riot/riotbuild")"
|
|
|
|
if [ "$pinned_digest" != "$upstream_digest" ]; then
|
|
git -C "${RIOTBASE}" grep -n '^DOCKER_TESTED_IMAGE_ID :=' "$RIOTMAKE/docker.inc.mk" \
|
|
| error_with_message "Update docker image SHA256 to ${upstream_digest}"
|
|
fi
|
|
|
|
if [ "$pinned_repo_digest" != "$upstream_repo_digest" ]; then
|
|
git -C "${RIOTBASE}" grep -n '^DOCKER_TESTED_IMAGE_REPO_DIGEST :=' "$RIOTMAKE/docker.inc.mk" \
|
|
| error_with_message "Update manifest digest to ${upstream_repo_digest}"
|
|
fi
|
|
}
|
|
|
|
error_on_input() {
|
|
! grep ''
|
|
}
|
|
|
|
all_checks() {
|
|
check_not_parsing_features
|
|
check_providing_features_only_makefile_features
|
|
check_not_exporting_variables
|
|
check_deprecated_vars_patterns
|
|
check_board_do_not_include_cpu_features_dep
|
|
check_cpu_cpu_model_defined_in_makefile_features
|
|
check_not_setting_board_equal
|
|
check_board_insufficient_memory_not_in_makefile
|
|
checks_tests_application_not_defined_in_makefile
|
|
checks_develhelp_not_defined_via_cflags
|
|
check_files_in_boards_not_reference_board_var
|
|
check_no_pseudomodules_in_makefile_dep
|
|
check_no_usemodules_in_makefile_include
|
|
check_no_pkg_source_local
|
|
check_no_riot_config
|
|
check_stderr_null
|
|
check_tests_application_path
|
|
check_pinned_docker_version_is_up_to_date
|
|
}
|
|
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
github_annotate_setup
|
|
all_checks | error_on_input
|
|
result="$?"
|
|
github_annotate_teardown
|
|
exit "${result}"
|
|
fi
|