aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cheatsheet.txt8
-rwxr-xr-xhooks/pre-commit26
-rwxr-xr-xhooks/pre-commit-copyright-check70
3 files changed, 104 insertions, 0 deletions
diff --git a/cheatsheet.txt b/cheatsheet.txt
index 42efbcd..8e18dd1 100644
--- a/cheatsheet.txt
+++ b/cheatsheet.txt
@@ -14,6 +14,14 @@ Global Setup
git config --global remote.origin.fetch '+refs/tags/*:refs/tags/*'
git config --global --unset remote.origin.tagopt
+ # Enable hooks globally.
+ #
+ git config --global core.hooksPath <git-project-dir>/hooks
+
+ # Override the global hooks with the repository-specific hooks (run in a
+ # repository directory).
+ #
+ git config core.hooksPath .git/hooks
Undo (move to index) last commit
diff --git a/hooks/pre-commit b/hooks/pre-commit
new file mode 100755
index 0000000..10a97d9
--- /dev/null
+++ b/hooks/pre-commit
@@ -0,0 +1,26 @@
+#! /usr/bin/env bash
+
+# Execute various pre-commit scripts in a git repository.
+#
+# To enable the hooks globally run:
+#
+# $ git config --global core.hooksPath <git-project-dir>/hooks
+#
+# Notes:
+#
+# - git passes no parameters to this kind of hooks.
+#
+# - git changes CWD to the git repository root directory for the hook process.
+#
+# - git command running from inside the hook sees files that should be
+# auto-staged due to the -a git-commit option or similar as already staged.
+#
+trap 'exit 1' ERR
+
+src_exe="$(realpath "${BASH_SOURCE[0]}")"
+src_dir="$(dirname "$src_exe")"
+
+# Run each hook checking the exit status and bailing out if unsuccessful. We
+# can just exec the last one.
+#
+exec "$src_dir/pre-commit-copyright-check"
diff --git a/hooks/pre-commit-copyright-check b/hooks/pre-commit-copyright-check
new file mode 100755
index 0000000..1bdeffd
--- /dev/null
+++ b/hooks/pre-commit-copyright-check
@@ -0,0 +1,70 @@
+#! /usr/bin/env bash
+
+# Check copyright notices in the COPYRIGHT and LICENSE files and issue a
+# warning if they don't include the current year.
+#
+# Specifically, look first for COPYRIGHT and then LICENSE in the root
+# directory and all subdirectories in a project.
+#
+# Then in each file look for the first line matching the:
+#
+# ^Copyright (\([cC]\))? ...
+#
+# Regex, where "..." matches various year lists/ranges (e.g., "2010", "2010,
+# 2011", "2010-2011", and their combinations; see the pattern below for
+# details). Specifically, we don't consider Copyright notices that:
+#
+# - don't start at the very beginning of a line (indented, etc)
+# - contain something other than years prior to the last year (names, etc)
+# - wrap over multiple lines (long year list, etc)
+#
+# Note also that the current year is obtained in the UTC timezone.
+#
+trap 'exit 1' ERR
+set -o errtrace # Trap in functions.
+
+function info () { echo "$*" 1>&2; }
+function error () { info "$*"; exit 1; }
+
+# Recursively collect the COPYRIGHT and LICENSE files, skipping the LICENSE
+# files in directories that contain the COPYRIGHT file.
+#
+# @@ Note that for now we assume that there are no spaces in the project file
+# and directory names.
+#
+files=()
+
+fs=($(find . \( -type f -o -type l \) -name COPYRIGHT))
+
+for f in "${fs[@]}"; do
+ files+=("$f")
+done
+
+fs=($(find . \( -type f -o -type l \) -name LICENSE))
+
+for f in "${fs[@]}"; do
+ d="$(dirname "$f")"
+
+ if [ ! -f "$d/COPYRIGHT" ]; then
+ files+=("$f")
+ fi
+done
+
+# Grep for the Copyright notice in the collected files and issue the warning
+# if it is present and is outdated.
+#
+# @@ We should probably skip the COPYRIGHT/LICENSE files whose parent
+# directories don't (recursively) contain staged files (think of projects
+# with multiple packages, bundled third-party code, etc). Note that we can
+# obtain the staged file list with the `git diff --name-only --cached`
+# command.
+#
+current_year="$(date -u +'%Y')"
+
+for f in "${files[@]}"; do
+ year="$(sed -n -re 's%^Copyright( +\([cC]\))?[ 0-9,-]*[ ,-]([0-9]{4}).*$%\2%p' "$f" | head -n 1)"
+
+ if [ -n "$year" -a "$year" != "$current_year" ]; then
+ info "WARNING: last copyright year in '${f#./}' is $year"
+ fi
+done