Skip to content

Instantly share code, notes, and snippets.

@kvz
Created December 17, 2013 15:54
Show Gist options
  • Save kvz/8007150 to your computer and use it in GitHub Desktop.
Save kvz/8007150 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
#
# A Git pre-commit hook that checks for syntax errors
# for: Ruby, JavaScript, Python, Bash, and (Cake)PHP
# based on the extensions of staged files in Git.
# Can be 'installed globally' as of Git 1.7.1 using init.templatedir
#
# Copyright 2013, kvz (http://twitter.com/kvz)
#
# Some common caveats have been taken care of:
# - Works with files that contain spaces
# - Works on initial commits
# - Will skip files that are about to be deleted
# - Uses file as staged in git, not how it currently is in your working dir
#
# Focussed on not committing syntax errors to repositories
# and should not have strong opinions on coding style, though
# could be modified to have them.
#
# Some language checks are very basic still. I'm welcoming improvements on
# https://github.com/kvz/dotfiles/blob/master/.gittemplate/hooks/pre-commit
#
# To install standalone (without the spaceship that is my dotfiles/install.sh)
# type:
# $ mkdir -p ~/.gittemplate/hooks
# $ curl https://raw.github.com/kvz/dotfiles/master/.gittemplate/hooks/pre-commit -ko ~/.gittemplate/hooks/pre-commit && chmod 755 $_
# $ git config --global init.templatedir '~/.gittemplate'
#
# Now in new (or existing) repos, type
# $ git init
#
# To reset all hooks by template in an existing repo type
# $ rm .git/hooks/* && git init
#
# This will copy any non-existing files in ~/.gittemplate into your
# new/current repo's .git dir. This only works from git 1.7.1 and up
#
# Warnings
# - Assumes BASH in case of *.sh files. If you are into Dash you
# should change that
#
# Prior Art
# - http://mark-story.com/posts/view/using-git-commit-hooks-to-prevent-stupid-mistakes
# - http://stackoverflow.com/a/8842663/151666
# - https://github.com/phpbb/phpbb/blob/develop-olympus/git-tools/hooks/pre-commit
# Necessary check for initial commit
against="4b825dc642cb6eb9a060e54bf8d69288fbee4904"
git rev-parse --verify HEAD > /dev/null 2>&1 && against="HEAD"
function i_can_haz() {
which "${1}" > /dev/null 2>&1 || emergency "Please install ${1} for pre-commit syntax checking. "
}
function stdcolors() (
set -o pipefail;
("$@" 2>&1>&3 | sed $'s,.*,\e[31m&\e[m,' >&2) 3>&1 \
| sed $'s,.*,\e[32m&\e[m,'
)
function info() {
echo -e "\x1B[32m${@}\x1B[0m"
}
function debug() {
echo -e "\x1B[37m${@}\x1B[0m"
}
function error() {
echo -e "\x1B[31m${@}\x1B[0m"
}
function emergency() {
error "${@}"
exit 1
}
# (A)dded (C)opied or (M)odified
git diff-index --cached --full-index --diff-filter=ACM $against | while read -r line; do
sha1="$(echo ${line} | cut -d' ' -f4)"
stat="$(echo ${line} | cut -d' ' -f5)"
file="$(echo ${line} | cut -d' ' -f6-)"
# debug "--> Syntax check for ${stat}:${file}=${sha1}, "
case "${file}" in
*.rb|*.erb)
i_can_haz ruby
git cat-file -p ${sha1} \
| (stdcolors ruby -c > /dev/null \
&& info "No syntax errors detected in ${file}") \
|| emergency "Please fix errors, type 'git add ${file}', and try again. "
;;
*.js)
i_can_haz jshint
git cat-file -p ${sha1} \
| (stdcolors jshint - > /dev/null \
&& info "No syntax errors detected in ${file}") \
|| emergency "Please fix errors, type 'git add ${file}', and try again. "
;;
*.coffee)
i_can_haz coffeelint
# coffeelint unfortunately uses STDOUT for errors, so no coloring
git cat-file -p ${sha1} \
| (coffeelint --stdin \
&& info "No syntax errors detected in ${file}") \
|| emergency "Please fix errors, type 'git add ${file}', and try again. "
;;
*.py)
i_can_haz pylint
git cat-file -p ${sha1} \
| (stdcolors pylint - > /dev/null \
&& info "No syntax errors detected in ${file}") \
|| emergency "Please fix errors, type 'git add ${file}', and try again. "
;;
*.bash|*.sh)
i_can_haz bash
git cat-file -p ${sha1} \
| (stdcolors bash -n - > /dev/null \
&& info "No syntax errors detected in ${file}") \
|| emergency "Please fix errors, type 'git add ${file}', and try again. "
;;
*.ctp|*.php)
i_can_haz php
git cat-file -p ${sha1} \
| (stdcolors php -n -l -ddisplay_errors=1 -derror_reporting=E_ALL -dlog_errrors=0 > /dev/null \
&& info "No syntax errors detected in ${file}") \
|| emergency "Please fix errors, type 'git add ${file}', and try again. "
;;
*)
# debug "Skipped as there is no handler for this extension"
;;
esac
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment