#!/usr/bin/perl
+use strict;
+use warnings;
+
use File::Basename;
use FindBin;
use OpenSSL::Query::REST;
use Module::Load::Conditional qw(can_load);
-can_load(modules => { OpenSSL::Query::DB => undef });
+can_load(modules => { 'OpenSSL::Query::DB' => undef });
my $rmrev = 0;
-my @reviewers;
-my @nocla_reviewers;
-my @unknown_reviewers;
-my $skip_reviewer;
-my $omccount = 0;
my @commits;
my $skip = 0;
my $matchstr;
my $num = 0;
my $refuse = 0;
my $prnum = 0;
-my $trivial = 0;
+my $verbose = 0;
+my $WHAT = 'openssl';
my $query = OpenSSL::Query->new();
+my @reviewers;
+my @nocla_reviewers;
+my @unknown_reviewers;
+my $skip_reviewer;
+my $omccount = 0;
+sub try_add_reviewer {
+ my $id = lc(shift);
+ my $rc = undef;
+ my $id2 = $id =~ /^\@(.*)$/ ? { github => $1 } : $id;
+ my $rev = $query->find_person_tag($id2, 'rev');
+ if ($rev) {
+ my $cla = $query->has_cla($rev);
+ if ($cla) {
+ unless (grep {$_ eq $rev} @reviewers) {
+ $omccount++ if $query->is_member_of($id2, 'omc');
+ push @reviewers, $rev;
+ }
+ $rc = $rev;
+ } else {
+ push @nocla_reviewers, $id
+ unless grep {$_ eq $id} @nocla_reviewers;
+ }
+ } else {
+ push @unknown_reviewers, $id
+ unless grep {$_ eq $id} @unknown_reviewers;
+ unless ($id =~ m|^.+\@.*$| && $query->has_cla($id)) {
+ push @nocla_reviewers, $id
+ unless grep {$_ eq $id} @nocla_reviewers;
+ }
+ }
+ return $rc;
+}
+
foreach (@ARGV) {
if (/^--list$/) {
my %list = ();
my $rev = $query->find_person_tag($email_id, 'rev');
my $omc = $query->is_member_of($email_id, 'omc');
next unless $query->has_cla($rev);
- my @ids = sort grep { $_ =~ m|^[a-z]+$| } map {
- if (ref($_) eq "HASH") {
- values %$_;
- } else {
- $_;
- }
- } @$_;
+ next unless $query->is_member_of($email_id, 'commit') || $omc;
+ my @ids =
+ sort grep { $_ =~ /^[a-z]+$/ || $_ =~ /^\@(?:\w|\w-\w)+$/ }
+ map {
+ if (ref($_) eq "HASH") {
+ my %h = %$_;
+ map { $_ eq "github" ? '@'.$h{$_} : $h{$_} } keys %h;
+ } else {
+ $_;
+ }
+ } @$_;
foreach (@ids) {
$list{$_} = { tag => $rev, omc => $omc };
}
}
exit 0;
} elsif (/^--reviewer=(.+)$/) {
- my $rev = $query->find_person_tag($1, 'rev');
- if ($rev) {
- my $cla = $query->has_cla($rev);
- if ($cla) {
- unless (grep {$_ eq $rev} @reviewers) {
- $omccount++ if $query->is_member_of($1, 'omc');
- push @reviewers, $rev;
- }
- } else {
- push @nocla_reviewers, $1
- unless grep {$_ eq $1} @nocla_reviewers;
- }
- } else {
- push @unknown_reviewers, $1
- unless grep {$_ eq $1} @unknown_reviewers;
- }
+ try_add_reviewer($1);
} elsif (/^--prnum=(.+)$/) {
$prnum = $1;
} elsif (/^--commit=(.+)$/) {
} elsif (/^--rmreviewers$/) {
$rmrev = 1;
} elsif (/^--myemail=(.+\@.+)$/) {
- my $rev = $query->find_person_tag($1, 'rev');
- if ($rev) {
- my $cla = $query->has_cla($rev);
- if ($cla) {
- # If author doesn't match us add us as reviewer
- if ($ENV{GIT_AUTHOR_EMAIL} ne $1) {
- unless (grep {$_ eq $rev} @reviewers) {
- $omccount++ if $query->is_member_of($1, 'omc');
- push @reviewers, $rev;
- }
- } else {
- # Can't review our own commits, setup this one for removal
- $skip_reviewer = $rev;
- $omccount-- if $query->is_member_of($1, 'omc');
- }
- } else {
- push @nocla_reviewers, $1
- unless grep {$_ eq $1} @nocla_reviewers;
- }
- } else {
- push @unknown_reviewers, $1
- unless grep {$_ eq $1} @unknown_reviewers;
- }
- } elsif (/^--trivial$/) {
- $trivial = 1;
+ try_add_reviewer($1);
+ } elsif (/^--verbose$/) {
+ $verbose = 1;
+ } elsif (/^--web$/) {
+ $WHAT = 'web';
+ } elsif (/--tools$/) {
+ $WHAT = 'tools'
}
}
+
+my @commit_message = map { (my $x = $_) =~ s|\R$||; $x } <STDIN>;
+my $trivial = !! grep(/^CLA:\s*Trivial\s*$/i, @commit_message);
+
+# If the author is a registered committer, that identity passes as a reviewer
+# too. There is a twist, though... see next comment
+if (my $rev = try_add_reviewer($ENV{GIT_AUTHOR_EMAIL})) {
+
+ # So here's the deal: We added the commit author because we need to keep
+ # count of the total amount of reviewers, which includes the commit author
+ # if it's a registered committer. However, the author can "reviewed
+ # themselves", so no Reviewed-by: should be added for that identity.
+ # However, we still need to check the @reviewers count below, so the
+ # solution is to record this rev tag separately and remove it from
+ # @reviewers after the count check.
+ $skip_reviewer = $rev;
+
+} else {
+
+ # In case the author is unknown to our databases or is lacking a CLA,
+ # we need to be extra careful to check if this is supposed to be a
+ # trivial commit.
+ my $author = lc($ENV{GIT_AUTHOR_EMAIL});
+
+ # Note: it really should be enough to check if $author is unknown, since
+ # the databases are supposed to be consistent with each other. However,
+ # let's be cautious and check both, in case someone has been registered
+ # as a known identity without having a CLA in place.
+ die "Commit author ",$author," has no CLA, and this is a non-trivial commit\n"
+ if !$trivial && grep { $_ eq $author } (@nocla_reviewers);
+
+ # Now that that's cleared, remove the author from anything that could cause
+ # more unnecessary errors (false positives).
+ @nocla_reviewers = grep { $_ ne $author } @nocla_reviewers;
+ @unknown_reviewers = grep { $_ ne $author } @unknown_reviewers;
+}
+
if (@unknown_reviewers) {
die "Unknown reviewers: ", join(", ", @unknown_reviewers), "\n";
}
if (@nocla_reviewers) {
die "Reviewers without CLA: ", join(", ", @nocla_reviewers), "\n";
}
+
+print STDERR "Detected trivial marker\n" if $verbose && $trivial;
+
+print STDERR "Going with these reviewers:\n ", join("\n ", @reviewers), "\n"
+ if $verbose;
+
if (scalar @reviewers < 2) {
die "Too few reviewers (total must be at least 2)\n";
}
@nocla_reviewers = grep { $_ ne $skip_reviewer } @nocla_reviewers;
@unknown_reviewers = grep { $_ ne $skip_reviewer } @unknown_reviewers;
}
-print STDERR "DEBUG: \@reviewers = ( ", join(", ", @reviewers), " )\n";
if ($skip == 1) {
my $commit_id = $ENV{GIT_COMMIT};
die "No reviewer set!\n";
}
-my $last_line_blank = 0;
-my $have_rev = 0;
-while(<STDIN>) {
- if (/^\(Merged from https:\/\/github\.com\/openssl\/openssl\/pull\//
- || /^Reviewed-by:\s*(\S.*\S)\s*$/) {
+# Remove blank lines from the end of commit message
+pop @commit_message while $commit_message[$#commit_message] =~ m|^\s*$|;
+
+my $last_is_rev = 0;
+foreach (@commit_message) {
+ # Start each line with assuming it's not a reviewed-by line
+ $last_is_rev = 0;
+ if (/^\(Merged from https:\/\/github\.com\/openssl\/$WHAT\/pull\//) {
next if $rmrev == 1;
- $have_rev = 1;
- # Skip if reviewer already in list
- next if $1 && grep { $1 eq $_ } @reviewers;
+ $last_is_rev = 1;
+ next; # Because we're rewriting it below
+ # (unless --nopr was given in addrev)
+ } elsif (/^Reviewed-by:\s*(\S.*\S)\s*$/) {
+ my $id = $1;
+ next if $rmrev == 1;
+ $last_is_rev = 1;
+ # Remove reviewers that are already in the message from our reviewer list
+ @reviewers = grep { $_ ne $id } @reviewers;
}
- print;
- $last_line_blank = ($_ =~ /^\s*$/);
+ print $_,"\n";
}
if ($rmrev == 0) {
- #Add a blank line unless the last one is already blank or a review line
- print "\n" unless $last_line_blank || $have_rev;
+ #Add a blank line unless the last one is a review line
+ print "\n" unless $last_is_rev;
foreach(@reviewers) {
print "Reviewed-by: $_\n";
}
- if ($trivial) {
- print "CLA: trivial\n";
- }
}
-print "(Merged from https://github.com/openssl/openssl/pull/$prnum)\n"
+print "(Merged from https://github.com/openssl/$WHAT/pull/$prnum)\n"
if $prnum;
-
-my $email = $ENV{GIT_AUTHOR_EMAIL};
-
-if (!$trivial && !$query->has_cla(lc $email)) {
- warn "\n\nWARNING: No CLA found for $email\n";
-}