util/release: Update gerrit_stats script to latest version

This updates a number of things:
- Move the cache directory under the .local directory
- Reformat & clean up with perltidy.  Add the perltidy command line.
- Add username and email aliases to clean up duplicates and unknown
  email addresses.
- Use full length commit IDs
- Collect patch commenters
- Check variables before using them as key values
- Ignore patch submit time, just collect the date
- Get stats about large patches
- Format the output better

Example output:
Statistics from commit c35f281934 to commit f8fbf0917c
Patch, Date, Owner, Author, Submitter, Inserted lines, Deleted lines, Subject, Reviewers, Commenters
"f8fbf0917c722378454b07c2e8ec1a3f87b324ae", 2022/12/10, Frank Chu, Frank Chu, Martin Roth, 22, 1, "mb/google/brya/var/marasov: Change FSP board type to Type3", "Frank Chu, Eric Lai" , "-"
"5778e06771627a5541ca2b137e783f47257f05ec", 2022/12/10, Dinesh Gehlot, Dinesh Gehlot, Subrata Banik, 30, 1, "soc/intel/meteorlake: Drop casts around `soc_read_pmc_base()`", "Kapil Porwal, Elyes Haouas" , "Subrata Banik"
"ed8bdefcdf6c19258febb9931d1e8eb12b958bcc", 2022/12/10, Jamie Ryu, Jamie Ryu, Felix Held, 76, 3, "mb/intel/mtlrvp: Add MTL-P RVP board ids", "Usha P,
Sridhar Siricilla, Eric Lai, Subrata Banik" , "Eric Lai, Subrata Banik, Harsha B R, Angel Pons"

- Total Commits: 985
- Average Commits per day: 17.85
- Total lines added: 61475
- Average lines added per commit: 62.41
- Number of patches adding more than 100 lines: 49
- Average lines added per small commit: 37.82
- Total lines removed: 758022
- Average lines removed per commit: 769.57
- Total difference between added and removed: -696547

=== Authors - Number of commits ===
Author                         ,Ptchs ,Revws , Cmnts , Sbmts , Email                                                , Prcnt, Last commit         ,
Earliest_commit
Elyes Haouas                   ,  126 ,   90 ,    28 ,     0 , ehaouas@noos.fr                                      ,12.79%, 2022/12/10 , 2022/10/17
Arthur Heymans                 ,  107 ,   99 ,    28 ,    40 , arthur@aheymans.xyz                                  ,10.86%, 2022/12/10 , 2022/10/17

=== Authors - Lines added ===
Martin Roth                   ,      10103, 16.434%
Kyösti Mälkki                 ,       6044, 9.832%
Arthur Heymans                ,       3314, 5.391%

=== Authors - Lines removed ===
Arthur Heymans                ,    -741944, 97.879%
Felix Held                    ,      -3031,  0.400%
Kyösti Mälkki                 ,      -1680,  0.222%

=== Reviewers - Number of patches reviewed ===
Angel Pons                    ,    272, 27.614%
Eric Lai                      ,    201, 20.406%
Felix Held                    ,    106, 10.761%

=== Submitters - Number of patches submitted ===
Name                          ,      #,  total%,    Own,    own%,  Other,  other%
Felix Held                    ,    482, 48.934%,     56,  11.62%,    426,  88.38%
Martin Roth                   ,    179, 18.173%,     42,  23.46%,    137,  76.54%
Subrata Banik                 ,     54,  5.482%,     31,  57.41%,     23,  42.59%

Signed-off-by: Martin Roth <gaumless@gmail.com>
Change-Id: Ie1694116ab36ca4db25d13935adadca10e50068f
Reviewed-on: https://review.coreboot.org/c/coreboot/+/70572
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Felix Singer <felixsinger@posteo.net>
This commit is contained in:
Martin Roth 2022-12-10 22:00:40 -07:00 committed by Martin Roth
parent a6514e2b1f
commit ae7d8379a5
1 changed files with 390 additions and 131 deletions

View File

