summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Weiss <holger@zedat.fu-berlin.de>2009-10-24 22:55:44 +0200
committerHolger Weiss <holger@zedat.fu-berlin.de>2009-10-24 22:55:44 +0200
commitaf5e252846d08a579835e9b3bd0b004727252850 (patch)
tree76c6731a465f5a87697096f7e95a58861f136da3
parenta6b329689782ddd22b4ecd52d0b375e0841ca682 (diff)
downloadmonitoring-plugins-af5e252846d08a579835e9b3bd0b004727252850.tar.gz
git-notify: Don't generate duplicate notifications
Never notify on a given commit more than once, even if it's referenced via multiple branch heads. We make sure this won't happen simply by maintaining a list of commits we notified about. The file path used for saving this list can be specified using the new "-t" option. (The contrib/hooks/post-receive-email script distributed with Git tries hard to avoid such a list, but it doesn't get the necessary magic right.)
-rwxr-xr-xtools/git-notify61
1 files changed, 61 insertions, 0 deletions
diff --git a/tools/git-notify b/tools/git-notify
index a158e872..a89104a6 100755
--- a/tools/git-notify
+++ b/tools/git-notify
@@ -3,6 +3,7 @@
3# Tool to send git commit notifications 3# Tool to send git commit notifications
4# 4#
5# Copyright 2005 Alexandre Julliard 5# Copyright 2005 Alexandre Julliard
6# Copyright 2009 Nagios Plugins Development Team
6# 7#
7# This program is free software; you can redistribute it and/or 8# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License as 9# modify it under the terms of the GNU General Public License as
@@ -19,6 +20,7 @@
19# -n max Set max number of individual mails to send 20# -n max Set max number of individual mails to send
20# -r name Set the git repository name 21# -r name Set the git repository name
21# -s bytes Set the maximum diff size in bytes (-1 for no limit) 22# -s bytes Set the maximum diff size in bytes (-1 for no limit)
23# -t file Set the file to use for reading and saving state
22# -u url Set the URL to the gitweb browser 24# -u url Set the URL to the gitweb browser
23# -i branch If at least one -i is given, report only for specified branches 25# -i branch If at least one -i is given, report only for specified branches
24# -x branch Exclude changes to the specified branch from reports 26# -x branch Exclude changes to the specified branch from reports
@@ -27,6 +29,7 @@
27 29
28use strict; 30use strict;
29use open ':utf8'; 31use open ':utf8';
32use Fcntl ':flock';
30use Encode 'encode'; 33use Encode 'encode';
31use Cwd 'realpath'; 34use Cwd 'realpath';
32 35
@@ -76,6 +79,9 @@ my @include_list = split /\s+/, git_config( "notify.include" ) || "";
76# branches to exclude 79# branches to exclude
77my @exclude_list = split /\s+/, git_config( "notify.exclude" ) || ""; 80my @exclude_list = split /\s+/, git_config( "notify.exclude" ) || "";
78 81
82# the state file we use (can be changed with the -t option)
83my $state_file = git_config( "notify.statefile" ) || "/var/tmp/git-notify.state";
84
79# Extra options to git rev-list 85# Extra options to git rev-list
80my @revlist_options; 86my @revlist_options;
81 87
@@ -87,6 +93,7 @@ sub usage()
87 print " -n max Set max number of individual mails to send\n"; 93 print " -n max Set max number of individual mails to send\n";
88 print " -r name Set the git repository name\n"; 94 print " -r name Set the git repository name\n";
89 print " -s bytes Set the maximum diff size in bytes (-1 for no limit)\n"; 95 print " -s bytes Set the maximum diff size in bytes (-1 for no limit)\n";
96 print " -t file Set the file to use for reading and saving state\n";
90 print " -u url Set the URL to the gitweb browser\n"; 97 print " -u url Set the URL to the gitweb browser\n";
91 print " -i branch If at least one -i is given, report only for specified branches\n"; 98 print " -i branch If at least one -i is given, report only for specified branches\n";
92 print " -x branch Exclude changes to the specified branch from reports\n"; 99 print " -x branch Exclude changes to the specified branch from reports\n";
@@ -127,6 +134,59 @@ sub git_rev_list(@)
127 return $revlist; 134 return $revlist;
128} 135}
129 136
137# append the given commit hashes to the state file
138sub save_commits($)
139{
140 my $commits = shift;
141
142 open STATE, ">>", $state_file or die "Cannot open $state_file: $!";
143 flock STATE, LOCK_EX or die "Cannot lock $state_file";
144 print STATE "$_\n" for @$commits;
145 flock STATE, LOCK_UN or die "Cannot unlock $state_file";
146 close STATE or die "Cannot close $state_file: $!";
147}
148
149# for the given range, return the new hashes and append them to the state file
150sub get_new_commits($$)
151{
152 my ($old_sha1, $new_sha1) = @_;
153 my ($seen, @args);
154 my $newrevs = [];
155
156 @args = ( "^$old_sha1" ) unless $old_sha1 eq '0' x 40;
157 push @args, $new_sha1, @exclude_list;
158
159 my $revlist = git_rev_list(@args);
160
161 if (not -e $state_file) # initialize the state file with all hashes
162 {
163 save_commits(git_rev_list("--all", "--full-history"));
164 return $revlist;
165 }
166
167 open STATE, $state_file or die "Cannot open $state_file: $!";
168 flock STATE, LOCK_SH or die "Cannot lock $state_file";
169 while (<STATE>)
170 {
171 chomp;
172 die "Invalid commit: $_" if not /^[0-9a-f]{40}$/;
173 $seen->{$_} = 1;
174 }
175 flock STATE, LOCK_UN or die "Cannot unlock $state_file";
176 close STATE or die "Cannot close $state_file: $!";
177
178 # FIXME: if another git-notify process reads the $state_file at *this*
179 # point, that process might generate duplicates of our notifications.
180
181 save_commits($revlist);
182
183 foreach my $commit (@$revlist)
184 {
185 push @$newrevs, $commit unless $seen->{$commit};
186 }
187 return $newrevs;
188}
189
130# truncate the given string if it exceeds the specified number of characters 190# truncate the given string if it exceeds the specified number of characters
131sub truncate_str($$) 191sub truncate_str($$)
132{ 192{
@@ -217,6 +277,7 @@ sub parse_options()
217 elsif ($arg eq '-n') { $max_individual_notices = shift @ARGV; } 277 elsif ($arg eq '-n') { $max_individual_notices = shift @ARGV; }
218 elsif ($arg eq '-r') { $repos_name = shift @ARGV; } 278 elsif ($arg eq '-r') { $repos_name = shift @ARGV; }
219 elsif ($arg eq '-s') { $max_diff_size = shift @ARGV; } 279 elsif ($arg eq '-s') { $max_diff_size = shift @ARGV; }
280 elsif ($arg eq '-t') { $state_file = shift @ARGV; }
220 elsif ($arg eq '-u') { $gitweb_url = shift @ARGV; } 281 elsif ($arg eq '-u') { $gitweb_url = shift @ARGV; }
221 elsif ($arg eq '-i') { push @include_list, shift @ARGV; } 282 elsif ($arg eq '-i') { push @include_list, shift @ARGV; }
222 elsif ($arg eq '-x') { push @exclude_list, shift @ARGV; } 283 elsif ($arg eq '-x') { push @exclude_list, shift @ARGV; }