Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 6991c40c2c
Fetching contributors…

Cannot retrieve contributors at this time

executable file 334 lines (291 sloc) 7.507 kb
#!/usr/bin/perl -w
#
# "post-receive" hook script to send git commit notifications
#
# Copyright (c) 2009 Benedikt Meurer <benedikt.meurer@googlemail.com>
# Copyright (c) 2005 Alexandre Julliard
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# Config
# ------
# cgit.baseurl
# The base URL of the cgit web interface (i.e. http://host.domain/cgit/).
# gitweb.baseurl
# The base URL of the gitweb web interface (i.e. http://host.domain/git).
# notify.mailinglist
# The mailinglist to which commit notifications should be sent. If unset,
# this hook script won't generate any commit notification emails for the
# repository. This is unset by default.
# notify.emailprefix
# The prefix to add to the subject of each commit notification. By default
# no special email subject prefix will be used.
# notify.include
# The branches for which to generate commit notification emails. If unset,
# commit notification emails will be generated for all branches (except
# the ones specified in notify.exclude).
# notify.exclude
# The branches for which no commit notification emails should be generated.
#
use Cwd 'realpath';
use Encode 'encode';
use open ':utf8';
use strict;
binmode STDIN, ':utf8';
binmode STDOUT, ':utf8';
sub git_config($);
sub git_object_info($);
sub git_repository();
################
### SETTINGS ###
################
# Path to sendmail
my $sendmail = '/usr/sbin/sendmail';
################################
### REPOSITORY CONFIGURATION ###
################################
# cgit base URL
my $cgit_baseurl = git_config("cgit.baseurl");
# gitweb base URL
my $gitweb_baseurl = git_config("gitweb.baseurl");
# default repository name
my $notify_repository = git_repository();
# mailinglist to send notifications to
my $notify_mailinglist = git_config("notify.mailinglist");
# subject prefix for notification emails
my $notify_emailprefix = git_config("notify.emailprefix") || "";
# branches to include
my @notify_include = split /\s+/, git_config("notify.include") || "";
# branches to exclude
my @notify_exclude = split /\s+/, git_config("notify.exclude") || "";
#################
### FUNCTIONS ###
#################
# fetch a parameter from the git config file
sub git_config($)
{
my ($key) = @_;
open GIT_CONFIG, "-|" or exec "git", "config", "$key";
my $value = <GIT_CONFIG>;
chomp $value if $value;
close GIT_CONFIG or $value = undef;
return $value;
}
# format an integer data + timezone as string (see git's date.c)
sub git_format_date($$)
{
my ($time,$tz) = @_;
if ($tz < 0)
{
my $minutes = (-$tz / 100) * 60 + (-$tz % 100);
$time -= $minutes * 60;
}
else
{
my $minutes = ($tz / 100) * 60 + ($tz % 100);
$time += $minutes * 60;
}
return gmtime($time) . sprintf " %+05d", $tz;
}
# extract the information from a commit or tag object and return a hash
# containing the various fields
sub git_object_info($)
{
my ($object) = @_;
my %info = ();
my @log = ();
my $do_log = 0;
open GIT_CAT_FILE, "-|" or exec "git", "cat-file", "-t", $object
or die "Failed to execute git-cat-file";
my $type = <GIT_CAT_FILE>;
chomp $type if $type;
close GIT_CAT_FILE or $type = undef;
open GIT_CAT_FILE, "-|" or exec "git", "cat-file", $type, $object
or die "Failed to execute git-cat-file";
while (<GIT_CAT_FILE>)
{
chomp;
if ($do_log)
{
last if /^-----BEGIN PGP SIGNATURE-----/;
push @log, $_;
}
elsif (/^(author|committer|tagger) ((.*)(<.*>)) (\d+) ([+-]\d+)$/)
{
$info{$1} = $2;
$info{$1 . '_name'} = $3;
$info{$1 . '_email'} = $4;
$info{$1 . '_date'} = $5;
$info{$1 . '_tz'} = $6;
}
elsif (/^tag (.*)$/)
{
$info{'tag'} = $1;
}
elsif (/^$/)
{
$do_log = 1;
}
}
close GIT_CAT_FILE;
$info{'type'} = $type;
$info{'log'} = \@log;
return %info;
}
# get the default repository name
sub git_repository()
{
my $dir = `git rev-parse --git-dir`;
chomp $dir;
$dir = realpath($dir);
$dir =~ s/(.*?)((\.git\/)?\.git)$/$1/;
$dir =~ s/(.*)\/([^\/]+)\/?$/$2/;
return $dir;
}
# send a prepared commit notice to a mailinglist
sub git_send_mail($@)
{
my ($subject, @text) = @_;
$subject = encode("MIME-Q", $subject);
open SENDMAIL, "|$sendmail -t" or die "Failed to execute $sendmail";
print SENDMAIL <<EOF;
To: $notify_mailinglist
Subject: $notify_emailprefix$subject
Sender: $notify_mailinglist
Content-Type: text/plain; charset=UTF-8
EOF
print SENDMAIL "\n";
print SENDMAIL join("\n", @text);
close SENDMAIL;
}
# send a commit notice to a mailinglist
sub git_send_notice($$)
{
my ($ref, $object) = @_;
my %info = git_object_info($object);
my @notice = ();
my $subject;
if ($info{'type'} eq 'tag')
{
push @notice,
"Module: $notify_repository",
"Branch: $ref",
"Tag: $object";
if ($cgit_baseurl)
{
push @notice,
"URL: "
. "$cgit_baseurl/$notify_repository/tag/?id="
. "$object";
}
if ($gitweb_baseurl)
{
push @notice,
"URL: "
. "$gitweb_baseurl/$notify_repository/?a=tag;"
. "h=$object";
}
push @notice,
"Tagger: " .
$info{'tagger'},
"Date: "
. git_format_date($info{'tagger_date'},$info{'tagger_tz'}),
'',
join "\n", @{$info{'log'}};
$subject = "<$notify_repository:$ref> "
. 'Tag ' . $info{'tag'} . ' : '
. ${$info{'log'}}[0];
}
else
{
push @notice,
"Module: $notify_repository",
"Branch: $ref",
"Commit: $object";
if ($cgit_baseurl)
{
push @notice,
"URL: "
. "$cgit_baseurl/$notify_repository/commit/?id="
. "$object";
}
if ($gitweb_baseurl)
{
push @notice,
"URL: "
. "$gitweb_baseurl/$notify_repository/?a=commit;"
. "h=$object";
}
push @notice,
"Author: " . $info{'author'},
"Date: "
. git_format_date($info{'author_date'},$info{'author_tz'}),
'',
' ' . (join "\n ", @{$info{'log'}}),
'';
open GIT_DIFF_TREE, "-|"
or exec 'git', 'diff-tree', '--stat', '-M',
'--no-commit-id', $object
or die "Failed to execute git-diff-tree";
push @notice, join('', <GIT_DIFF_TREE>);
close GIT_DIFF_TREE;
open GIT_DIFF_TREE, "-|"
or exec 'git', 'diff-tree', '-p', '-M',
'--no-commit-id', $object,
or die "Failed to execute git-diff-tree";
push @notice, join('', <GIT_DIFF_TREE>);
close GIT_DIFF_TREE;
$subject = "<$notify_repository:$ref> "
. ${$info{'log'}}[0];
}
git_send_mail($subject, @notice);
}
# send all the notices to the mailinglist
sub git_send_all_notices($$$)
{
my ($old, $new, $ref) = @_;
$ref =~ s/^refs\/heads\///;
return if (@notify_include && !grep {$_ eq $ref} @notify_include);
# check if we have a new ref here
if ($old eq '0' x 40)
{
git_send_notice($ref, $new) if $notify_mailinglist;
return;
}
# collect commits
my @commits = ();
open GIT_REV_LIST, "-|"
or exec 'git', 'rev-list', "^$old", "$new", @notify_exclude
or die "Failed to execute git-rev-list";
while (<GIT_REV_LIST>)
{
chomp;
die "Invalid commit $_" unless /^[0-9a-f]{40}$/;
unshift @commits, $_;
}
close GIT_REV_LIST;
# send notifications for each commit
foreach my $commit (@commits)
{
git_send_notice($ref, $commit) if $notify_mailinglist;
}
}
if (@ARGV)
{
git_send_all_notices($ARGV[0], $ARGV[1], $ARGV[2]);
}
else
{
while (<>)
{
chomp;
if (/^([0-9a-f]{40}) ([0-9a-f]{40}) (.*)$/)
{
git_send_all_notices($1, $2, $3);
}
}
}
exit 0;
Jump to Line
Something went wrong with that request. Please try again.