aboutsummaryrefslogtreecommitdiff
path: root/hooks
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2020-02-05 21:18:18 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2020-02-06 13:51:59 +0300
commit754099b7218056a24d77aea0278bb3bc2c7a9716 (patch)
tree56ae541e000ebbb713a60e15465ce44eac01c274 /hooks
parent9ecee2a02b69c867962688f859cea4c8a7c28796 (diff)
Add pre-commit-copyright-check git hook
Diffstat (limited to 'hooks')
-rwxr-xr-xhooks/pre-commit26
-rwxr-xr-xhooks/pre-commit-copyright-check70
2 files changed, 96 insertions, 0 deletions
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