From 7f5f1cd225a456cfd5a11840f1beca40bd77de2e Mon Sep 17 00:00:00 2001 From: Tianyi Gao Date: Wed, 28 Oct 2026 08:51:39 +0000 Subject: [PATCH] Add a stripped build and checkpatch to CI * Build homa.ko with __STRIP__=1 and run the unit tests on it, with the same kernel as the normal build, so that a change that breaks stripping shows at once. * Run checkpatch on the change of each pull request and push, as the netdev patch checks do (.github/scripts/checkpatch.sh): once on the module sources as they are, once on the files that go upstream after util/strip.py. Only errors fail; warnings and checks show as annotations. --- .github/scripts/checkpatch.sh | 96 +++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 30 ++++++++++- 2 files changed, 125 insertions(+), 1 deletion(-) create mode 100755 .github/scripts/checkpatch.sh diff --git a/.github/scripts/checkpatch.sh b/.github/scripts/checkpatch.sh new file mode 100755 index 00000000..cf3187cf --- /dev/null +++ b/.github/scripts/checkpatch.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0+ + +# Usage: .github/scripts/checkpatch.sh [stripped] +# +# Run checkpatch on the change from commit to the working tree, in the +# same way as the netdev patch checks (NIPA). is a Linux source tree; +# its scripts/checkpatch.pl is used. Run this from the top of the repository. +# +# Without "stripped", check the module sources as they are (CHECK_SRCS in the +# Makefile, as "make checkpatch"). With "stripped", check the files that go +# upstream, after util/strip.py (as "make checkpatch-net-next"). util/ and +# test/ are not checked. The main branch has checkpatch findings of its own, +# so only the change is checked. +# +# The exit status is 1 if checkpatch reports an error, and 0 otherwise: +# warnings and checks do not fail, as in NIPA. + +set -e + +if [ $# -lt 2 ] || [ $# -gt 3 ] || [ "${3:-stripped}" != stripped ]; then + echo "Usage: $0 [stripped]" >&2 + exit 2 +fi +base=$1 +linux=$2 +stripped=$3 +work=$(mktemp -d) +trap 'rm -rf $work' EXIT + +# Put into directory $2 the code of tree $1 that checkpatch must see. +prepare_tree() { + local tree=$1 out=$2 srcs + + if [ -n "$stripped" ]; then + # "make net-next" writes the stripped files into a Linux source + # tree: the module into net/homa and homa.h into + # include/uapi/linux. + mkdir -p $out/net $out/include/uapi/linux + make -s -C $tree net-next LINUX_SRC_DIR=$out HOMA_TARGET=$out/net/homa + else + # "make print-CHECK_SRCS" prints "CHECK_SRCS = ". + srcs=$(make -s -C $tree print-CHECK_SRCS | sed 's/^CHECK_SRCS = //') + mkdir -p $out + (cd $tree && cp $srcs $out/) + fi +} + +# Check the diff in file $1 with the options of NIPA +# (tests/patch/checkpatch/checkpatch.sh). The diff is not in a Linux tree and +# has no commit message: hence --no-tree, --no-signoff and COMMIT_MESSAGE, and +# NIPA's ignored types for commit messages are left out. +run_checkpatch() { + local diff=$1 result=$work/checkpatch.out + + # checkpatch exits with 1 for warnings and checks too, so its exit + # status is not used; the result is read below. + $linux/scripts/checkpatch.pl --strict --codespell --max-line-length=80 \ + --no-tree --no-signoff --color=never \ + --ignore=COMMIT_MESSAGE,MACRO_ARG_REUSE,ALLOC_SIZEOF_STRUCT,CAMELCASE,FILE_PATH_CHANGES \ + $diff > $result || true + + # In GitHub Actions, a line that starts with "::warning::" shows as an + # annotation, so add it to warnings and checks there. + if [ -n "$GITHUB_ACTIONS" ]; then + sed -E 's/^(WARNING|CHECK):/::warning::&/' $result + else + cat $result + fi + + if grep -q '^ERROR:' $result; then + echo "checkpatch found errors." + return 1 + fi +} + +# Prepare this tree first, so that a util/strip.py failure always shows. +prepare_tree . $work/head + +if ! git cat-file -e "$base^{commit}" 2>/dev/null; then + echo "Base commit '$base' is not in this repository: checkpatch skipped." + exit 0 +fi +mkdir $work/base-src +git archive $base | tar -x -C $work/base-src +prepare_tree $work/base-src $work/base + +cd $work +# diff exits with 1 when the trees differ, which is the normal case. +diff -ruN base head > change.diff || true +if [ ! -s change.diff ]; then + echo "The change does not touch checked code: checkpatch skipped." + exit 0 +fi +run_checkpatch change.diff diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6efd5b4a..68c68056 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,11 +8,15 @@ jobs: runs-on: ubuntu-24.04 env: LINUX_VERSION: 6.17.8 + # The base for checkpatch: a pull request's base, or the branch tip before a push. + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} steps: - uses: actions/checkout@v5 + with: + fetch-depth: 0 # the strip check needs a pull request's base - name: Install kernel build dependencies - run: sudo apt-get update && sudo apt-get install -y flex bison bc libelf-dev libssl-dev + run: sudo apt-get update && sudo apt-get install -y flex bison bc libelf-dev libssl-dev codespell # The unit tests compile against kernel headers, which need a # configured tree; modules_prepare is enough, no vmlinux. @@ -42,3 +46,27 @@ jobs: - name: Unit tests (IPv4) if: ${{ !cancelled() }} run: cd test && ./unit --ipv4 + + # The stripped version (__STRIP__=1), with the same kernel. + - name: Build homa.ko (stripped) + if: ${{ !cancelled() }} + run: make KBUILD_MODPOST_WARN=1 __STRIP__=1 + + # Clean first: both versions of the unit tests use the same object files. + - name: Unit tests, stripped (IPv6) + if: ${{ !cancelled() }} + run: make -C test clean && make -C test -j$(nproc) __STRIP__=1 unit && cd test && ./unit + + - name: Unit tests, stripped (IPv4) + if: ${{ !cancelled() }} + run: cd test && ./unit --ipv4 + + # checkpatch the change of a pull request or push (see the script): + # the module sources as they are, then the files that go upstream. + - name: checkpatch + if: ${{ !cancelled() }} + run: .github/scripts/checkpatch.sh "$BASE_SHA" $KDIR + + - name: checkpatch (stripped) + if: ${{ !cancelled() }} + run: .github/scripts/checkpatch.sh "$BASE_SHA" $KDIR stripped