Skip to content

Commit cf8716f

Browse files
author
Nigel Metheringham
committed
Initial version of the git/bugzilla script
0 parents  commit cf8716f

File tree

2 files changed

+187
-0
lines changed

2 files changed

+187
-0
lines changed

config.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
# YAML config
3+
#
4+
git_dir: /Users/nigel/Tasks/exim/exim/.git
5+
exludehead:
6+
lasttag: .bug_last_commit
7+
gitweb: http://git.exim.org/exim.git
8+
bugzilla:
9+
server: http://bugs.exim.org/
10+
user: git
11+
pass: pass

script/git-to-bugzilla.pl

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#!/usr/bin/env perl
2+
#
3+
#
4+
use strict;
5+
use warnings;
6+
use Carp;
7+
use Config::Any;
8+
use Data::Dump;
9+
use File::Slurp;
10+
use FindBin;
11+
use Getopt::Long;
12+
use Git::Repository;
13+
14+
use lib "$FindBin::Bin/../lib";
15+
use WWW::Bugzilla;
16+
17+
my $verbose;
18+
my $debug;
19+
20+
# ------------------------------------------------------------------------
21+
sub update_bugzilla {
22+
my $cfg = shift;
23+
my $info = shift;
24+
my $set = shift;
25+
26+
my $bz = WWW::Bugzilla->new(
27+
server => $cfg->{bugzilla}{server},
28+
email => $cfg->{bugzilla}{user},
29+
password => $cfg->{bugzilla}{pass},
30+
bug_number => $set->{bug}
31+
) || croak "Cannot open bz - $!";
32+
33+
my $header = sprintf( "Git commit: %s/commitdiff/%s\n", $cfg->{gitweb}, $info->{rev} );
34+
if ( scalar( @{ $info->{diff} } ) > 50 ) {
35+
36+
# big diff - we skip the diff
37+
$bz->additional_comments(
38+
join( "\n", $header, @{ $info->{info} }, '', @{ $info->{log} }, '----', @{ $info->{diffstat} } ) );
39+
}
40+
else {
41+
42+
# otherwise we do the whole thing
43+
$bz->additional_comments( join( "\n", $header, @{ $info->{all} } ) );
44+
}
45+
46+
$bz->change_status("fixed") if ( $set->{action} eq 'fixes' );
47+
$bz->change_status("closed") if ( $set->{action} eq 'closes' );
48+
49+
$bz->commit;
50+
51+
printf( "[%d] %s %s [%s]\n", $set->{bug}, $info->{rev}, $info->{log}[0], $set->{action} );
52+
}
53+
54+
# ------------------------------------------------------------------------
55+
sub find_bugzilla_references {
56+
my $info = shift;
57+
my $cfg = shift;
58+
59+
my @results;
60+
my $action = '';
61+
my $bugid;
62+
foreach my $line ( @{ $info->{log} } ) {
63+
$line = lc($line);
64+
if ( $line =~ /(closes|fixes|references):?\s*(?:bug(?:zilla)?)?\s*\#?(\d+)/ ) {
65+
$action = $1;
66+
$bugid = $2;
67+
}
68+
elsif ( $line =~ /\b(?:bug(?:zilla)?)\s*\#?(\d+)/ ) {
69+
$action = 'references';
70+
$bugid = $1;
71+
}
72+
else {
73+
next;
74+
}
75+
76+
# remap actions
77+
$action = 'closes' if ( $action =~ /^fix/ );
78+
79+
push( @results, { bug => $bugid, action => $action } );
80+
##printf( "%s\n\taction = %s bugid = %s\n", $info->{rev}, $action, $bugid );
81+
}
82+
return @results;
83+
}
84+
85+
# ------------------------------------------------------------------------
86+
87+
sub git_commit_info {
88+
my $git = shift;
89+
my $rev = shift;
90+
91+
my @lines = $git->run( 'show', '-M', '-C', '--patch-with-stat', '--pretty=fuller', $rev );
92+
93+
my $info = {
94+
rev => $rev,
95+
info => [],
96+
log => [],
97+
diffstat => [],
98+
diff => [],
99+
all => [@lines], # deliberate copy
100+
};
101+
102+
while ( my $line = shift @lines ) {
103+
last if ( $line =~ /^$/ );
104+
push( @{ $info->{info} }, $line );
105+
}
106+
107+
while ( my $line = shift @lines ) {
108+
last if ( $line =~ /^---\s*$/ );
109+
push( @{ $info->{log} }, $line );
110+
}
111+
112+
while ( my $line = shift @lines ) {
113+
last if ( $line =~ /^$/ );
114+
push( @{ $info->{diffstat} }, $line );
115+
}
116+
117+
# all the rest
118+
$info->{diff} = \@lines;
119+
120+
return $info;
121+
}
122+
123+
# ------------------------------------------------------------------------
124+
125+
sub walk_git_commits {
126+
my $git = shift;
127+
my $cfg = shift;
128+
129+
my $lastrev = $git->run( 'rev-parse', $cfg->{lastref} );
130+
my $headrev = $git->run( 'rev-parse', $cfg->{branch_head} );
131+
132+
return if ( $lastrev eq $headrev );
133+
134+
my @revs = $git->run( 'rev-list', '--topo-order', '--no-merges', ( $lastrev . '..' . $headrev ) );
135+
136+
foreach my $rev ( reverse(@revs) ) {
137+
my $info = git_commit_info( $git, $rev );
138+
139+
#ddx($info);
140+
#dd( $info->{info}, $info->{log}[0] );
141+
my @sets = find_bugzilla_references( $info, $cfg );
142+
foreach my $set (@sets) {
143+
update_bugzilla( $cfg, $info, $set );
144+
}
145+
}
146+
return $headrev;
147+
}
148+
149+
# ------------------------------------------------------------------------
150+
151+
# main
152+
{
153+
my $config;
154+
155+
GetOptions(
156+
'config=s' => \$config,
157+
'debug!' => \$debug,
158+
'verbose!' => \$verbose,
159+
) or die "Incorrect options";
160+
die "No config file given\n" unless ( $config and -f $config );
161+
my $cfg = ( values( %{ Config::Any->load_files( { files => [$config], use_ext => 1 } )->[0] } ) )[0];
162+
163+
die "No git_dir specified\n" unless ( $cfg->{git_dir} );
164+
$cfg->{lasttag} ||= $cfg->{git_dir} . '/refs/tags/BugzillaDone';
165+
$cfg->{branch_head} ||= 'HEAD';
166+
167+
$cfg->{lastref} = -f $cfg->{lasttag} ? read_file( $cfg->{lasttag} ) : 'HEAD';
168+
chomp( $cfg->{lastref} );
169+
170+
my $git = Git::Repository->new( git_dir => $cfg->{git_dir} ) || die "No valid git repo\n";
171+
172+
my $newlast = walk_git_commits( $git, $cfg );
173+
if ($newlast) {
174+
write_file( $cfg->{lasttag}, $newlast );
175+
}
176+
}

0 commit comments

Comments
 (0)