Last active
November 23, 2015 12:21
-
-
Save pfctgeorge/775c8b0b7ca7ba812e87 to your computer and use it in GitHub Desktop.
Git hooks
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
#!/env/python | |
# coding: utf-8 | |
from subprocess import check_output, PIPE, Popen | |
import sys | |
import re | |
BADREV = "0000000000000000000000000000000000000000" | |
def is_binary_file(filename): | |
regex = ('\.(pdb|dll|exe|png|gif|jpg|mwb|zip|tgz|gz|bz2|7z' | |
'|rar|swf|fla|jar|mo|ttf|foo|mp3|icc|pdf|bmp|wmf|otf)$') | |
return re.search(regex, filename) is not None | |
def is_merging_commit(rev): | |
s = check_output(["git", "rev-list", "--parents", "-n", "1", rev]) | |
return len(s.split()) - 1 >= 2 | |
def is_fixed_issue(rev): | |
commit_message = check_output(["git", "show", "-s", | |
"--format=format:%s", rev]).strip() | |
return re.match("Fixes \#\d+: ", commit_message) is not None | |
def check_crlf(rev): | |
diff_tree = check_output(["git", "diff-tree", "-r", rev]).strip() | |
for line in diff_tree.split("\n")[1:]: | |
(old_mode, new_mode, old_sha1, new_sha1, _, name) = line.split() | |
# skip checking for deleted file and binary file | |
if new_sha1 == BADREV or is_binary_file(name): | |
continue | |
p1 = Popen(["git", "cat-file", "blob", new_sha1], stdout=PIPE) | |
p2 = Popen(["grep -c $'\x0D'"], stdin=p1.stdout, stdout=PIPE, | |
shell=True) | |
p1.stdout.close() | |
if (int(p2.communicate()[0]) > 0): | |
return False | |
return True | |
def print_error_message_for_not_fixing_issue_commit(rev): | |
print "###########################################################" | |
print "# The message of commit [%s] should be" % rev[0:7] | |
print "# started with `Fixes #:issue-id` format." | |
print "# please run `git rebase -i` to deal with." | |
print "############################################################" | |
def print_error_message_for_crlf_commit(rev): | |
print "############################################################" | |
print "# One or more files in commit [%s] contained CRLF" % rev[0:7] | |
print "# line endings which are not allowed. Please visit" | |
print "# https://help.github.com/articles/dealing-with-line-endings" | |
print "# for correct configuration and re-commit the change." | |
print "############################################################" | |
def check_rev(rev): | |
# skip checking for merging commit | |
if is_merging_commit(rev): | |
return True | |
if not is_fixed_issue(rev): | |
print_error_message_for_not_fixing_issue_commit(rev) | |
return False | |
if not check_crlf(rev): | |
print_error_message_for_crlf_commit(rev) | |
return False | |
return True | |
if __name__ == "__main__": | |
for line in sys.stdin: | |
old, new, ref = line.strip().split() | |
if new == BADREV: | |
continue | |
if old == BADREV: | |
# try to push a new branch | |
refs = check_output(["git", "for-each-ref", "--format=%(refname)", | |
"refs/heads/*"]).strip().split("\n") | |
for ref in refs: | |
for rev in check_output(["git", "rev-list", "--topo-order", | |
"--reverse", "%s...%s" % (new, ref) | |
]).strip().split("\n"): | |
if not check_rev(rev): | |
exit(1) | |
exit(0) | |
for rev in check_output(["git", "rev-list", | |
"--topo-order", "--reverse", | |
"%s...%s" % (new, old)]).strip().split("\n"): | |
if not check_rev(rev): | |
exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment