Git Pre-commit hook

By | 2011/12/24

Yesterday I have written first code in Bash Script :D. It was a pre-commit hook which checks my Javascript files against bugs using JSLint. To install it, please download JSLint from http://www.javascriptlint.com/ and copy executable file (I renamed it from jsl to jslint) and config file to:

your_project/.git/hooks

and put following code into the pre-commit file which should be already there.

BTW, to skip it, do:

git commit --no-verify -m "Message"
#!/bin/sh
 
declare prev_file=""
declare prev_line=""
declare out
declare cmd=".git/hooks/jslint -conf .git/hooks/jslint.conf"
declare -i interrupt=0
 
if git-rev-parse --verify HEAD >/dev/null 2>&1; then
    against=HEAD
else
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
 
#take all changed files, example (1 modified file):
# Array[0]: M
# Array[1]: assets/css/styles.css
for FILE in `git diff --cached --name-status` ; do
	#if file exist
	if [ -e $FILE ]
		then
		#check only JS files
		if [[ $FILE == *.js ]]
			then
			#if file has been modified
			if [ "$prev_file" == "M" ]
				then
				cmd="$cmd -process $FILE"
			fi
		fi
	fi
 
	prev_file=$FILE;
done
 
#execute command and check if any mistakes has been made
out=$( eval "$cmd" );
 
#check if errors == 0 and warrnings == 0
if [ out ]
	then
	for LINE in $out; do
		if [ "$LINE" = "error(s)," ]
			then
			if [ "$prev_line" != "0" ]
				then
				interrupt=1
			fi
		fi
 
		if [ "$LINE" = "warning(s)" ]
			then
			if [ "$prev_line" != "0" ]
				then
				interrupt=1
			fi
		fi
 
		prev_line=$LINE;
	done
fi
 
echo "$out\n\n"
 
#display error messages and interrupt commit
if [ "$interrupt" == "1" ]
	then
	exit 1
fi
 
exit

Here is my config file:

#
# Configuration File for JavaScript Lint 0.3.0
# Developed by Matthias Miller (http://www.JavaScriptLint.com)
#
# This configuration file can be used to lint a collection of scripts, or to enable
# or disable warnings for scripts that are linted via the command line.
#
 
### Warnings
# Enable or disable warnings based on requirements.
# Use "+WarningName" to display or "-WarningName" to suppress.
#
+no_return_value              # function {0} does not always return a value
+duplicate_formal             # duplicate formal argument {0}
+equal_as_assign              # test for equality (==) mistyped as assignment (=)?{0}
+var_hides_arg                # variable {0} hides argument
+redeclared_var               # redeclaration of {0} {1}
+anon_no_return_value         # anonymous function does not always return a value
+missing_semicolon            # missing semicolon
+meaningless_block            # meaningless block; curly braces have no impact
+comma_separated_stmts        # multiple statements separated by commas (use semicolons?)
+unreachable_code             # unreachable code
+missing_break                # missing break statement
+missing_break_for_last_case  # missing break statement for last case in switch
+comparison_type_conv         # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
+inc_dec_within_stmt          # increment (++) and decrement (--) operators used as part of greater statement
+useless_void                 # use of the void type may be unnecessary (void is always undefined)
+multiple_plus_minus          # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
+use_of_label                 # use of label
+block_without_braces         # block statement without curly braces
+leading_decimal_point        # leading decimal point may indicate a number or an object member
+trailing_decimal_point       # trailing decimal point may indicate a number or an object member
+octal_number                 # leading zeros make an octal number
+nested_comment               # nested comment
+misplaced_regex              # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
+ambiguous_newline            # unexpected end of line; it is ambiguous whether these lines are part of the same statement
+empty_statement              # empty statement or extra semicolon
-missing_option_explicit      # the "option explicit" control comment is missing
+partial_option_explicit      # the "option explicit" control comment, if used, must be in the first script tag
+dup_option_explicit          # duplicate "option explicit" control comment
+useless_assign               # useless assignment
+ambiguous_nested_stmt        # block statements containing block statements should use curly braces to resolve ambiguity
+ambiguous_else_stmt          # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
+missing_default_case         # missing default case in switch statement
+duplicate_case_in_switch     # duplicate case in switch statements
+default_not_at_end           # the default case is not at the end of the switch statement
+legacy_cc_not_understood     # couldn't understand control comment using /*@keyword@*/ syntax
+jsl_cc_not_understood        # couldn't understand control comment using /*jsl:keyword*/ syntax
+useless_comparison           # useless comparison; comparing identical expressions
+with_statement               # with statement hides undeclared variables; use temporary variable instead
+trailing_comma_in_array      # extra comma is not recommended in array initializers
+assign_to_function_call      # assignment to a function call
+parseint_missing_radix       # parseInt missing radix parameter
 
 
### Output format
# Customize the format of the error message.
#    __FILE__ indicates current file path
#    __FILENAME__ indicates current file name
#    __LINE__ indicates current line
#    __ERROR__ indicates error message
#
# Visual Studio syntax (default):
+output-format ======================================================================\n__FILE__, line: __LINE__\n----------------------------------------------------------------------\n__ERROR__
# Alternative syntax:
#+output-format __FILE__:__LINE__: __ERROR__
 
 
### Context
# Show the in-line position of the error.
# Use "+context" to display or "-context" to suppress.
#
+context
 
 
### Semicolons
# By default, assignments of an anonymous function to a variable or
# property (such as a function prototype) must be followed by a semicolon.
#
+lambda_assign_requires_semicolon
 
 
### Control Comments
# Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for
# the /*@keyword@*/ control comments and JScript conditional comments. (The latter is
# enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason,
# although legacy control comments are enabled by default for backward compatibility.
#
+legacy_control_comments
 
 
### JScript Function Extensions
# JScript allows member functions to be defined like this:
#     function MyObj() { /*constructor*/ }
#     function MyObj.prototype.go() { /*member function*/ }
#
# It also allows events to be attached like this:
#     function window::onload() { /*init page*/ }
#
# This is a Microsoft-only JavaScript extension. Enable this setting to allow them.
#
-jscript_function_extensions
 
 
### Defining identifiers
# By default, "option explicit" is enabled on a per-file basis.
# To enable this for all files, use "+always_use_option_explicit"
+always_use_option_explicit
 
# Define certain identifiers of which the lint is not aware.
# (Use this in conjunction with the "undeclared identifier" warning.)
#
# Common uses for webpages might be:
#+define window
#+define document
+define jQuery
+define Backbone
+define _
 
+define ModuleMap
+define ModuleWindows
+define ModuleData
 
### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
#+process .git/hooks/jsl-test.js

I’m aware that my code just work, and can be improved, so feel free to post some suggestions.