@ -8,6 +8,8 @@ package gerrit_stats;
# sudo cpan App::cpanminus # sudo cpan App::cpanminus
# sudo /usr/local/bin/cpanm JSON::Util Net::OpenSSH DateTime Devel::Size # sudo /usr/local/bin/cpanm JSON::Util Net::OpenSSH DateTime Devel::Size
# perltidy -l=200 -bt=2 -ce
use strict; use strict;
use warnings; use warnings;
use English qw( -no_match_vars ); use English qw( -no_match_vars );
@ -23,7 +25,7 @@ use Devel::Size qw(size total_size);
my $old_version; my $old_version;
my $new_version; my $new_version;
my $infodir="$ENV{'HOME'}/.commit_info/" . `git config -l | grep remote.origin.url | sed 's|.*@||' | sed 's|:.*||'`; my $infodir = "$ENV{'HOME'}/.local/commit_info/" . `git config -l | grep remote.origin.url | sed 's|.*@||' | sed 's|:.*||'`;
chomp($infodir); chomp($infodir);
my $URL_WITH_USER; my $URL_WITH_USER;
my $SKIP_GERRIT_CHECK; my $SKIP_GERRIT_CHECK;
@ -45,6 +47,7 @@ sub Main {
my %authors = (); my %authors = ();
my %owners = (); my %owners = ();
my %reviewers = (); my %reviewers = ();
my %commenters = ();
my %author_added = (); my %author_added = ();
my %author_removed = (); my %author_removed = ();
my $total_added = 0; my $total_added = 0;
@ -53,15 +56,109 @@ sub Main {
my $number_of_submitters = 0; my $number_of_submitters = 0;
my $submit_epoch = ""; my $submit_epoch = "";
my $first_submit_epoch = ""; my $first_submit_epoch = "";
my $patches_over_100_lines = 0;
my $total_lines_large_patches = 0;
my %email_addresses = (
'Kacper Stojek' => 'kacper.stojek@3mdeb.com',
'Damien Zammit' => 'damien@zamaudio.com',
'Pavel Sayekat' => 'pavelsayekat@gmail.com',
'Lance Zhao' => 'lance.zhao@gmail.com',
);
my %aliases = (
' Felix Singer' => 'Felix Singer',
'Abhay kumar' => 'Abhay Kumar',
'AlexandruX Gagniuc' => 'Alexandru Gagniuc',
'Anish K. Patel' => 'Anish K Patel',
'Bao Zheng' => 'Zheng Bao',
'Bernhard M. Wiedemann' => 'Bernhard M. Wiedermann',
'Björn Busse' => 'Bjarn Busse',
'BryantOu' => 'Bryant Ou',
'Chen Wisley' => 'Wisley Chen',
'Cheng-Yi Chiang' => 'Jimmy Cheng-Yi Chiang',
'Chris Ching (using chromium account)' => 'Chris Ching,',
'ChromeOS Developer' => 'Dave Parker',
'Cristi M' => 'Cristian Magherusan-Stanciu',
'Cristian M?gheru?an-Stanciu' => 'Cristian Magherusan-Stanciu',
'Cristian MÄgheruÈan-Stanciu' => 'Cristian Magherusan-Stanciu',
'Cristian MÄgheruÈan-Stanciu' => 'Cristian Magherusan-Stanciu',
'DAWEI CHIEN' => 'Dawei Chien',
'efdesign98' => 'Frank Vibrans',
'Eugene D. Myers' => 'Eugene Myers',
'Frank Vibrans III' => 'Frank Vibrans',
'frank vibrans' => 'Frank Vibrans',
'Frank.Vibrans' => 'Frank Vibrans',
'FrankChu' => 'Frank Chu',
'garmin chang' => 'Garmin Chang',
'Garmin.Chang' => 'Garmin Chang',
'hannahwilliams2' => 'Hannah Williams',
'HAOUAS Elyes' => 'Elyes Haouas',
'Harshapriya N' => 'Harsha Priya',
'Hsuan-ting Chen' => 'Hsuan Ting Chen',
'Iru Cai (vimacs)' => 'Iru Cai',
'Jérémy Compostella' => 'Jeremy Compostella',
'Jérémy Compostella' => 'Jeremy Compostella',
'JG Poxu' => 'Po Xu',
'JonathonHall-Purism' => 'Jonathon Hall',
'Karthikeyan Ramasubramanian' => 'Karthik Ramasubramanian',
'Kerry She' => 'Kerry Sheh',
'kewei.xu' => 'kewei xu',
'Kumar, Gomathi' => 'Gomathi Kumar',
'Kyösti Mälkki' => 'Kyösti Mälkki',
'Kyösti Mälkki' => 'Kyösti Mälkki',
'Marcello Sylvester Bauer' => 'Marcello Sylvester Bauer',
'Martin L Roth' => 'Martin Roth',
'Martin Roth - Personal' => 'Martin Roth',
'Matt Ziegelbaum' => 'Matthew Ziegelbaum',
'mengqi.zhang' => 'Mengqi Zhang',
'mrnuke' => 'Alexandru Gagniuc',
'Nina-CM Wu' => 'Nina Wu',
'ot_zhenguo.li' => 'Zhenguo Li',
'Patrick Georgi patrick.georgi' => 'Patrick Georgi',
'Patrick Georgi patrick' => 'Patrick Georgi',
'Pavlushka' => 'Pavel Sayekat',
'Ravi Kumar Bokka' => 'Ravi Kumar',
'Ravi kumar' => 'Ravi Kumar',
'Ravi Sarawadi' => 'Ravishankar Sarawadi',
'ravindr1' => 'Ravindra',
'Ravindra N' => 'Ravindra',
'Ricardo Ribalda Delgado' => 'Ricardo Ribalda',
'ron minnich' => 'Ron Minnich',
'Ronald G. Minnich' => 'Ron Minnich',
'samrab' => 'Sudheer Amrabadi',
'SANTHOSH JANARDHANA HASSAN' => 'Santhosh Janardhana Hassan',
'semihalf-czapiga-jakub' => 'Jakub Czapiga',
'Seunghwan Kim' => 'SH Kim',
'Sooi, Li Cheng' => 'Li Cheng Sooi',
'Stefan Reinauerstepan' => 'Stefan Reinauer',
'stepan' => 'Stefan Reinauer',
'Swift Geek (Sebastian Grzywna)' => 'Sebastian "Swift Geek" Grzywna',
'Sylvain "ythier" Hitier' => 'Sylvain Hitier',
'Thomas Gstädtner' => 'Thomas Gstaedtner',
'UwePoeche' => 'Uwe Poeche',
'UwePoeche' => 'Uwe Poeche',
'Varshit Pandya' => 'Varshit B Pandya',
'Wayne3 Wang' => 'Wayne Wang',
'Wayne3_Wang' => 'Wayne Wang',
'Xi Chen' => 'Xixi Chen',
'Yu-Hsuan Hsu' => 'Yu-hsuan Hsu',
'zbao' => 'Zheng Bao',
'Zheng Bao zheng.bao' => 'Zheng Bao',
'zhiyong tao' => 'Zhiyong Tao',
'Дмитрий Понаморев' => 'Dmitry Ponamorev',
);
if ( !$URL_WITH_USER ) { if ( !$URL_WITH_USER ) {
get_user() get_user();
} }
# make sure the versions exist print "Saving data to $infodir\n";
# Make sure the versions exist
check_versions(); check_versions();
#fetch patches if needed. Get ids of first and last commits # Fetch patches if needed. Get ids of first and last commits
my @commits = `git log --pretty=%h "$old_version..$new_version" 2>/dev/null`; my @commits = `git log --pretty=%H "$old_version..$new_version" 2>/dev/null`;
get_commits(@commits); get_commits(@commits);
my $last_commit_id = $commits[0]; my $last_commit_id = $commits[0];
my $first_commit_id = $commits[ @commits - 1 ]; my $first_commit_id = $commits[ @commits - 1 ];
@ -69,14 +166,15 @@ sub Main {
chomp $first_commit_id; chomp $first_commit_id;
print "Statistics from commit $first_commit_id to commit $last_commit_id\n"; print "Statistics from commit $first_commit_id to commit $last_commit_id\n";
print "Patch, Date, Owner, Author, Submitter, Inserted lines, Deleted lines, Subject, Reviewers\n"; print "Patch, Date, Owner, Author, Submitter, Inserted lines, Deleted lines, Subject, Reviewers, Commenters\n";
#loop through all commits # Loop through all commits
for my $commit_id (@commits) { for my $commit_id (@commits) {
$commit_id =~ s/^\s+|\s+$//g; $commit_id =~ s/^\s+|\s+$//g;
my $submitter = ""; my $submitter = "";
my %patch_reviewers = (); my %patch_reviewers = ();
my %patch_commenters = ();
my $info; my $info;
my $owner; my $owner;
my $author; my $author;
@ -88,7 +186,7 @@ sub Main {
$number_of_commits++; $number_of_commits++;
print "\"$commit_id\", "; print "\"$commit_id\", ";
#read the data file for the current commit # Read the data file for the current commit
if ( -f "$infodir/$commit_id" && -s "$infodir/$commit_id" > 20 ) { if ( -f "$infodir/$commit_id" && -s "$infodir/$commit_id" > 20 ) {
open( my $HANDLE, "<", "$infodir/$commit_id" ) or die "Error: could not open file '$infodir/$commit_id'\n"; open( my $HANDLE, "<", "$infodir/$commit_id" ) or die "Error: could not open file '$infodir/$commit_id'\n";
$info = <$HANDLE>; $info = <$HANDLE>;
@ -96,20 +194,26 @@ sub Main {
my $commit_info = JSON::Util->decode($info); my $commit_info = JSON::Util->decode($info);
#get the easy data # Get the easy data
$owner = $commit_info->{'owner'}{'name'}; $owner = $commit_info->{'owner'}{'name'};
if ( !$owner ) { if ( !$owner ) {
$owner = $commit_info->{'owner'}{'username'}; $owner = $commit_info->{'owner'}{'username'};
} }
if ( !$owner ) { if ( !$owner ) {
$owner = ""; $owner = "-";
} }
if ( $owner && exists( $aliases{$owner} ) ) {
$owner = $aliases{$owner};
}
$author = $commit_info->{'currentPatchSet'}{'author'}{'name'}; $author = $commit_info->{'currentPatchSet'}{'author'}{'name'};
$author_email = $commit_info->{'currentPatchSet'}{'author'}{'email'}; if ( $author && exists( $aliases{$author} ) ) {
$author = $aliases{$author};
}
if ( !$author ) { if ( !$author ) {
$author = $commit_info->{'currentPatchSet'}{'author'}{'username'}; $author = $commit_info->{'currentPatchSet'}{'author'}{'username'};
} }
$author_email = $commit_info->{'currentPatchSet'}{'author'}{'email'};
$inserted_lines = $commit_info->{'currentPatchSet'}{'sizeInsertions'}; $inserted_lines = $commit_info->{'currentPatchSet'}{'sizeInsertions'};
$deleted_lines = $commit_info->{'currentPatchSet'}{'sizeDeletions'}; $deleted_lines = $commit_info->{'currentPatchSet'}{'sizeDeletions'};
$subject = $commit_info->{'subject'}; $subject = $commit_info->{'subject'};
@ -120,21 +224,88 @@ sub Main {
if ( $approval->{'type'} eq "SUBM" ) { if ( $approval->{'type'} eq "SUBM" ) {
$submit_epoch = $approval->{'grantedOn'}; $submit_epoch = $approval->{'grantedOn'};
$submitter = $approval->{'by'}{'name'}; $submitter = $approval->{'by'}{'name'};
if ( exists( $aliases{$submitter} ) ) {
$submitter = $aliases{$submitter};
}
} }
} }
#get all the reviewers for all patch revisions # Get all the commenters for all patch revisions
my $comments = $commit_info->{'comments'};
for my $comment (@$comments) {
my $commenter;
if ( $comment->{'reviewer'}{'username'} ) {
if ( $comment->{'reviewer'}{'username'} eq "jenkins" ) {
next;
}
if ( $comment->{'reviewer'}{'username'} eq "hardwaretestrobot" ) {
next;
}
if ( $comment->{'reviewer'}{'username'} eq "raptor-automated-test" ) {
next;
}
}
if ( $comment->{'reviewer'}{'name'} ) {
if ( $comment->{'reviewer'}{'name'} eq "Gerrit Code Review" ) {
next;
}
}
if ( $comment->{'message'} ) {
if ( $comment->{'message'} =~ "successfully cherry-picked" ) {
next;
}
if ( $comment->{'message'} =~ ": Code-Review" ) {
next;
}
if ( $comment->{'message'} =~ "Uploaded patch set" ) {
next;
}
}
if ( !$commenter ) {
$commenter = $comment->{'reviewer'}{'name'};
if ( $commenter && exists( $aliases{$commenter} ) ) {
$commenter = $aliases{$commenter};
}
}
if ( !$commenter ) {
$commenter = $comment->{'reviewer'}{'username'};
if ( $commenter && exists( $aliases{$commenter} ) ) {
$commenter = $aliases{$commenter};
}
}
if ( $commenter && $author && $commenter eq $author ) {
next;
}
if ($commenter) {
if ( $commenter && exists $patch_commenters{$commenter} ) {
$patch_commenters{$commenter}++;
} else {
$patch_commenters{$commenter} = 1;
}
}
}
# Get all the reviewers for all patch revisions
my $patchsets = $commit_info->{'patchSets'}; my $patchsets = $commit_info->{'patchSets'};
for my $patch (@$patchsets) { for my $patch (@$patchsets) {
if ( !$author ) { if ( !$author ) {
$author = $patch->{'author'}{'name'}; $author = $patch->{'author'}{'name'};
if ( $author && exists( $aliases{$author} ) ) {
$author = $aliases{$author};
} }
}
my $approvals = $patch->{'approvals'}; my $approvals = $patch->{'approvals'};
for my $approval (@$approvals) { for my $approval (@$approvals) {
if ( ( !$submitter ) && ( $approval->{'type'} eq "SUBM" ) ) { if ( ( !$submitter ) && ( $approval->{'type'} eq "SUBM" ) ) {
$submit_epoch = $approval->{'grantedOn'}; $submit_epoch = $approval->{'grantedOn'};
$submitter = $approval->{'by'}{'name'}; $submitter = $approval->{'by'}{'name'};
if ( $submitter && exists( $aliases{$submitter} ) ) {
$submitter = $aliases{$submitter};
}
} }
if ( $approval->{'type'} eq "Code-Review" ) { if ( $approval->{'type'} eq "Code-Review" ) {
@ -151,11 +322,20 @@ sub Main {
} }
} else { } else {
# get the info from git
# Get the info from git
my $logline = `git log --pretty="%ct@@@%s@@@%an@@@%aE@@@%cn" $commit_id^..$commit_id --`; my $logline = `git log --pretty="%ct@@@%s@@@%an@@@%aE@@@%cn" $commit_id^..$commit_id --`;
$logline =~ m/^(.*)@@@(.*)@@@(.*)@@@(.*)@@@(.*)\n/; $logline =~ m/^(.*)@@@(.*)@@@(.*)@@@(.*)@@@(.*)\n/;
( $submit_epoch, $subject, $author, $author_email, $submitter ) = ( $1, $2, $3, $4, $5 ); ( $submit_epoch, $subject, $author, $author_email, $submitter ) = ( $1, $2, $3, $4, $5 );
if ( exists( $aliases{$author} ) ) {
$author = $aliases{$author};
}
$owner = $author; $owner = $author;
if ( $submitter && exists( $aliases{$submitter} ) ) {
$submitter = $aliases{$submitter};
}
$logline = `git log --pretty= --shortstat $commit_id^..$commit_id --`; $logline = `git log --pretty= --shortstat $commit_id^..$commit_id --`;
if ( $logline =~ m/\s+(\d+)\s+insertion/ ) { if ( $logline =~ m/\s+(\d+)\s+insertion/ ) {
$inserted_lines = $1; $inserted_lines = $1;
@ -167,6 +347,9 @@ sub Main {
for my $line (@loglines) { for my $line (@loglines) {
if ( $line =~ m/.*:\s+(.*)\s</ ) { if ( $line =~ m/.*:\s+(.*)\s</ ) {
my $patch_reviewer = $1; my $patch_reviewer = $1;
if ( exists( $aliases{$patch_reviewer} ) ) {
$patch_reviewer = $aliases{$patch_reviewer};
}
if ($patch_reviewer) { if ($patch_reviewer) {
if ( exists $patch_reviewers{$patch_reviewer} ) { if ( exists $patch_reviewers{$patch_reviewer} ) {
$patch_reviewers{$patch_reviewer}++; $patch_reviewers{$patch_reviewer}++;
@ -187,47 +370,87 @@ sub Main {
$submit_epoch = $1; $submit_epoch = $1;
} }
#add the count and owner to the submitter hash # Add the count and owner to the submitter hash
if (exists $submitters{$submitter}) { if ( $submitter && exists $submitters{$submitter} && exists $submitters{$submitter}{count} ) {
$submitters{$submitter}++; $submitters{$submitter}{count}++;
} else { } else {
$submitters{$submitter} = 1; $submitters{$submitter}{count} = 1;
$number_of_submitters++; $number_of_submitters++;
$submitters{$submitter}{"self"} = 0;
$submitters{$submitter}{others} = 0;
$submitters{$submitter}{name} = $submitter;
} }
#create a readable date if ( $submitter eq $author ) {
$submitters{$submitter}{"self"}++;
} else {
$submitters{$submitter}{others}++;
}
# Create a readable date
my $dt = DateTime->from_epoch( epoch => $submit_epoch ); my $dt = DateTime->from_epoch( epoch => $submit_epoch );
$dt->set_time_zone('Europe/Paris'); $dt->set_time_zone('Europe/Paris');
my $submit_time = $dt->strftime('%Y/%m/%d %H:%M:%S'); my $submit_time = $dt->strftime('%Y/%m/%d');
if ( !$first_submit_epoch ) { if ( !$first_submit_epoch ) {
$first_submit_epoch = $submit_epoch; $first_submit_epoch = $submit_epoch;
} }
#create the list of reviewers to print # Create the list of commenters to print
my $commenterlist = "";
foreach my $commenter ( keys %patch_commenters ) {
if ( $commenter && exists( $aliases{$commenter} ) ) {
$commenter = $aliases{$commenter};
}
if ( $commenterlist eq "" ) {
$commenterlist = $commenter;
} else {
$commenterlist .= ", $commenter";
}
if ( $commenter && exists $commenters{$commenter} ) {
$commenters{$commenter}++;
} else {
$commenters{$commenter} = 1;
}
}
if ( !$commenterlist ) {
$commenterlist = "-";
}
# Create the list of reviewers to print
my $reviewerlist = ""; my $reviewerlist = "";
foreach my $reviewer ( keys %patch_reviewers ) { foreach my $reviewer ( keys %patch_reviewers ) {
if ( exists( $aliases{$reviewer} ) ) {
$reviewer = $aliases{$reviewer};
}
if ( $reviewerlist eq "" ) { if ( $reviewerlist eq "" ) {
$reviewerlist = $reviewer; $reviewerlist = $reviewer;
} else { } else {
$reviewerlist .= ", $reviewer"; $reviewerlist .= ", $reviewer";
} }
if (exists $reviewers{$reviewer}) { if ( $reviewer && exists $reviewers{$reviewer} ) {
$reviewers{$reviewer}++; $reviewers{$reviewer}++;
} else { } else {
$reviewers{$reviewer} = 1; $reviewers{$reviewer} = 1;
} }
} }
if ( !$reviewerlist ) { if ( !$reviewerlist ) {
$reviewerlist = "-" $reviewerlist = "-";
} }
if ($print_commit_list) { if ($print_commit_list) {
print "$submit_time, $owner, $author, $submitter, $inserted_lines, $deleted_lines, \"$subject\", \"$reviewerlist\"\n"; print "$submit_time, $owner, $author, $submitter, $inserted_lines, $deleted_lines, \"$subject\", \"$reviewerlist\" , \"$commenterlist\"\n";
} else { } else {
print "$number_of_commits\n"; print "$number_of_commits\n";
} }
$total_added += $inserted_lines; $total_added += $inserted_lines;
if ( $inserted_lines - $deleted_lines > 100 ) {
$patches_over_100_lines++;
$total_lines_large_patches += $inserted_lines;
}
$total_removed += $deleted_lines; $total_removed += $deleted_lines;
if ( exists $owners{$owner} ) { if ( exists $owners{$owner} ) {
$owners{$owner}++; $owners{$owner}++;
@ -235,7 +458,7 @@ sub Main {
$owners{$owner} = 1; $owners{$owner} = 1;
} }
if (exists $authors{$author}{"num"}) { if ( $author && exists $authors{$author}{"num"} ) {
$authors{$author}{"num"}++; $authors{$author}{"num"}++;
$author_added{$author} += $inserted_lines; $author_added{$author} += $inserted_lines;
$author_removed{$author} += $deleted_lines; $author_removed{$author} += $deleted_lines;
@ -247,8 +470,12 @@ sub Main {
$author_added{$author} = $inserted_lines; $author_added{$author} = $inserted_lines;
$author_removed{$author} = $deleted_lines; $author_removed{$author} = $deleted_lines;
} }
if (! exists $authors{$author}{email} && $author_email) { if ( $author && ( !exists $authors{$author}{email} || $authors{$author}{email} eq "-" ) ) {
if ($author_email) {
$authors{$author}{email} = "$author_email"; $authors{$author}{email} = "$author_email";
} elsif ( exists $email_addresses{$author} ) {
$authors{$author}{email} = $email_addresses{$author};
}
} }
} }
my $Days = ( $first_submit_epoch - $submit_epoch ) / 86400; my $Days = ( $first_submit_epoch - $submit_epoch ) / 86400;
@ -256,19 +483,43 @@ sub Main {
$Days += 1; $Days += 1;
} }
print "- Total Commits: $number_of_commits\n"; print "\n- Total Commits: $number_of_commits\n";
printf "- Average Commits per day: %.2f\n", $number_of_commits / $Days; printf "- Average Commits per day: %.2f\n", $number_of_commits / $Days;
print "- Total lines added: $total_added\n"; print "- Total lines added: $total_added\n";
printf "- Average lines added per commit: %.2f\n", $total_added / $number_of_commits;
print "- Number of patches adding more than 100 lines: $patches_over_100_lines\n";
printf "- Average lines added per small commit: %.2f\n", ( $total_added - $total_lines_large_patches ) / ( $number_of_commits - $patches_over_100_lines );
print "- Total lines removed: $total_removed\n"; print "- Total lines removed: $total_removed\n";
print "- Total difference: " . ($total_added + $total_removed) . "\n\n"; printf "- Average lines removed per commit: %.2f\n", $total_removed / $number_of_commits;
print "- Total difference between added and removed: " . ( $total_added - $total_removed ) . "\n\n";
print "=== Authors - Number of commits ===\n"; print "=== Authors - Number of commits ===\n";
printf "%-30s ,%5s ,%5s ,%6s ,%6s , %-52s ,%6s, %-19s , %s\n", "Author", "Ptchs", "Revws", "Cmnts", "Sbmts", "Email", "Prcnt", "Last commit", "Earliest_commit";
my $number_of_authors = 0; my $number_of_authors = 0;
foreach my $author ( sort { $authors{$b}{num} <=> $authors{$a}{num} } ( keys %authors ) ) { foreach my $author ( sort { $authors{$b}{num} <=> $authors{$a}{num} } ( keys %authors ) ) {
if (! exists $authors{$author}{"email"}) { my $submissions = 0;
if ( $author && exists $submitters{$author} ) {
$submissions = $submitters{$author}{count};
}
my $review_count = 0;
if ( $author && exists $reviewers{$author} ) {
$review_count = $reviewers{$author};
}
my $comment_count = 0;
if ( $author && exists $commenters{$author} ) {
$comment_count = $commenters{$author};
}
if ( $author && !exists $authors{$author}{"email"} ) {
$authors{$author}{"email"} = "-"; $authors{$author}{"email"} = "-";
} }
printf "%-25s %5d %-40s (%2.2f%%) {%s / %s}\n",$author, $authors{$author}{"num"}, $authors{$author}{"email"}, $authors{$author}{"num"} / $number_of_commits * 100, $authors{$author}{"latest_commit"}, $authors{$author}{"earliest_commit"};
printf "%-30s ,%5d ,%5d ,%6d ,%6d , %-52s ,%5.2f%%, %s , %s\n", $author, $authors{$author}{"num"}, $review_count,
$comment_count, $submissions, $authors{$author}{"email"}, $authors{$author}{"num"} / $number_of_commits * 100,
$authors{$author}{"latest_commit"}, $authors{$author}{"earliest_commit"};
$number_of_authors++; $number_of_authors++;
} }
print "Total Authors: $number_of_authors\n\n"; print "Total Authors: $number_of_authors\n\n";
@ -276,15 +527,15 @@ sub Main {
print "=== Authors - Lines added ===\n"; print "=== Authors - Lines added ===\n";
foreach my $author ( sort { $author_added{$b} <=> $author_added{$a} } ( keys %author_added ) ) { foreach my $author ( sort { $author_added{$b} <=> $author_added{$a} } ( keys %author_added ) ) {
if ( $author_added{$author} ) { if ( $author_added{$author} ) {
printf "%-25s %5d (%2.3f%%)\n",$author, $author_added{$author}, $author_added{$author} / $total_added * 100; printf "%-30s, %10d, %2.3f%%\n", $author, $author_added{$author}, $author_added{$author} / $total_added * 100;
} }
} }
print "\n"; print "\n";
print "=== Authors - Lines removed ===\n"; print "=== Authors - Lines removed ===\n";
foreach my $author (sort { $author_removed{$a} <=> $author_removed{$b} } (keys %author_removed) ) { foreach my $author ( sort { $author_removed{$b} <=> $author_removed{$a} } ( keys %author_removed ) ) {
if ( $author_removed{$author} ) { if ( $author_removed{$author} ) {
printf "%-25s %5d (%2.3f%%)\n",$author,$author_removed{$author} * -1, $author_removed{$author} / $total_removed * 100; printf "%-30s, %10d, %6.3f%%\n", $author, $author_removed{$author} * -1, $author_removed{$author} / $total_removed * 100;
} }
} }
print "\n"; print "\n";
@ -292,19 +543,27 @@ sub Main {
print "=== Reviewers - Number of patches reviewed ===\n"; print "=== Reviewers - Number of patches reviewed ===\n";
my $number_of_reviewers = 0; my $number_of_reviewers = 0;
foreach my $reviewer ( sort { $reviewers{$b} <=> $reviewers{$a} } ( keys %reviewers ) ) { foreach my $reviewer ( sort { $reviewers{$b} <=> $reviewers{$a} } ( keys %reviewers ) ) {
printf "%-25s %5d (%2.3f%%)\n",$reviewer, $reviewers{$reviewer}, $reviewers{$reviewer} / $number_of_commits * 100; printf "%-30s, %6d, %6.3f%%\n", $reviewer, $reviewers{$reviewer}, $reviewers{$reviewer} / $number_of_commits * 100;
$number_of_reviewers++; $number_of_reviewers++;
} }
print "Total Reviewers: $number_of_reviewers\n\n"; print "Total Reviewers: $number_of_reviewers\n\n";
print "=== Submitters - Number of patches submitted ===\n"; print "=== Submitters - Number of patches submitted ===\n";
foreach my $submitter (sort { $submitters{$b} <=> $submitters{$a} } (keys %submitters) ) { printf "%-30s, %6s, %7s, %6s, %7s, %6s, %7s\n", "Name", "#", "total%", "Own", "own%", "Other", "other%";
printf "%-25s %5d (%2.3f%%)\n",$submitter, $submitters{$submitter}, $submitters{$submitter} / $number_of_commits * 100; foreach my $submitter ( sort { $submitters{$b}{count} <=> $submitters{$a}{count} } ( keys %submitters ) ) {
printf "%-30s, % 6d, %6.3f%%, %6d, %6.2f%%, %6d, %6.2f%%\n",
$submitter,
$submitters{$submitter}{count},
$submitters{$submitter}{count} / $number_of_commits * 100,
$submitters{$submitter}{"self"},
$submitters{$submitter}{"self"} / $submitters{$submitter}{count} * 100,
$submitters{$submitter}{others}, $submitters{$submitter}{others} / $submitters{$submitter}{count} * 100;
} }
print "Total Submitters: $number_of_submitters\n\n"; print "Total Submitters: $number_of_submitters\n\n";
print "Commits, Ave, Added, Removed, Diff, Authors, Reviewers, Submitters\n"; print "Commits, Ave, Added, Removed, Diff, Authors, Reviewers, Submitters\n";
printf "$number_of_commits, %.2f, $total_added, $total_removed, " . ($total_added + $total_removed) . ", $number_of_authors, $number_of_reviewers, $number_of_submitters\n", $number_of_commits / $Days; printf "$number_of_commits, %.2f, $total_added, $total_removed, " . ( $total_added + $total_removed ) . ", $number_of_authors, $number_of_reviewers, $number_of_submitters\n",
$number_of_commits / $Days;
} }
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
@ -323,13 +582,12 @@ sub check_versions {
} }
} }
#-------------------------------------------------------------------------------
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
sub get_user { sub get_user {
my $url = `git config -l | grep remote.origin.url`; my $url = `git config -l | grep remote.origin.url`;
if ($url =~ /.*url=ssh:\/\/(\w+@[a-zA-Z][a-zA-Z0-9\.]+:\d+)/) if ( $url =~ /.*url=ssh:\/\/(\w+@[a-zA-Z][a-zA-Z0-9\.]+:\d+)(\/\w+)*/ ) {
{
$URL_WITH_USER = $1; $URL_WITH_USER = $1;
} else { } else {
print "Error: Could not get a ssh url with a username from gitconfig.\n"; print "Error: Could not get a ssh url with a username from gitconfig.\n";
@ -343,7 +601,7 @@ sub get_user {
sub get_commits { sub get_commits {
my @commits = @_; my @commits = @_;
my $submit_time = ""; my $submit_time = "";
if (defined $SKIP_GERRIT_CHECK) { if ( defined $SKIP_GERRIT_CHECK && $SKIP_GERRIT_CHECK ) {
return; return;
} }
my $ssh = Net::OpenSSH->new( "$URL_WITH_USER", ); my $ssh = Net::OpenSSH->new( "$URL_WITH_USER", );
@ -352,7 +610,7 @@ sub get_commits {
print "Using URL: ssh://$URL_WITH_USER\n"; print "Using URL: ssh://$URL_WITH_USER\n";
if ( !-d $infodir ) { if ( !-d $infodir ) {
mkpath($infodir) mkpath($infodir);
} }
for my $commit_id (@commits) { for my $commit_id (@commits) {
@ -360,8 +618,8 @@ sub get_commits {
$submit_time = ""; $submit_time = "";
my $gerrit_review; my $gerrit_review;
# Quit if we've reeached the last coreboot commit supporting these queries # Look for last coreboot commit
if ($commit_id =~ /^7309709/) { if ( $commit_id eq "7309709742" ) {
last; last;
} }
@ -389,7 +647,7 @@ sub get_commits {
for my $approval (@$approvals) { for my $approval (@$approvals) {
if ( $approval->{'type'} eq "SUBM" ) { if ( $approval->{'type'} eq "SUBM" ) {
$submit_time = $approval->{'grantedOn'} $submit_time = $approval->{'grantedOn'};
} }
} }
my $dt = ""; my $dt = "";
@ -430,6 +688,7 @@ sub check_arguments {
'url|u=s' => \$URL_WITH_USER, 'url|u=s' => \$URL_WITH_USER,
'skip|s' => \$SKIP_GERRIT_CHECK, 'skip|s' => \$SKIP_GERRIT_CHECK,
); );
# strip ssh:// from url if passed in. # strip ssh:// from url if passed in.
if ( defined $URL_WITH_USER ) { if ( defined $URL_WITH_USER ) {
$URL_WITH_USER =~ s|ssh://||; $URL_WITH_USER =~ s|ssh://||;