Skip to content

Instantly share code, notes, and snippets.

@realdadfish
Last active August 29, 2015 14:03
Show Gist options
  • Save realdadfish/3cd8ca0778eb20026587 to your computer and use it in GitHub Desktop.
Save realdadfish/3cd8ca0778eb20026587 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
#
# ATTENTION: In addition to Net::Jabber you also need to apply
# this patch http://toroid.org/ams/etc/net-xmpp-virtualhost-support
# to let this script connect to a jabber server independent from
# the domain you gave it.
#
# Then, symlink this script in each git repository you want to
# receive notifications for (i.e. ln -s path/to/post-receive.pl repo.git/hooks/post-receive)
# and configure the branches (".*" as catch-all works) and chat ID
# like this:
#
# git config hooks.notify.repo 'some identifier'
# git config hooks.notify.branches 'master next'
# git config hooks.notify.chat '[email protected]'
#
# Thats it, have fun.
# Thomas.
#
# Author: Thomas Keller <[email protected]>
# Original author: Abhijit Menon-Sen <[email protected]>
#
use Net::Jabber;
my $servername = '<server-name-or-ip>';
my $JID = '<jabber-id>';
my $password = '<password>';
# cut off large commit messages after so many characters
my $charlimit = 1000;
# only report so and so many commits per ref at once
my $commitlimit = 5;
my $repo = qx(git config hooks.notify.repo);
chomp $repo;
my @branches = split /,*\s+/, qx(git config hooks.notify.branches);
my $chat = qx(git config hooks.notify.chat);
chomp $chat;
my $branches = join( "|", @branches ) || "master";
# Read "oldsha1 newsha1 refname" lines from stdin and convert the
# relevant ones into summary messages.
my @changes;
while ( <> ) {
chomp;
my ( $old, $new, $ref ) = split / /;
$ref =~ s!refs/heads/!!;
next unless $ref =~ /$branches/;
# skip branch deletions
next if $new =~ /0{40}/;
my $range = "$old..$new";
# new refs are pushed with zero'd $old and that doesn't like git log
$range = "-1 $new" if $old =~ /0{40}/;
my $s = qx(git log --no-merges --reverse --find-copies-harder --raw $range);
$s =~ s/^:.*?(\w+\t)/$1/gsm;
push @changes, [ $ref, $s ];
}
exit unless @changes;
# since we need to send messages slowly to servers like ejabberd
# to avoid having parts of them eaten up, we fork and exit here
# so the pushing user doesn't have to wait for us.
fork and exit;
# Send the notification messages to each recipient.
my ( $username, $hostname ) = split /@/, $JID;
my ( $chatroom, $chatdomain) = split /@/, $chat;
my $client = new Net::Jabber::Client ();
$client->Connect( hostname => $hostname, servername => $servername, srv => '_xmpp-client._tcp' )
or die "Cannot connect to jabber server for $hostname ($servername): $!\n";
my @r = $client->AuthSend(
username => $username,
password => $password,
resource => "gitguy"
);
die "Cannot authenticate as $JID (@r)\n" if $r[0] ne "ok";
$client->MUCJoin(
room => $chatroom,
server => $chatdomain,
nick => "gitguy"
);
foreach my $c ( @changes ) {
my ( $ref, $s ) = @$c;
sendMessage($client, $chat, "Changes pushed to branch $repo/$ref");
my @commits = split /(?=\n\ncommit)/, $s;
for my $i (0 .. $commitlimit - 1) {
$cm = $commits[$i];
$cm =~ s/^\s+|\s+$//g;
$cm = substr($cm, 0, $charlimit) . "..." if length($cm) > $charlimit;
sendMessage($client, $chat, $cm);
}
$left = $#commits - $commitlimit;
if ($left > 0) {
sendMessage($client, $chat, "($left more commits not shown)");
}
}
$client->Disconnect();
sub sendMessage {
$client = $_[0];
$chat = $_[1];
$text = $_[2];
my $msg = new Net::Jabber::Message ();
$msg->SetMessage(
type => 'groupchat',
to => $chat,
body => $text
);
$client->Send( $msg );
# wait time after each message send 0.5s
# couldn't get more messages through reliably
# with a value below this
select(undef, undef, undef, 0.5);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment