spdx-headers.sh changed into `git rev-parse --show-toplevel` before stamping. Run from a copy of the repository that has no .git of its own, such as a git archive export under the working tree, git names the enclosing checkout, so the copy stamped the checkout's tracked files instead of its own. The script now takes as its root the directory above its own scripts/ directory. When git does not name that directory as the top of a checkout, it prints a refusal on stderr and exits 2 before it reads any file. Run from its own checkout it behaves as before, which is how `make spdx-headers` and `make sqlc-generate` call it. TestSPDXHeadersStampsOnlyItsOwnCheckout builds a scratch git checkout with one tracked Go file and, under it, an export holding the same files without a .git. Run from the export, the script must exit 2 and leave both Go files unstamped; run from the checkout's own copy, it must stamp the checkout's file and not the export's. At the parent the export case fails: the script exits 0 and stamps the checkout's a.go. The checkout case passes on both sides. Run in the working tree, the new script stamped 0 of 934 eligible files and changed no path. go vet, gofmt, bash -n and make lint pass.
122 lines
4.5 KiB
Bash
Executable File
122 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Stamp SPDX license headers on hand-written source files.
|
|
#
|
|
# member-console is dual-licensed: AGPL-3.0-only for everyone, or a separate
|
|
# commercial license from the copyright holder (see COMMERCIAL.md). Every
|
|
# hand-written source file carries the dual identifier so the offer is legible
|
|
# from the file itself, not only from the repository root.
|
|
#
|
|
# Covered: Go, SQL migrations and seeds, the Go HTML templates under
|
|
# internal/, and the first-party JavaScript and CSS under internal/. Not
|
|
# covered: sqlc query files (sqlc copies every comment preceding the first
|
|
# "-- name:" line into the generated Go as that query's doc comment, so a
|
|
# header there pollutes the generated code; the generated .sql.go beside each
|
|
# query file carries the header instead), the vendored browser assets listed
|
|
# below (their own licenses, see NOTICE), files under a testdata directory
|
|
# (tests read them byte for byte), configuration, shell, documentation,
|
|
# images. Repository-wide coverage of those, and a check that fails on a bare
|
|
# new file, is what REUSE tooling provides; adopting it is deferred until CI
|
|
# exists (forge issue #111).
|
|
#
|
|
# sqlc rewrites its output on every run and has no option for emitting a
|
|
# header, so `make sqlc-generate` invokes this script afterwards to restore the
|
|
# headers it drops. Run `make spdx-headers` to stamp the whole tree.
|
|
#
|
|
# Usage:
|
|
# scripts/spdx-headers.sh # every tracked eligible file
|
|
# scripts/spdx-headers.sh DIR [DIR..] # every eligible file on disk under
|
|
# # DIR, including files not yet tracked
|
|
#
|
|
# Idempotent: a file whose first lines already carry an SPDX-License-Identifier
|
|
# is left untouched, so a changed identifier must be rewritten deliberately.
|
|
#
|
|
# Templates get the {{- /* */ -}} form: an HTML comment would be sent to every
|
|
# browser, and the trim markers keep the rendered output byte-identical.
|
|
|
|
set -euo pipefail
|
|
|
|
IDENTIFIER="AGPL-3.0-only OR LicenseRef-Commercial"
|
|
COPYRIGHT="2025-2026 Christian Galo"
|
|
|
|
# Third-party assets redistributed under their own licenses; see NOTICE.
|
|
VENDORED=(
|
|
internal/embeds/static/bootstrap.bundle.js
|
|
internal/embeds/static/bootstrap.css
|
|
internal/embeds/static/htmx.min.js
|
|
internal/embeds/static/sortable.min.js
|
|
)
|
|
|
|
# The tree to stamp is the checkout this script belongs to. Inside a copy of
|
|
# the repository that has no .git of its own, such as an export under the
|
|
# working tree, git would name the enclosing checkout instead, so the script
|
|
# refuses rather than stamp files the caller did not point it at.
|
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
|
top="$(git -C "$root" rev-parse --show-toplevel 2>/dev/null || true)"
|
|
if [ "$top" != "$root" ]; then
|
|
echo "spdx-headers: $root is not the top of a git checkout; run the copy of this script inside the checkout to stamp" >&2
|
|
exit 2
|
|
fi
|
|
cd "$root"
|
|
|
|
# Go and SQL are eligible anywhere; templates and assets only under internal/,
|
|
# which keeps archived review pages and exploration dossiers out.
|
|
eligible() {
|
|
local f="$1"
|
|
for v in "${VENDORED[@]}"; do
|
|
[ "$f" = "$v" ] && return 1
|
|
done
|
|
case "$f" in
|
|
*/testdata/*) return 1 ;;
|
|
*/queries/*.sql) return 1 ;;
|
|
*.go | *.sql) return 0 ;;
|
|
internal/*.html | internal/*.js | internal/*.css) return 0 ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
header() {
|
|
case "$1" in
|
|
*.go | *.js)
|
|
printf '// SPDX-License-Identifier: %s\n// SPDX-FileCopyrightText: %s\n\n' "$IDENTIFIER" "$COPYRIGHT"
|
|
;;
|
|
*.sql)
|
|
printf -- '-- SPDX-License-Identifier: %s\n-- SPDX-FileCopyrightText: %s\n\n' "$IDENTIFIER" "$COPYRIGHT"
|
|
;;
|
|
*.css)
|
|
printf '/* SPDX-License-Identifier: %s */\n/* SPDX-FileCopyrightText: %s */\n\n' "$IDENTIFIER" "$COPYRIGHT"
|
|
;;
|
|
*.html)
|
|
printf '{{- /* SPDX-License-Identifier: %s */ -}}\n{{- /* SPDX-FileCopyrightText: %s */ -}}\n\n' "$IDENTIFIER" "$COPYRIGHT"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
if [ "$#" -gt 0 ]; then
|
|
mapfile -t candidates < <(find "$@" -type f \( -name '*.go' -o -name '*.sql' -o -name '*.html' -o -name '*.js' -o -name '*.css' \) | sed 's#^\./##' | sort)
|
|
else
|
|
mapfile -t candidates < <(git ls-files -- '*.go' '*.sql' 'internal/*.html' 'internal/*.js' 'internal/*.css')
|
|
fi
|
|
|
|
stamped=0
|
|
eligible_count=0
|
|
for f in "${candidates[@]}"; do
|
|
[ -n "$f" ] || continue
|
|
eligible "$f" || continue
|
|
eligible_count=$((eligible_count + 1))
|
|
if head -n 3 "$f" | grep -q 'SPDX-License-Identifier:'; then
|
|
continue
|
|
fi
|
|
tmp="$(mktemp)"
|
|
{
|
|
header "$f"
|
|
cat "$f"
|
|
} >"$tmp"
|
|
# Copy through rather than mv so the file keeps its original mode.
|
|
cat "$tmp" >"$f"
|
|
rm -f "$tmp"
|
|
stamped=$((stamped + 1))
|
|
done
|
|
|
|
printf 'spdx-headers: stamped %d of %d eligible files\n' "$stamped" "$eligible_count"
|