/ misc / git-hooks / pre-commit
pre-commit
  1  #!/usr/bin/env bash
  2  
  3  set -euo pipefail
  4  
  5  set +e
  6  git diff-files --quiet
  7  is_unclean=$?
  8  set -e
  9  
 10  # Revert `git stash` on exit
 11  function revert_git_stash {
 12    >&2 echo "Unstashing uncommitted changes..."
 13    git stash pop -q
 14  }
 15  
 16  # Stash pending changes and revert them when script ends
 17  if [ -z "${NO_STASH:-}" ] && [ $is_unclean -ne 0 ]; then
 18    >&2 echo "Stashing uncommitted changes..."
 19    GIT_LITERAL_PATHSPECS=0 git stash -q --keep-index
 20    trap revert_git_stash EXIT
 21  fi
 22  
 23  export FLAKEBOX_GIT_LS
 24  FLAKEBOX_GIT_LS="$(git ls-files)"
 25  export FLAKEBOX_GIT_LS_TEXT
 26  FLAKEBOX_GIT_LS_TEXT="$(echo "$FLAKEBOX_GIT_LS" | grep -v -E "\.(png|ods|jpg|jpeg|woff2|keystore|wasm|ttf|jar|ico|gif)\$")"
 27  
 28  
 29  function check_nothing() {
 30    true
 31  }
 32  export -f check_nothing
 33  
 34  function check_cargo_fmt() {
 35      set -euo pipefail
 36  
 37      flakebox-in-each-cargo-workspace cargo fmt --all --check
 38  
 39  }
 40  export -f check_cargo_fmt
 41  
 42  function check_cargo_lock() {
 43      set -euo pipefail
 44  
 45      # https://users.rust-lang.org/t/check-if-the-cargo-lock-is-up-to-date-without-building-anything/91048/5
 46      flakebox-in-each-cargo-workspace cargo update --workspace --locked |& while read -r note ; do echo "$note    (cargo)"; done
 47  
 48  }
 49  export -f check_cargo_lock
 50  
 51  function check_leftover_dbg() {
 52      set -euo pipefail
 53  
 54      errors=""
 55      for path in $(echo "$FLAKEBOX_GIT_LS_TEXT" | grep '.*\.rs'); do
 56        if grep 'dbg!(' "$path" > /dev/null; then
 57          >&2 echo "$path contains dbg! macro"
 58          errors="true"
 59        fi
 60      done
 61  
 62      if [ -n "$errors" ]; then
 63        >&2 echo "Fix the problems above or use --no-verify" 1>&2
 64        return 1
 65      fi
 66  
 67  }
 68  export -f check_leftover_dbg
 69  
 70  function check_semgrep() {
 71      set -euo pipefail
 72  
 73      # semgrep is not available on MacOS
 74      if ! command -v semgrep > /dev/null ; then
 75        >&2 echo "Skipping semgrep check: not available"
 76        return 0
 77      fi
 78  
 79      if [ ! -f .config/semgrep.yaml ] ; then
 80        >&2 echo "Skipping semgrep check: .config/semgrep.yaml doesn't exist"
 81        return 0
 82      fi
 83  
 84      if [ ! -s .config/semgrep.yaml ] ; then
 85        >&2 echo "Skipping semgrep check: .config/semgrep.yaml empty"
 86        return 0
 87      fi
 88  
 89      env SEMGREP_ENABLE_VERSION_CHECK=0 \
 90        semgrep -q --error --no-rewrite-rule-ids --config .config/semgrep.yaml
 91  
 92  }
 93  export -f check_semgrep
 94  
 95  function check_shellcheck() {
 96      set -euo pipefail
 97  
 98      for path in $(echo "$FLAKEBOX_GIT_LS_TEXT" | grep -E '.*\.sh$'); do
 99        shellcheck --severity=warning "$path"
100      done
101  
102  }
103  export -f check_shellcheck
104  
105  function check_trailing_newline() {
106      set -euo pipefail
107  
108      errors=""
109      for path in $(echo "$FLAKEBOX_GIT_LS_TEXT"); do
110  
111        # extra branches for clarity
112        if [ ! -s "$path" ]; then
113           # echo "$path is empty"
114           true
115        elif [ -z "$(tail -c 1 < "$path")" ]; then
116           # echo "$path ends with a newline or with a null byte"
117           true
118        else
119          >&2 echo "$path doesn't end with a newline" 1>&2
120          errors="true"
121        fi
122      done
123  
124      if [ -n "$errors" ]; then
125        >&2 echo "Fix the problems above or use --no-verify" 1>&2
126        return 1
127      fi
128  
129  }
130  export -f check_trailing_newline
131  
132  function check_trailing_whitespace() {
133      set -euo pipefail
134  
135      rev="HEAD"
136      if ! git rev-parse -q 1>/dev/null HEAD 2>/dev/null ; then
137        >&2 echo "Warning: no commits yet, checking against --root"
138        rev="--root"
139      fi
140      if ! git diff --check $rev ; then
141        >&2 echo "Trailing whitespace detected. Please remove them before committing."
142        return 1
143      fi
144  
145  }
146  export -f check_trailing_whitespace
147  
148  function check_typos() {
149      set -euo pipefail
150  
151      if ! echo "$FLAKEBOX_GIT_LS_TEXT" | typos --file-list - --force-exclude ; then
152        >&2 echo "Typos found: Valid new words can be added to '.typos.toml'"
153        return 1
154      fi
155  
156  }
157  export -f check_typos
158  
159  parallel \
160    --nonotice \
161  ::: \
162      check_cargo_fmt \
163      check_cargo_lock \
164      check_leftover_dbg \
165      check_semgrep \
166      check_shellcheck \
167      check_trailing_newline \
168      check_trailing_whitespace \
169      check_typos \
170    check_nothing