#!/usr/bin/perl 

#The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
# 
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
# 
# svn_bz_hook.pl
#
# Written by Niko Efthymiou <nefthy at option-it.de> 
# Based svn_bz_append.pl by Toby Thain and Matthew Curry and the Bugzilla 
# source itself.
#
#
# Installation: 
#
# edit $SVNLOOK and $BZDIR below to point to the right places
# make an executable file in you repository hook dir (/var/svn/test/hooks/ or
# something) that is called post-commit it should look something like this
#
# #!/bin/sh
# exec /path/to/svn_bz_hook.pl "$1" "$2"
#
# you will also need to modify the Bugzilla userid/login_name lookup (marked FIXME).
#
#
# Usage:
#
# just write #<bug_number> at the start of a line in yout commit log and
# everithing following until the end of the log or the next #<bug_number> at
# the start of a line is added as a comment for that bug number in Bugzilla
#
# if you use fixed #<bug_number> instead, the bug will also be marked fixed.
#
# if the is anything before the first #<bug_number> / fixed #<bug_number> it is
# added to each bug.
#
# if no #<bug_number> or fixed #<bug_number> is found at the start of a line. 
# Nothing unusual happens.
#
#
# If you like this and meet me one day, by me a Beer :)
use strict;
use warnings;


BEGIN {
	my $BZDIR = "/var/www/localhost/bugzilla3/";
	chdir "$BZDIR" or die("chdir to $BZDIR failed." );
	push @INC, "contrib";
	push @INC, "."; 
}

my $SVNLOOK = "/usr/bin/svnlook";

use Bugzilla;
use Bugzilla::Config;
use Bugzilla::Util;
use Bugzilla::Bug;
use Bugzilla::BugMail;
use Bugzilla::Flag;
my $username = 'nefthy@option-it.de';

die "usage: ",__FILE__," REPO_PATH REVISION" unless $#ARGV > 0;

my ($repo,$rev) = @ARGV;

# Find Bugzilla login from Svn committer user name.
chop(my $author = `$SVNLOOK author $repo -r $rev`);

# FIXME You will probably need to customise this for your site.
my @rec = Bugzilla->dbh->selectrow_array("SELECT login_name,userid FROM profiles \
         WHERE login_name LIKE \'$author%\';");

my $login_name = shift @rec;
my $userid = shift @rec;

if (!defined($login_name) or !defined($userid)) {
   die("Bugzilla login_name not found for $author")
}


# set the bugzilla user else nothing works...
my $user = Bugzilla::User->new({ name => $username })
    || die('could not create Bugzilla::User object for ' . $username); 

Bugzilla->set_user($user) || die("failed to set user");

my $message_revision = "$repo rev $rev committed by $author\n";

my @bugs;
my $log = `$SVNLOOK log $repo -r $rev`;

my $message_changed_files = "\n" . `$SVNLOOK changed $repo -r $rev`;

my @lines = split("\n", $log);  
my $cur_bug = 0;
my %bugs;
my %fixed;
foreach my $line (@lines) {
	if ($line =~ /^(fixed\s*)?#(\d+)\s*(.*)/) {
		$cur_bug = $2;
		if (defined $1) {
			$fixed{$cur_bug} = 1;
		}
		if (defined $3) {
			$bugs{$cur_bug} .= $3."\n";
		}
	} else {
		$bugs{$cur_bug} .= $line . "\n";
	}
}

my $message_common = "";
if (defined $bugs{0}) {
	$message_common = $bugs{0};
	delete $bugs{0};
} 

my $failed = 0;
BUG: while ((my $bug_id, my $message_comment) = each(%bugs)) {
	my $message = "";
	$message_common =~ s/^\s*//;
	$message_common =~ s/\s*$//;
	
	if ("" ne $message_common) {
		$message .= $message_common . "\n--\n";
	}
	$message .= $message_comment . "--\n" 
		. $message_revision . "" . $message_changed_files;
	
	#fetch the bug
	my $bug = Bugzilla::Bug->check($bug_id);
	if (!defined $bug) {
		$failed = 1;
		print "Bug #$bug_id not found.";
		die("here");
		next BUG;
	}
	Bugzilla->dbh->bz_start_transaction();
	my $timestamp = Bugzilla->dbh->selectrow_array(q{SELECT NOW()});
	
	#add comment and change status
	$bug->add_comment($message);
	if ($fixed{$bug_id}) {
		#found fixed #<bug_number> so resolve it as fixed
		$bug->set_status('RESOLVED', {resolution => 'FIXED' });
	}

	#do the updating
	my $changes = $bug->update();
	Bugzilla::Flag->process($bug, undef, $timestamp, undef);
	Bugzilla->dbh->bz_commit_transaction();

	#do some voodoo to send the email...
    my $old_qa  = $changes->{'qa_contact'}  ? $changes->{'qa_contact'}->[0] : '';
    my $old_own = $changes->{'assigned_to'} ? $changes->{'assigned_to'}->[0] : '';
    my $old_cc  = $changes->{cc}            ? $changes->{cc}->[0] : '';
	my $recipients = {
        cc        => [split(/[\s,]+/, $old_cc)],
        owner     => $old_own,
        qacontact => $old_qa,
        changer   => Bugzilla->user->login 
	};

	Bugzilla::BugMail::Send($bug_id, $recipients);
}
exit($failed);
