Revision 11e8869836a20f39871134035fdb50096f4d7dc4 authored by Paul Zimmermann on 20 February 2014, 14:53:40 UTC, committed by Paul Zimmermann on 20 February 2014, 14:53:40 UTC
2 parent s e23925b + 0410003
Raw File
post-receive.pl
#!/usr/bin/perl -Tw

# This is an example git post-receive hook script. It can be used to
# automatically send emails listing new revisions to the repository
# introduced by the change being reported.
#
# Copyright 2011 Emmanuel Thomé -- This script is placed in the public domain.
#
# Usage: copy this to $GIT_DIR/hooks/post-receive (executable) in the
# repository receiving pushes.
#
# The file $GIT_DIR/config should contain the following keys (these are
# examples).
#
# hooks.emailprefix=
# hooks.mailinglist=Cado-NFS commits <cado-nfs-commits@lists.gforge.inria.fr>
# hooks.envelopesender=Cado-NFS commits <cado-nfs-commits@lists.gforge.inria.fr>
# hooks.gitweb=http://tomato.elliptic.org/gitweb/?p=cado-nfs.git;

use strict;
use warnings;
use UUID;       # Or any simple way of creating MIME delimiters, really.
use File::Basename;
use POSIX;

$ENV{'PATH'}="/bin:/usr/bin:/usr/sbin";

my $git_dir="$ENV{'GIT_DIR'}" or die 'no $GIT_DIR set';

my $repo = basename($git_dir, ".git");

sub config_get {
    my $key = shift;
    my $x = `git config $key 2>/dev/null`;
    if ($x =~ /^([^'`]*)$/) {
        # A positive answer with empty content still reaches here.
        $x=$1;
        chomp($x);
        return $x;
    }
    my $default = shift;
    return '' unless $default;
    die "Mandatory config key $key is missing" if $default eq '!';
    return $default;
}
    
my $gitweb=config_get('hooks.gitweb');
chomp($gitweb);
my $recipient=config_get('hooks.mailinglist', '!');
my $sender=config_get('hooks.envelopesender', '!');
my $subj_prefix=config_get('hooks.emailprefix', "[$repo-commits] ");

sub commit_link {
    my $commit = shift;
    return $commit unless $gitweb;
    my $url = $gitweb . "a=commitdiff;h=$commit";
    return "<a href=\"$url\">$commit</a>";
}

my @branches_touched=();
my $total_text_plain='';
my $total_text_html='';
my $total_nc = 0;
my $last_subject;

sub boundary { UUID::generate($_);UUID::unparse($_, my $x); $x; }

my $mainbound = boundary();

my $patches_mboxes='';

while (defined($_=<STDIN>)) {
    chomp($_);
    s/^\s*//;
    next if /^$/;
    s/^([0-9a-f]{40})\s+// or die "Bad input line: $_";
    my $old = $1;
    s/^([0-9a-f]{40})\s+// or die "Bad input line: $_";
    my $new = $1;
    next if $old =~ /^0+$/;
    next if $new =~ /^0+$/;
    my $ref = $_;
    $ref =~ s,^refs/heads/,,;
    push @branches_touched, $ref;
    my $format = '%h %ae %s';
    open F, "git log --pretty=\"$format\" --abbrev $old..$new |";
    my $text_plain='';
    my $text_html='';
    my $author='';
    my $nc=0;
    while (defined(my $line = <F>)) {
        my ($commit, $who, $subject) = split(' ', $line, 3);
        chomp($subject);
        if ($who ne $author) {
            $text_html .= "</ul>\n" if $author;
            $author = $who;
            $text_plain .= "\n$who\n";
            $text_html .= "<p>$who</p>\n<ul>\n";
        }
        $text_plain .= " $commit $subject\n";
        my $link = commit_link($commit);
        $text_html .= "<li>$link $subject</li>\n";
        $last_subject = $subject;
        $nc++;
    }
    close F;
    $text_html .= "</ul>\n" if $author;
    $text_plain .= "\n\n";

    my $x = "Branch: $ref";
    $text_plain = "$x, $nc new commits\n" . ('=' x length($x)) . "\n" . $text_plain;
    $text_html = "<h1>Branch: $ref, $nc new commits</h1>\n" . $text_html;;

    $total_text_plain .= $text_plain;
    $total_text_html .= $text_html;
    $total_nc += $nc;

    my $bound = boundary();

    open PATCH, "git format-patch --stdout $old..$new |";
    $x = eval { local $/=undef; <PATCH>; };
    $x =~ s/^(From (\w{7})\w{33})/--$bound
Content-Type: message\/rfc822; charset=us-ascii
Content-Disposition: attachment; filename="$2.patch"

$1/gm;

    my $now = POSIX::strftime( "%Y%m%d%H%M%S", localtime);

    $patches_mboxes .= <<EOF;
--$mainbound
Content-Type: multipart/mixed; boundary=$bound
Content-Disposition: attachment; filename="$repo-$ref-$now.mbox"

$x

--$bound--
EOF
    close PATCH;
}


my $refs = join(', ', @branches_touched);

return unless $total_nc;

my $subject = "$total_nc new commits";
if ($total_nc == 1) {
    $subject = $last_subject;
}


my $header = <<EOF;
To: $recipient
From: $sender
Subject: $subj_prefix($refs) $subject
EOF

$header=~s/\n$//m;

my $textbound = boundary();

my $body = <<EOF;
--$mainbound
Content-Type: multipart/alternative; boundary=$textbound

--$textbound
Content-Type: text/plain; charset=utf-8

$total_text_plain

--$textbound
Content-Type: text/html; charset=utf-8

$total_text_html

--$textbound--

$patches_mboxes

--$mainbound--
EOF

my $bodylength = length($body);
my $bodylines = eval { @_=split(/^/m, $body);scalar @_; };

if (@ARGV && $ARGV[0] eq '-d') {
    open SMTP, ">&STDOUT";
    my $now=strftime("%a %b %d %H:%M:%S %Y", localtime);
    print SMTP "From root $now\n";
} else {
    open SMTP, "| exim '$recipient'";
}

print SMTP <<EOF;
$header
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=$mainbound
Content-Transfer-Encoding: 8bit
Content-Disposition: inline
Content-Length: $bodylength
Lines: $bodylines

$body
EOF
close SMTP;

back to top