Last active
February 13, 2023 21:40
-
-
Save L1ghtmann/4392264f9a0dd2c189d53e2602c8cf0b to your computer and use it in GitHub Desktop.
Get a list of contributors to a public GitHub org sorted by total diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env perl | |
| # | |
| # org-contributors.pl | |
| # Created by Lightmann | |
| # February 2023 | |
| # | |
| use strict; | |
| use warnings; | |
| use FindBin; | |
| use File::Temp; | |
| use Getopt::Long; | |
| use sigtrap qw(die normal-signals error-signals); | |
| my $script = $FindBin::Script; | |
| my $usage = <<"EOF"; | |
| Usage: $script [options] | |
| Options: | |
| [-i|--ignore] Comma-separated list of repos to ignore in the organization | |
| [-o|--org] Name of GitHub organization to query | |
| [-h|--help] Display this page | |
| EOF | |
| my ($opt_ignore, $opt_org, $opt_help); | |
| GetOptions( | |
| "ignore|i=s" => \$opt_ignore, | |
| "org|o=s" => \$opt_org, | |
| "help|h" => \$opt_help, | |
| ); | |
| if ($opt_help) { | |
| print $usage; | |
| exit 0; | |
| } | |
| die "Usage: $script --org <org name>\nRun $script --help for more details\n" if (!defined $opt_org); | |
| my $curl = `curl -s "https://api.github.com/users/$opt_org/repos?per_page=100" | grep -o 'git@[^"]*'`; | |
| die "Error: the org specified -- $opt_org -- does not appear to exist. Please check the name for typos.\n" if ($curl eq ''); | |
| my @repos = split('\n', $curl); | |
| my $dir = FindBin::again(); | |
| my $tmp = File::Temp->newdir; | |
| chdir $tmp; | |
| my %authors; | |
| foreach my $repo (@repos){ | |
| # Switch repo url to https from ssh | |
| (my $url = $repo) =~ s/git\@github.com:/https:\/\/github.com\//; | |
| # Skip specified repos | |
| if (defined $opt_ignore){ | |
| my @filters = ($opt_ignore); | |
| @filters = split(',', $opt_ignore) if ($opt_ignore =~ /,/); | |
| # https://stackoverflow.com/a/15951137 | |
| # Convert array elements into regex | |
| my $rx = join('\b|\b', map quotemeta, @filters); | |
| if ($url =~ /\b$rx\b/) { | |
| print "[=] Skipping $url\n"; | |
| next; | |
| } | |
| } | |
| print "[x] Starting work on $url....\n"; | |
| # Clone repo | |
| system("git clone --quiet --no-checkout $url"); | |
| # Grab repo name (i.e., directory name) | |
| (my $directory = (split(/\//, $url))[-1]) =~ s/\.[^.]+$//; | |
| # Get contribution info | |
| my $log = `git -C $directory --no-pager log --stat`; | |
| my @commits = split(/commit /, $log); | |
| print "[+] Got the commit history. Quantifying diff....\n"; | |
| foreach my $commit (@commits){ | |
| my @lines = split(/\n/, $commit); | |
| # Grab relevant bits | |
| my ($author) = grep(/Author: /, @lines); | |
| my ($diff) = grep(/changed, /, @lines); | |
| # Santiy check | |
| next if (!defined $author || !defined $diff); | |
| # Simplify bits | |
| $author =~ s/Author: //g; # Remove prefix | |
| $author =~ s/(<[^<>]*>)//g; # Remove email | |
| $author =~ s/\s+$//; # Remove trailing space | |
| my @changes = split(/, /, $diff); | |
| # Do some math | |
| foreach my $change (@changes){ | |
| if (index($change, "-") != -1 || index($change, "+") != -1) { | |
| (my $num = $change) =~ s/\D//g; | |
| $authors{$author} += $num if ($num ne ""); | |
| } | |
| } | |
| } | |
| } | |
| print "[!] The results are in. Sorting....\n"; | |
| # https://stackoverflow.com/a/9660407 | |
| # Sort hash keys according to respective val | |
| # Need to maintain the order, hence the array | |
| my @sorted = sort { $authors{$b} <=> $authors{$a} } keys %authors; | |
| print "[-] Ordered list of contributors to $opt_org repositories:\n"; | |
| print "-------------------------------------------------------\n"; | |
| foreach my $author (@sorted) { | |
| # https://stackoverflow.com/a/58104835 | |
| # Format each diff num nicely | |
| my $diff = $authors{$author}; | |
| while($diff =~ s/(\d+)(\d\d\d)/$1\,$2/){}; | |
| print "◉ $author: $diff edits\n"; | |
| } | |
| print "-------------------------------------------------------\n"; | |
| chdir $dir; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment