Skip to content
Open
1 change: 1 addition & 0 deletions .github/workflows/static-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
run: |
docker run --rm \
-e CI_BASE_BRANCH=master_upstream \
-e GITHUB_RUN_ID=${GITHUB_RUN_ID} \
-v $(pwd):/data/riotbuild \
riot/riotbuild:latest \
make static-test
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
ZZZZZZZZZZZ Z
ZZZZZ

The friendly Operating System for IoT!
The friendly Operating System for IoT!

RIOT is a real-time multi-threading operating system that supports a range of
devices that are typically found in the Internet of Things (IoT):
Expand Down
72 changes: 72 additions & 0 deletions dist/tools/ci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
CI specific scripts
===================

Static tests
------------

The [static_tests.sh] script runs all static tests and outputs them in a unified
output. You can also run this script by running `make static-test` in the base
directory.

To add a new static test, just write a `check.sh` script or call your static
checker directly and add it to the list of static tests in [static_tests.sh]:

```sh
ENV1=foobar ENV2=snafu run <your test command> --args
```

Github annotations
------------------
Using [github_annotate.sh] you can generate [Github annotations] for your
tests. You can generate both warnings and errors. Before doing anything however,
you include [github_annotate.sh]\ (assuming `${RIOTTOOLS is set to}` [dist/tools/])

```sh
. "${RIOTTOOLS}"/ci/github_annotate.sh
```

and set-up the mechanism

```sh
github_annotate_setup
```

If your tests generate output you now can pipe that to the file `${LOGFILE}` by
using `${LOG}`, e.g.

```sh
my_awesome_test | ${LOG}
```

Don't worry, your test will function normal still, if you don't run it in a
Github Action!

Now you can use `github_annotate_error` and `github_annotate_warning` to
generate the actual errors and warnings. Both commands expect 3 parameters:
1. `FILENAME`: The name of the file the warning or error occurred in,
2. `LINENUM`: The number of the line the warning or error occurred in, and
3. `DETAILS`: Some descriptive details or the message of your warning or error.

You can parse those from `${LOGFILE}` (e.g. using tools such as `grep`, `sed`,
or `awk`) or generate them on the fly, if your script allows for that. E.g.

```sh
cat ${LOGFILE} | grep '^.*:[0-9]\+:' | while read error; do
github_annotate_error \
$(echo "${error}" | cut -d: -f1) \
$(echo "${error}" | cut -d: -f2) \
$(echo "${error}" | cut -d: -f3-)
done
```

After all errors or warnings are annotated, call `github_annotate_teardown` to
finish annotations.

**Note:** `github_annotate_report_last_run` is called within [static_tests.sh]
to attach the actual annotations to your PR. You don't need to call it from
within your test if you are adding that test to [static_tests.sh].

[static_tests.sh]: ./static_tests.sh
[Github annotations]: https://github.blog/2018-12-14-introducing-check-runs-and-annotations/
[github_annotate.sh]: ./github_annotate.sh
[dist/tools]: ../
67 changes: 67 additions & 0 deletions dist/tools/ci/github_annotate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2020 Martine S. Lenders <m.lenders@fu-berlin.sh>
#
# 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.

LOG=cat
LOGFILE=
OUTFILE=github_annotate_outfile.log
ECHO_ESC=echo

if ps -p $$ | grep -q '\<bash\>'; then
# workaround when included in bash to escape newlines and carriage returns
# properly in _escape
ECHO_ESC='echo -e'
fi

github_annotate_setup() {
if [ -n "${GITHUB_RUN_ID}" ]; then
LOGFILE=run-${GITHUB_RUN_ID}.log
LOG="tee -a ${LOGFILE}"
fi
}

github_annotate_is_on() {
test -n "${LOGFILE}"
return $?
}

_escape() {
# see https://stackoverflow.com/a/1252191/11921757
${ECHO_ESC} "$1" | sed -e ':a' -e 'N' -e '$!ba' \
-e 's/%/%25/g' -e 's/\r/%0D/g' -e 's/\n/%0A/g'
}

github_annotate_error() {
if [ -n "${GITHUB_RUN_ID}" ]; then
FILENAME="${1}"
LINENUM="${2}"
DETAILS="$(_escape "${3}")"
echo "::error file=${FILENAME},line=${LINENUM}::${DETAILS}" >> ${OUTFILE}
fi
}

github_annotate_warning() {
if [ -n "${GITHUB_RUN_ID}" ]; then
FILENAME="${1}"
LINENUM="${2}"
DETAILS="$(_escape "${3}")"
echo "::warning file=${FILENAME},line=${LINENUM}::${DETAILS}" >> ${OUTFILE}
fi
}

