Files
qdl/scripts/checkpatch_wrapper.sh
T
Igor Opaniuk d3d806cbe3 checkpatch: Run per-commit range checks locally and in CI
Until now checkpatch had two divergent code paths: the local meson
'check' target ran 'checkpatch.pl --no-tree -f' against every tracked
source file, while the CI workflow used the webispy/checkpatch-action
action, which runs checkpatch in patch mode against each commit in the
PR. The two modes report different defects -- in particular, file mode
flags style issues in long-untouched code and skips commit-log checks,
while patch mode validates the commit message (Signed-off-by, subject
length, ...) and only inspects added/changed lines. Contributors could
end up with a green local 'check' but a red CI run, and vice versa.

Introduce a 'check-range' mode in scripts/checkpatch_wrapper.sh that
mirrors what the GitHub Action does: iterate over every commit in
CHECKPATCH_BASE..CHECKPATCH_HEAD (defaulting to origin/master..HEAD),
feed each commit through 'git format-patch -1 --stdout' and pipe the
result into checkpatch.pl. All commits are processed even on failure
so the user sees every offending commit in one go.

Expose the new mode as a meson run_target ('meson compile check-range
-C build') and switch the CI workflow to invoke the wrapper directly
with the PR base/head SHAs, so local and CI invocations exercise the
exact same code path. Document the new target in README under the
Contributing section.

Signed-off-by: Igor Opaniuk <igor.opaniuk@oss.qualcomm.com>
2026-05-04 21:25:07 -05:00

96 lines
2.5 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
set -euo pipefail
ROOT_URL="https://raw.githubusercontent.com/torvalds/linux/v6.15/scripts"
CHECKPATCH_URL="${ROOT_URL}/checkpatch.pl"
SPELLING_URL="${ROOT_URL}/spelling.txt"
ROOT_PATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )/../"
CHECKPATCH_DIR="${ROOT_PATH}/.scripts"
CHECKPATCH="${CHECKPATCH_DIR}/checkpatch.pl"
SPELLING="${CHECKPATCH_DIR}/spelling.txt"
# Just to repo root to work consistently from anywhere
cd "$ROOT_PATH"
# List only tracked source files (not ignored/untracked)
CHECKPATCH_SOURCES=$(git ls-files | grep -E '\.(c|h|sh)$' | \
grep -vE '(^|/)sha2\.(c|h)$' | \
grep -vE 'version\.h$' | \
grep -vE 'list\.h$'
)
ensure_checkpatch() {
if [[ ! -x "$CHECKPATCH" ]]; then
echo "Downloading checkpatch.pl and spelling.txt..."
mkdir -p "$CHECKPATCH_DIR"
curl -sSfL "$CHECKPATCH_URL" -o "$CHECKPATCH"
curl -sSfL "$SPELLING_URL" -o "$SPELLING"
chmod +x "$CHECKPATCH"
fi
}
do_check_all() {
ensure_checkpatch
echo "Running checkpatch on tracked source files (excluding sha2.c, sha2.h)..."
for file in ${CHECKPATCH_SOURCES}; do
perl "${CHECKPATCH}" --no-tree -f "$file" || exit 1
done
}
do_check_cached() {
ensure_checkpatch
echo "Running checkpatch on staged changes..."
git diff --cached -- . | perl "$CHECKPATCH" --no-tree -
}
do_check_range() {
ensure_checkpatch
local base="${CHECKPATCH_BASE:-origin/master}"
local head="${CHECKPATCH_HEAD:-HEAD}"
if ! git rev-parse --verify "${base}" >/dev/null 2>&1; then
echo "Base ref '${base}' is not available." >&2
echo "Set CHECKPATCH_BASE to a fetched ref (e.g. origin/master)." >&2
exit 1
fi
local commits
commits=$(git rev-list --reverse "${base}..${head}")
if [[ -z "${commits}" ]]; then
echo "No commits in range ${base}..${head}; nothing to check."
return 0
fi
echo "Running checkpatch on commits in range ${base}..${head}..."
local fail=0
for commit in ${commits}; do
echo
echo "--- Checking commit ${commit} ---"
if ! git format-patch -1 --stdout "${commit}" | perl "${CHECKPATCH}" --no-tree -; then
fail=1
fi
done
return $fail
}
usage() {
echo "Usage: $0 {download-checkpatch|check|check-cached|check-range}"
echo
echo " check-range Run checkpatch per-commit on the range"
echo " \$CHECKPATCH_BASE..\$CHECKPATCH_HEAD"
echo " (defaults: origin/master..HEAD)"
exit 2
}
case "${1:-}" in
download) ensure_checkpatch ;;
check) do_check_all ;;
check-cached) do_check_cached ;;
check-range) do_check_range ;;
*) usage ;;
esac