Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

get_maintainer: add commit author information to --rolestats

get_maintainer currently uses "Signed-off-by" style lines to find
interested parties to send patches to when the MAINTAINERS file does not
have a specific section entry with a matching file pattern.

Add statistics for commit authors and lines added and deleted to the
information provided by --rolestats.

These statistics are also emitted whenever --rolestats and --git are
selected even when there is a specified maintainer.

This can have the effect of expanding the number of people that are shown
as possible "maintainers" of a particular file because "authors",
"added_lines", and "removed_lines" are also used as criterion for the
--max-maintainers option separate from the "commit_signers".

The first "--git-max-maintainers" values of each criterion
are emitted. Any "ties" are not shown.

For example: (forcedeth does not have a named maintainer)

Old output:

$ ./scripts/get_maintainer.pl -f drivers/net/ethernet/nvidia/forcedeth.c
"David S. Miller" <davem@davemloft.net> (commit_signer:8/10=80%)
Jiri Pirko <jiri@resnulli.us> (commit_signer:2/10=20%)
Patrick McHardy <kaber@trash.net> (commit_signer:2/10=20%)
Larry Finger <Larry.Finger@lwfinger.net> (commit_signer:1/10=10%)
Peter Zijlstra <peterz@infradead.org> (commit_signer:1/10=10%)
netdev@vger.kernel.org (open list:NETWORKING DRIVERS)
linux-kernel@vger.kernel.org (open list)

New output:

$ ./scripts/get_maintainer.pl -f drivers/net/ethernet/nvidia/forcedeth.c
"David S. Miller" <davem@davemloft.net> (commit_signer:8/10=80%)
Jiri Pirko <jiri@resnulli.us> (commit_signer:2/10=20%,authored:2/10=20%,removed_lines:3/33=9%)
Patrick McHardy <kaber@trash.net> (commit_signer:2/10=20%,authored:2/10=20%,added_lines:12/95=13%,removed_lines:10/33=30%)
Larry Finger <Larry.Finger@lwfinger.net> (commit_signer:1/10=10%,authored:1/10=10%,added_lines:35/95=37%)
Peter Zijlstra <peterz@infradead.org> (commit_signer:1/10=10%)
"Peter Hüwe" <PeterHuewe@gmx.de> (authored:1/10=10%,removed_lines:15/33=45%)
Joe Perches <joe@perches.com> (authored:1/10=10%)
Neil Horman <nhorman@tuxdriver.com> (added_lines:40/95=42%)
Bill Pemberton <wfp5p@virginia.edu> (removed_lines:3/33=9%)
netdev@vger.kernel.org (open list:NETWORKING DRIVERS)
linux-kernel@vger.kernel.org (open list)

Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Joe Perches and committed by
Linus Torvalds
c9ecefea 1d3fa370

