Created
August 17, 2011 08:46
-
-
Save joes/1151114 to your computer and use it in GitHub Desktop.
git pre-commit hook with php syntax checking and more
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# | |
# Author: Joe Siponen <joe.siponen@gmail.com> | |
# | |
# A hook script to verify that only syntactically valid php code is commited. | |
# | |
# This hook also stops files containing the string '[[NOCOMMIT' from being committed. | |
# This provides an mechanism allowing you to protect yourself from committing | |
# code you have added for debugging purposes by adding the string '[[NOCOMMIT' | |
# near the relevant section of code. | |
# | |
# Called by git-commit with no arguments. The hook should exit with non-zero status | |
# after issuing an appropriate message if it wants to stop the commit. | |
# | |
# Put this code into a file called "pre-commit" inside your .git/hooks | |
# directory, and make sure it is executable ("chmod +x .git/hooks/pre-commit") | |
# | |
# Requires Ruby 1.8.6 or better | |
require 'pp' | |
require 'open3' | |
require 'strscan' | |
include Open3 | |
workdir = Dir.getwd | |
head_verified = system('git rev-parse --verify HEAD >/dev/null') | |
if head_verified | |
against = 'HEAD' | |
else | |
# Initial commit: diff against an empty tree object | |
against = '4b825dc642cb6eb9a060e54bf8d69288fbee4904' | |
end | |
# pp ENV | |
def is_php_lint_error_result(result_string) | |
return result_string.chomp.size > 0 | |
end | |
def read_file_from_git_index(file) | |
file_index_contents_cmd = "git show :#{file}" | |
file_index_contents = nil | |
popen3(file_index_contents_cmd) do |stdin, stdout, stderr| | |
file_index_contents = stdout.read | |
end | |
if file_index_contents.nil? || file_index_contents.size <= 0 | |
$stdout.puts "Error reading #{file}: "+(file_index_contents.nil? ? 'Unreadable file' : 'Empty file') | |
exit 1 | |
end | |
return file_index_contents | |
end | |
changed_files = `git diff-index --diff-filter=ACMRTU --name-only -z --cached #{against}`.split("\0").inject([]) do |files, line| | |
files << line.chomp | |
files | |
end | |
puts "Validating PHP syntax" | |
php_syntax_error_files = changed_files.inject([]) do |php_syntax_error_files, file| | |
if file =~ /\.php$/ #Validate php files | |
php_file_index_contents = read_file_from_git_index(file) | |
if php_file_index_contents.nil? || php_file_index_contents.size <= 0 | |
$stdout.puts "Error reading #{file}: "+(php_file_index_contents.size <= 0 ? 'Empty file' : 'Unreadable file') | |
exit 1 | |
end | |
puts "php -l #{file}" | |
php_lint_result = nil | |
popen3('php -l') do | stdin, stdout, stderr | | |
stdin.puts(php_file_index_contents) | |
stdin.close_write() | |
php_lint_result = stderr.read() | |
end | |
if is_php_lint_error_result(php_lint_result) | |
php_syntax_error_files << "file://#{File.join(workdir, file)}: #{php_lint_result.chomp}" | |
end | |
end | |
php_syntax_error_files | |
end | |
#Check for the token [[NOCOMMIT in changed files and | |
#stop the commit if it exists. | |
commit_warn_token_re = /\[\[NOCOMMIT/ | |
commmit_warn_line_counter = 0 | |
commit_warned_files = changed_files.inject([]) do |commit_warned_files, file| | |
file_contents = read_file_from_git_index(file) | |
commit_warn_scanner = StringScanner.new(file_contents) | |
while !(commit_warn_scanner.eos?) | |
matched = commit_warn_scanner.scan_until(commit_warn_token_re) | |
break if (matched.nil? or matched.size <= 0) | |
matched_on_line = matched.count("\n") | |
commmit_warn_line_counter += matched_on_line | |
commit_warned_files << "file://#{File.join(workdir, file)}: [[NOCOMMIT token at line #{commmit_warn_line_counter+1}" | |
end | |
commit_warned_files | |
end | |
is_valid_commit = true | |
if (php_syntax_error_files.size > 0) | |
$stderr.puts "\n== PHP Parse errors in: ==\n"+php_syntax_error_files.join("\n") | |
is_valid_commit = false | |
end | |
if (commit_warned_files.size > 0) | |
$stderr.puts "\n== Encountered [[NOCOMMIT tokens in: ==\n"+commit_warned_files.join("\n") | |
is_valid_commit = false | |
end | |
if is_valid_commit == true | |
$stdout.puts 'No errors/problems detected in pre-commit phase' | |
# All is well | |
exit 0 | |
else | |
puts | |
$stdout.puts 'Aborting commit due to errors/problems detected in pre-commit phase' | |
exit 1 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
First version, beta quality: trying this one out for now to see what breaks