99 lines
2.4 KiB
Bash
Executable File
99 lines
2.4 KiB
Bash
Executable File
#!/bin/sh
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
# Copyright (C) 2026 David (Corey) Herrera
|
|
#
|
|
# Verify every source file ADDED in a range carries the SPDX pair and the file
|
|
# header block. See docs/coding-best-practices.md.
|
|
#
|
|
# scripts/check-headers.sh [range] # default: origin/main..HEAD
|
|
#
|
|
# Only files the range ADDS are checked. Files that already exist are left
|
|
# alone deliberately: the rule is that everyone submitting code stays in
|
|
# compliance, not that the whole tree gets retrofitted.
|
|
#
|
|
# Exempt: tests, generated sources, and files carrying upstream third-party
|
|
# attribution (those keep their own header).
|
|
#
|
|
# Run it locally before opening a pull request; CI runs the same script.
|
|
|
|
set -eu
|
|
|
|
cd "$(git rev-parse --show-toplevel)"
|
|
|
|
RANGE="${1:-${BASE_REF:-origin/main}..HEAD}"
|
|
|
|
files=$(git diff --diff-filter=A --name-only "$RANGE" -- \
|
|
'*.c' '*.h' '*.cu' '*.cuh' '*.m')
|
|
|
|
if [ -z "$files" ]; then
|
|
echo "check-headers: ok (no source files added)"
|
|
exit 0
|
|
fi
|
|
|
|
fail=0
|
|
|
|
note() {
|
|
echo "check-headers: $1" >&2
|
|
echo " $2" >&2
|
|
fail=$((fail + 1))
|
|
}
|
|
|
|
OLDIFS=$IFS
|
|
IFS='
|
|
'
|
|
for f in $files; do
|
|
IFS=$OLDIFS
|
|
|
|
# Added and then removed again within the range.
|
|
[ -f "$f" ] || continue
|
|
|
|
case "$f" in
|
|
tests/*|*/tests/*) continue ;;
|
|
*_ptx.h|*_ptx.cuh) continue ;;
|
|
esac
|
|
|
|
# Third-party-derived files keep their upstream attribution.
|
|
if head -5 "$f" | grep -qE 'SPDX-FileCopyrightText|Apache-2\.0'; then
|
|
continue
|
|
fi
|
|
|
|
if ! head -3 "$f" | grep -q 'SPDX-License-Identifier'; then
|
|
note "$f: missing the SPDX identifier" \
|
|
"add: /* SPDX-License-Identifier: AGPL-3.0-or-later */"
|
|
continue
|
|
fi
|
|
|
|
if ! head -16 "$f" | grep -q '@file'; then
|
|
note "$f: missing the @file header block" \
|
|
"run: ./scripts/add-file-headers.sh --apply $f"
|
|
continue
|
|
fi
|
|
|
|
brief=$(head -16 "$f" | sed -n 's|.*@brief[[:space:]]*||p' | head -1)
|
|
case "$brief" in
|
|
'')
|
|
note "$f: @brief is empty" \
|
|
"one line saying what this file is for"
|
|
;;
|
|
TODO*|todo*)
|
|
note "$f: @brief is still TODO" \
|
|
"replace it with one line saying what this file is for"
|
|
;;
|
|
esac
|
|
|
|
for tag in @status @issues @todo; do
|
|
if ! head -16 "$f" | grep -q -- "$tag"; then
|
|
note "$f: header block is missing $tag" \
|
|
"all three of @status/@issues/@todo are present, 'None' when empty"
|
|
fi
|
|
done
|
|
done
|
|
IFS=$OLDIFS
|
|
|
|
if [ "$fail" -gt 0 ]; then
|
|
echo "check-headers: $fail problem(s) — see docs/coding-best-practices.md" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "check-headers: ok"
|