From 29e96e6b9a8e68e6554dd48bc2ce68ae9525d29f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 1 Dec 2011 18:13:44 +0100 Subject: [PATCH] Add hook to check the commit log syntax. * autogen.sh: Install commit-msg hook for git. --- autogen.sh | 7 ++ scripts/git-hooks/commit-msg | 127 +++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100755 scripts/git-hooks/commit-msg diff --git a/autogen.sh b/autogen.sh index 8a424bce5..0ec134d69 100755 --- a/autogen.sh +++ b/autogen.sh @@ -296,6 +296,13 @@ EOF git config --add filter.cleanpo.clean \ "awk '/^\"POT-Creation-Date:/&&!s{s=1;next};!/^#: /{print}'" fi + if [ -f scripts/git-hooks/commit-msg -a ! -f .git/hooks/commit-msg ] ; then + cat <&2 +*** Activating commit log message check hook. *** +EOF + cp -av scripts/git-hooks/commit-msg .git/hooks/commit-msg + chmod -c +x .git/hooks/commit-msg + fi fi echo "Running aclocal -I m4 -I gl/m4 ${ACLOCAL_FLAGS:+$ACLOCAL_FLAGS }..." diff --git a/scripts/git-hooks/commit-msg b/scripts/git-hooks/commit-msg new file mode 100755 index 000000000..5a697c7a6 --- /dev/null +++ b/scripts/git-hooks/commit-msg @@ -0,0 +1,127 @@ +eval '(exit $?0)' && eval 'exec perl -w "$0" ${1+"$@"}' + & eval 'exec perl -w "$0" $argv:q' + if 0; + +# An hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, copy it to "~/.git/hooks/commit-msg". +# +# This script is based on the one from GNU coreutils. + +use strict; +use warnings; +(my $ME = $0) =~ s|.*/||; + +my $editor = $ENV{EDITOR} || 'vi'; +$ENV{PATH} = '/bin:/usr/bin'; + +# Rewrite the $LOG_FILE (old contents in @$LINE_REF) with an additional +# commented diagnostic "# $ERR" line at the top. +sub rewrite($$$) +{ + my ($log_file, $err, $line_ref) = @_; + local *LOG; + open LOG, '>', $log_file + or die "$ME: $log_file: failed to open for writing: $!"; + print LOG "# $err"; + print LOG @$line_ref; + close LOG + or die "$ME: $log_file: failed to rewrite: $!\n"; +} + +sub re_edit($) +{ + my ($log_file) = @_; + + warn "Interrupt (Ctrl-C) to abort...\n"; + + system 'sh', '-c', "$editor $log_file"; + ($? & 127) || ($? >> 8) + and die "$ME: $log_file: the editor ($editor) failed, aborting\n"; +} + +# Given a $LOG_FILE name and a \@LINE buffer, +# read the contents of the file into the buffer and analyze it. +# If the log message passes muster, return the empty string. +# If not, return a diagnostic. +sub check_msg($$) +{ + my ($log_file, $line_ref) = @_; + + local *LOG; + open LOG, '<', $log_file + or return "failed to open for reading: $!"; + @$line_ref = ; + close LOG; + + my @line = @$line_ref; + chomp @line; + + # Don't filter out blank or comment lines; git does that already, + # and if we were to ignore them here, it could lead to committing + # with lines that start with "#" in the log. + + # Filter out leading blank and comment lines. + # while (@line && $line[0] =~ /^(?:#.*|[ \t]*)$/) { shift @line; } + + # Filter out blank and comment lines at EOF. + # while (@line && $line[$#line] =~ /^(?:#.*|[ \t]*)$/) { pop @line; } + + @line == 0 + and return 'no log message'; + + # The first line should not be too short + 8 < length $line[0] || return 'summary line too short'; + + # The first line should not start with an asterisk or a hash sign. + # An asterisk might indicate that a change entry was started right + # at the first line. + $line[0] =~ /^[*#]/ && return "summary line starts with an * or #"; + + # Second line should be blank or not present. + 2 <= @line && length $line[1] + and return 'second line must be empty'; + + # Limit line length to allow for the ChangeLog's leading TAB. + foreach my $line (@line) + { + 72 < length $line && $line =~ /^[^#]/ + and return 'line longer than 72 characters'; + } + + return ''; +} + +{ + @ARGV == 1 + or die; + + my $log_file = $ARGV[0]; + + while (1) + { + my @line; + my $err = check_msg $log_file, \@line; + $err eq '' + and last; + $err = "$ME: $err\n"; + warn $err; + exit 1; + + # Insert the diagnostic as a comment on the first line of $log_file. + #rewrite $log_file, $err, \@line; + #re_edit $log_file; + # + ## Stop if our parent is killed. + #getppid() == 1 + # and last; + } +} + +# Local Variables: +# mode: perl +# End: