aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2015-04-30 16:15:09 +1200
committerTom Ryder <tom@sanctum.geek.nz>2015-04-30 16:15:09 +1200
commitbe14d39a95771e40c3b7448b6488f7d164acce38 (patch)
treeebfaca1e7ab10a3598dac80328c845637eb923cd
downloadsyntax-checking-git-hooks-be14d39a95771e40c3b7448b6488f7d164acce38.tar.gz
syntax-checking-git-hooks-be14d39a95771e40c3b7448b6488f7d164acce38.zip
First commit
-rw-r--r--LICENSE22
-rw-r--r--README.markdown23
-rwxr-xr-xpre-commit106
3 files changed, 151 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6420c68
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Tom Ryder
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..ce4a3a2
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,23 @@
+Syntax checking Git hooks
+=========================
+
+As used by Tom Ryder, because Michael Fincham asked.
+
+The `pre-commit` file goes in `.git/hooks` in your repository, and you make it
+executable. You'll need `file(1)` and various other binaries in your PATH.
+
+This is nowhere near as tidy as it could be, but it correctly handles syntax
+checking and linting of added or changed files only, without rescanning the
+whole project. It does this with some byzantine Bash. It handles filenames with
+funny characters (including newlines) correctly.
+
+I'll write some real documentation Laterâ„¢.
+
+License
+-------
+
+Copyright (c) [Tom Ryder][1]. Distributed under [MIT License][2].
+
+[1]: https://sanctum.geek.nz/
+[2]: http://opensource.org/licenses/MIT
+
diff --git a/pre-commit b/pre-commit
new file mode 100755
index 0000000..31fb374
--- /dev/null
+++ b/pre-commit
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+# Tom Ryder <tom@sanctum.geek.nz>
+
+# Start counting errors
+declare -i errors
+
+# Read records supplied by git diff-index, null-terminated; we only want the
+# sha1 object name of the staged file
+while read -r -d '' _ _ _ sha1 _ ; do
+
+ # git diff-files has a NULL both before and after the filename it prints,
+ # so we need to run read again to get the filename out to move on to the
+ # next record (this is a bit weird, but at least it works)
+ read -r -d '' filename _
+
+ # Skip the sha1 if it's empty (which is how diff-index shows deleted files
+ # or moves)
+ if [[ $sha1 != *[^0]* ]] ; then
+ continue
+ fi
+
+ # Check Bash syntax
+ if [[ $filename == *.bash ]] || \
+ git cat-file -p "$sha1" | file - | grep -iq 'Bourne-Again' ; then
+ printf 'Checking modified %s ... \n' "$filename"
+
+ # Check the file with sh -n
+ if ! git cat-file -p "$sha1" | bash -n ; then
+ ((errors++))
+ continue
+ fi
+ fi
+
+ # Check shell script syntax
+ if [[ $filename == *.sh ]] || \
+ git cat-file -p "$sha1" | file - | grep -iq 'POSIX shell' ; then
+ printf 'Checking modified %s ... \n' "$filename"
+
+ # Check the file with sh -n
+ if ! git cat-file -p "$sha1" | sh -n ; then
+ ((errors++))
+ continue
+ fi
+ fi
+
+ # Check HTML syntax
+ if [[ $filename == *.html ]] || \
+ git cat-file -p "$sha1" | file - | grep -iq html ; then
+ printf 'Checking modified %s ... \n' "$filename"
+
+ # Check the file with HTML5 tidy(1)
+ if ! git cat-file -p "$sha1" | tidy -eq -utf8 ; then
+ ((errors++))
+ continue
+ fi
+ fi
+
+ # Check JS syntax and best practices
+ if [[ $filename == *.js ]] || \
+ git cat-file -p "$sha1" | file - | grep -iq javascript ; then
+ printf 'Checking modified %s ... \n' "$filename"
+
+ # Check the file with jslint (which sucks and is bad)
+ if ! jslint <(git cat-file -p "$sha1") ; then
+ ((errors++))
+ continue
+ fi
+ fi
+
+ # Check Perl syntax
+ if [[ $filename == *.pl ]] || \
+ [[ $filename == *.pm ]] || \
+ git cat-file -p "$sha1" | file - | grep -iq perl ; then
+ printf 'Checking modified %s ... \n' "$filename"
+
+ # Check the file with perl -c; skip perlcritic if it doesn't pass
+ if ! git cat-file -p "$sha1" | perl -c ; then
+ ((errors++))
+ continue
+ fi
+
+ # Check the file with perlcritic --brutal
+ if ! git cat-file -p "$sha1" | perlcritic --brutal ; then
+ ((errors++))
+ continue
+ fi
+ fi
+
+ # Check PHP syntax
+ if [[ $filename == *.php ]] || \
+ git cat-file -p "$sha1" | file - | grep -iq php ; then
+ printf 'Checking modified %s ... \n' "$filename"
+
+ # Check the file with php -l
+ if ! git cat-file -p "$sha1" | php -l ; then
+ ((errors++))
+ continue
+ fi
+ fi
+
+# Standard input for the while loop is here
+done < <(git diff-index -z --cached HEAD)
+
+# Exit 0 if there were no errors, 1 if there were
+exit "$((errors > 0))"
+