+85 -6
+85 -6
scripts/get_maintainer.pl
··· 98 98 "available" => '(which("git") ne "") && (-d ".git")', 99 99 "find_signers_cmd" => 100 100 "git log --no-color --follow --since=\$email_git_since " . 101 + '--numstat --no-merges ' . 101 102 '--format="GitCommit: %H%n' . 102 103 'GitAuthor: %an <%ae>%n' . 103 104 'GitDate: %aD%n' . ··· 107 106 " -- \$file", 108 107 "find_commit_signers_cmd" => 109 108 "git log --no-color " . 109 + '--numstat ' . 110 110 '--format="GitCommit: %H%n' . 111 111 'GitAuthor: %an <%ae>%n' . 112 112 'GitDate: %aD%n' . ··· 116 114 " -1 \$commit", 117 115 "find_commit_author_cmd" => 118 116 "git log --no-color " . 117 + '--numstat ' . 119 118 '--format="GitCommit: %H%n' . 120 119 'GitAuthor: %an <%ae>%n' . 121 120 'GitDate: %aD%n' . ··· 128 125 "blame_commit_pattern" => "^([0-9a-f]+) ", 129 126 "author_pattern" => "^GitAuthor: (.*)", 130 127 "subject_pattern" => "^GitSubject: (.*)", 128 + "stat_pattern" => "^(\\d+)\\t(\\d+)\\t\$file\$", 131 129 ); 132 130 133 131 my %VCS_cmds_hg = ( ··· 156 152 "blame_commit_pattern" => "^([ 0-9a-f]+):", 157 153 "author_pattern" => "^HgAuthor: (.*)", 158 154 "subject_pattern" => "^HgSubject: (.*)", 155 + "stat_pattern" => "^(\\d+)\t(\\d+)\t\$file\$", 159 156 ); 160 157 161 158 my $conf = which_conf(".get_maintainer.conf"); ··· 1274 1269 } 1275 1270 1276 1271 sub vcs_find_signers { 1277 - my ($cmd) = @_; 1272 + my ($cmd, $file) = @_; 1278 1273 my $commits; 1279 1274 my @lines = (); 1280 1275 my @signatures = (); 1276 + my @authors = (); 1277 + my @stats = (); 1281 1278 1282 1279 @lines = &{$VCS_cmds{"execute_cmd"}}($cmd); 1283 1280 1284 1281 my $pattern = $VCS_cmds{"commit_pattern"}; 1282 + my $author_pattern = $VCS_cmds{"author_pattern"}; 1283 + my $stat_pattern = $VCS_cmds{"stat_pattern"}; 1284 + 1285 + $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern 1285 1286 1286 1287 $commits = grep(/$pattern/, @lines); # of commits 1287 1288 1289 + @authors = grep(/$author_pattern/, @lines); 1288 1290 @signatures = grep(/^[ \t]*${signature_pattern}.*\@.*$/, @lines); 1291 + @stats = grep(/$stat_pattern/, @lines); 1289 1292 1290 - return (0, @signatures) if !@signatures; 1293 + # print("stats: <@stats>\n"); 1294 + 1295 + return (0, \@signatures, \@authors, \@stats) if !@signatures; 1291 1296 1292 1297 save_commits_by_author(@lines) if ($interactive); 1293 1298 save_commits_by_signer(@lines) if ($interactive); ··· 1306 1291 @signatures = grep(!/${penguin_chiefs}/i, @signatures); 1307 1292 } 1308 1293 1294 + my ($author_ref, $authors_ref) = extract_formatted_signatures(@authors); 1309 1295 my ($types_ref, $signers_ref) = extract_formatted_signatures(@signatures); 1310 1296 1311 - return ($commits, @$signers_ref); 1297 + return ($commits, $signers_ref, $authors_ref, \@stats); 1312 1298 } 1313 1299 1314 1300 sub vcs_find_author { ··· 1865 1849 sub vcs_file_signoffs { 1866 1850 my ($file) = @_; 1867 1851 1852 + my $authors_ref; 1853 + my $signers_ref; 1854 + my $stats_ref; 1855 + my @authors = (); 1868 1856 my @signers = (); 1857 + my @stats = (); 1869 1858 my $commits; 1870 1859 1871 1860 $vcs_used = vcs_exists(); ··· 1879 1858 my $cmd = $VCS_cmds{"find_signers_cmd"}; 1880 1859 $cmd =~ s/(\$\w+)/$1/eeg; # interpolate $cmd 1881 1860 1882 - ($commits, @signers) = vcs_find_signers($cmd); 1861 + ($commits, $signers_ref, $authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 1862 + 1863 + @signers = @{$signers_ref} if defined $signers_ref; 1864 + @authors = @{$authors_ref} if defined $authors_ref; 1865 + @stats = @{$stats_ref} if defined $stats_ref; 1866 + 1867 + # print("commits: <$commits>\nsigners:<@signers>\nauthors: <@authors>\nstats: <@stats>\n"); 1883 1868 1884 1869 foreach my $signer (@signers) { 1885 1870 $signer = deduplicate_email($signer); 1886 1871 } 1887 1872 1888 1873 vcs_assign("commit_signer", $commits, @signers); 1874 + vcs_assign("authored", $commits, @authors); 1875 + if ($#authors == $#stats) { 1876 + my $stat_pattern = $VCS_cmds{"stat_pattern"}; 1877 + $stat_pattern =~ s/(\$\w+)/$1/eeg; #interpolate $stat_pattern 1878 + 1879 + my $added = 0; 1880 + my $deleted = 0; 1881 + for (my $i = 0; $i <= $#stats; $i++) { 1882 + if ($stats[$i] =~ /$stat_pattern/) { 1883 + $added += $1; 1884 + $deleted += $2; 1885 + } 1886 + } 1887 + my @tmp_authors = uniq(@authors); 1888 + foreach my $author (@tmp_authors) { 1889 + $author = deduplicate_email($author); 1890 + } 1891 + @tmp_authors = uniq(@tmp_authors); 1892 + my @list_added = (); 1893 + my @list_deleted = (); 1894 + foreach my $author (@tmp_authors) { 1895 + my $auth_added = 0; 1896 + my $auth_deleted = 0; 1897 + for (my $i = 0; $i <= $#stats; $i++) { 1898 + if ($author eq deduplicate_email($authors[$i]) && 1899 + $stats[$i] =~ /$stat_pattern/) { 1900 + $auth_added += $1; 1901 + $auth_deleted += $2; 1902 + } 1903 + } 1904 + for (my $i = 0; $i < $auth_added; $i++) { 1905 + push(@list_added, $author); 1906 + } 1907 + for (my $i = 0; $i < $auth_deleted; $i++) { 1908 + push(@list_deleted, $author); 1909 + } 1910 + } 1911 + vcs_assign("added_lines", $added, @list_added); 1912 + vcs_assign("removed_lines", $deleted, @list_deleted); 1913 + } 1889 1914 } 1890 1915 1891 1916 sub vcs_file_blame { ··· 1954 1887 if ($email_git_blame_signatures) { 1955 1888 if (vcs_is_hg()) { 1956 1889 my $commit_count; 1890 + my $commit_authors_ref; 1891 + my $commit_signers_ref; 1892 + my $stats_ref; 1893 + my @commit_authors = (); 1957 1894 my @commit_signers = (); 1958 1895 my $commit = join(" -r ", @commits); 1959 1896 my $cmd; ··· 1965 1894 $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 1966 1895 $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 1967 1896 1968 - ($commit_count, @commit_signers) = vcs_find_signers($cmd); 1897 + ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 1898 + @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 1899 + @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 1969 1900 1970 1901 push(@signers, @commit_signers); 1971 1902 } else { 1972 1903 foreach my $commit (@commits) { 1973 1904 my $commit_count; 1905 + my $commit_authors_ref; 1906 + my $commit_signers_ref; 1907 + my $stats_ref; 1908 + my @commit_authors = (); 1974 1909 my @commit_signers = (); 1975 1910 my $cmd; 1976 1911 1977 1912 $cmd = $VCS_cmds{"find_commit_signers_cmd"}; 1978 1913 $cmd =~ s/(\$\w+)/$1/eeg; #substitute variables in $cmd 1979 1914 1980 - ($commit_count, @commit_signers) = vcs_find_signers($cmd); 1915 + ($commit_count, $commit_signers_ref, $commit_authors_ref, $stats_ref) = vcs_find_signers($cmd, $file); 1916 + @commit_authors = @{$commit_authors_ref} if defined $commit_authors_ref; 1917 + @commit_signers = @{$commit_signers_ref} if defined $commit_signers_ref; 1981 1918 1982 1919 push(@signers, @commit_signers); 1983 1920 }