github_annotate_teardown() {
if [ -n "${LOGFILE}" ]; then
rm -f ${LOGFILE}
LOGFILE=
fi
}

github_annotate_report_last_run() {
if [ -n "${GITHUB_RUN_ID}" -a -f "${OUTFILE}" ]; then
# de-duplicate errors
sort -u ${OUTFILE} >&2
fi
rm -f ${OUTFILE}
}
3 changes: 3 additions & 0 deletions dist/tools/ci/static_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# directory for more details.
#

. $(dirname "$0")/github_annotate.sh

function print_result {
local RED="\033[0;31m"
local GREEN="\033[0;32m"
Expand Down Expand Up @@ -47,6 +49,7 @@ function run {
(printf "%s\n" "$OUT" | while IFS= read -r line; do printf "\t%s\n" "$line"; done)
echo ""
fi
github_annotate_report_last_run
}

RESULT=0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@
MAKE = os.environ.get('MAKE', 'make')





class ErrorInTest(Exception):
"""Custom exception for a failed test.

Expand Down
16 changes: 15 additions & 1 deletion dist/tools/flake8/check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
. "$(dirname "$0")/../ci/github_annotate.sh"
github_annotate_setup

FLAKE8_CMD="python3 -m flake8"

Expand Down Expand Up @@ -43,7 +45,19 @@ ${FLAKE8_CMD} --version &> /dev/null || {
exit 1
}

ERRORS=$(${FLAKE8_CMD} --config="${RIOTTOOLS}"/flake8/flake8.cfg ${FILES})
ERRORS=$(${FLAKE8_CMD} --config="${RIOTTOOLS}"/flake8/flake8.cfg ${FILES} | ${LOG})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I would just use the ERRORS variable instead of indirecting via LOG, as I did in the doccheck


if github_annotate_is_on; then
grep "^.\+:[0-9]\+:" "${LOGFILE}" | while read line; do
FILENAME=$(echo "${line}" | cut -d: -f1)
LINENR=$(echo "${line}" | cut -d: -f2)
DETAILS=$(echo "${line}" | cut -d: -f3- |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the output of the test annotation: I think -f3 is the column (which sadly, as far as my trials could gather, can't be annotated with github_annotate_error). Rather do

Suggested change
DETAILS=$(echo "${line}" | cut -d: -f3- |
DETAILS=$(echo "${line}" | cut -d: -f4- |

sed -e 's/^[ \t]*//' -e 's/[ \t]*$//')
github_annotate_error "${FILENAME}" "${LINENR}" "${DETAILS}"
done
fi

github_annotate_teardown

if [ -n "${ERRORS}" ]
then
Expand Down
26 changes: 23 additions & 3 deletions dist/tools/whitespacecheck/check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.

. "$(dirname "$0")/../ci/github_annotate.sh"

IGNORE=$(awk '{ printf ":!%s ", $0 }' "$(dirname "$0")/ignore_list.txt")

# If no branch but an option is given, unset BRANCH.
Expand All @@ -23,28 +25,46 @@ else
fi
fi

# sets
# - LOG to tee output into for later parsing
# - LOGFILE to parse GitHub annotations into
github_annotate_setup

# select files to check
if [ -z "${BRANCH}" ]; then
BRANCH=$(git rev-list HEAD | tail -n 1)
fi

git -c core.whitespace="tab-in-indent,tabwidth=4" \
diff --check "$(git merge-base "${BRANCH}" HEAD)" -- *.[ch] ${IGNORE}

diff --check "$(git merge-base "${BRANCH}" HEAD)" -- *.[ch] ${IGNORE} \
| ${LOG}
RESULT=$?

# Git regards any trailing white space except `\n` as an error so `\r` is
# checked here, too
git -c core.whitespace="trailing-space" \
diff --check "$(git merge-base "${BRANCH}" HEAD)" -- . ${IGNORE}
diff --check "$(git merge-base "${BRANCH}" HEAD)" -- . ${IGNORE} \
| ${LOG}

TRAILING_RESULT=$?

if github_annotate_is_on; then
grep "^.\+:[0-9]\+:" "${LOGFILE}" | while read line; do
FILENAME=$(echo "${line}" | cut -d: -f1)
LINENR=$(echo "${line}" | cut -d: -f2)
DETAILS=$(echo "${line}" | cut -d: -f3- |
sed -e 's/^[ \t]*//' -e 's/[ \t]*$//')
github_annotate_error "${FILENAME}" "${LINENR}" "${DETAILS}"
done
fi

github_annotate_teardown

if [ ${TRAILING_RESULT} -ne 0 ] || [ ${RESULT} -ne 0 ]
then
echo "ERROR: This change introduces new whitespace errors"
exit 1
else
exit 0
fi