Skip to content

Commit 25b64fd

Browse files
Git hook to prevent unformatted code from being committed (#3502)
* Git hook to prevent unformatted code from being committed * Hook must be activated by running `git config core.hooksPath scripts/githooks` from repo root (this is now automatically done in the `setup_software` script) * [pre-commit.ci lite] apply automatic fixes * Re-add requirements_lock.txt * Use pre-push hook instead of pre-commit hook * Add explanatory comments in bash scripts * Add mac support for pre-commit hook --------- Co-authored-by: Apeiros-46B <Apeiros-46B@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 85838af commit 25b64fd

5 files changed

Lines changed: 74 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ src/config
150150
# codespell dictionary
151151
scripts/dictionary/
152152

153+
# marker files for pre-commit and pre-push hooks to check if staged files have been formatted
154+
scripts/.format_markers/
155+
153156
# clangd for nvim lsp
154157
src/.clangd
155158

environment_setup/setup_software.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
CURR_DIR=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
1919
cd "$CURR_DIR" || exit
2020

21+
git config core.hooksPath "$CURR_DIR/../scripts/githooks"
22+
2123
source util.sh
2224

2325
g_arch=$(uname -m) # Global variable. No function should use this name.

scripts/githooks/pre-commit

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/sh
2+
3+
# From the list of files on stdin (separated by newline), return formattable files to stdout
4+
filter_formattable_files() {
5+
grep -E '\.(h|cpp|c|cc|hpp|tpp|proto|py|md|yml)$|/BUILD$'
6+
}
7+
8+
# Output the modification time of a file (or 0 if nonexistent)
9+
get_mtime() {
10+
case "$(uname -s)" in
11+
Darwin*)
12+
stat -f %m "$1" 2> /dev/null || echo 0
13+
;;
14+
*)
15+
# No one will run this on BSD or other Unixes, so this should be fine
16+
stat -c %Y "$1" 2> /dev/null || echo 0
17+
;;
18+
esac
19+
}
20+
21+
# Find repo root, marker for the current branch, and marker mtime (0 if marker does not exist)
22+
toplevel="$(git rev-parse --show-toplevel)"
23+
marker="$toplevel/scripts/.format_markers/$(git rev-parse --abbrev-ref HEAD)"
24+
mtime=$(get_mtime "$marker")
25+
26+
git diff --staged --name-only | filter_formattable_files | while read -r file; do
27+
# Compare marker mtime with file mtime
28+
if [ $mtime -lt $(get_mtime "$toplevel/$file") ]; then
29+
# The file was modified AFTER formatting. Remove the marker to tell the pre-push hook
30+
# that this commit introduces unformatted code.
31+
rm -f "$marker" 2> /dev/null
32+
echo "Warning: Code is unformatted."
33+
break
34+
fi
35+
done

scripts/githooks/pre-push

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
3+
# Prompt user for confirmation at a [y/N] prompt and return 0 when user responds "yes" or "y"
4+
confirm() {
5+
read -r -p "$1 [y/N] " response < /dev/tty
6+
case "$response" in
7+
[yY][eE][sS]|[yY])
8+
return 0
9+
;;
10+
*)
11+
return 1
12+
;;
13+
esac
14+
}
15+
16+
scriptsdir="$(git rev-parse --show-toplevel)/scripts"
17+
18+
# If marker for current branch does not exist
19+
if ! [ -f "$scriptsdir/.format_markers/$(git rev-parse --abbrev-ref HEAD)" ]; then
20+
echo "Warning: Code is unformatted. Please run $scriptsdir/lint_and_format.sh."
21+
if confirm 'Continue without formatting?'; then
22+
echo "Continuing push anyway."
23+
exit 0
24+
else
25+
echo "Aborting push."
26+
exit 1
27+
fi
28+
fi

scripts/lint_and_format.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,10 @@ run_eof_new_line
149149
run_git_diff_check
150150
run_ansible_lint
151151

152+
# Update markers, telling Git hooks that formatting has been done
153+
# (Per-branch, so switching branches doesn't confuse the hooks)
154+
branch="$(git rev-parse --abbrev-ref HEAD)"
155+
mkdir -p "$CURR_DIR/.format_markers/$(dirname "$branch")"
156+
touch "$CURR_DIR/.format_markers/${branch}"
157+
152158
exit 0

0 commit comments

Comments
 (0)