Sunday 29 November 2009

Git - inhibit commit if modules don't compile

Sometimes I forget to run Perl base tests for my modules, before committing changes. As to what happens, I end up committing something that doesn't quite compile ;)

Luckily Git has a pre-commit hook one can use to run at least the "compile" tests.

The following aborts the commit if the t/00*.t tests (usually the "do all modules compile?" tests) in the repository don't run correctly:

~$ cat .git/hooks/pre-commit
#!/usr/bin/perl
# Runs modules' "compiles" tests before committing
# Dies (halting commit) if they don't compile
print "pre-commit => testing..\n";
do {qx{
prove -Ilib t/00*.t
}} or die <<'DIEMSG';
pre-commit => ERRORS:
$@
DIEMSG
print "pre-commit => test OK\n";


This is an example of a 00-load.t file, that can literally be dropped-in the t/ directory:

use strict;
use warnings;
use Test::More;
use File::Find::Rule;

my @files = File::Find::Rule->name('*.pm')->in('lib');
plan tests => ~ ~ @files;

for (@files) {
s/^lib.//;
s/.pm$//;
s{[\\/]}{::}g;

ok(
eval "require $_; 1",
"loaded $_ with no problems",
);
}


File::Find::Rule is one of the golden gems found on CPAN, rclamp++!

Till soon,
-marco-

1 comment:

  1. You have to be extremely careful with this. You aren't testing if your commit compiles, but if the working tree compiles. You should stash the changes (except for those in the index).

    My pre-commit hook looks like this:
    git stash save --keep-index

    ./runtests.py

    if [ $? = 0 ]; then
    exit 0;
    else
    git stash pop;
    exit 1;
    fi;

    And my post-commit hook looks like this:
    git stash pop;

    I think there might still be a problem if I commit with --no-verify, though.

    ReplyDelete