File Coverage

blib/lib/Group/Git/Cmd/Stats.pm
Criterion Covered Total %
statement 33 80 41.2
branch 0 32 0.0
condition 0 5 0.0
subroutine 11 14 78.5
pod 3 3 100.0
total 47 134 35.0


line stmt bran cond sub pod time code
1             package Group::Git::Cmd::Stats;
2              
3             # Created on: 2013-05-10 07:05:17
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 1     1   15083 use strict;
  1         1  
  1         22  
10 1     1   361 use version;
  1         1209  
  1         5  
11 1     1   518 use Moose::Role;
  1         304947  
  1         3  
12 1     1   3489 use Carp;
  1         2  
  1         57  
13 1     1   4 use List::Util qw/max/;
  1         2  
  1         48  
14 1     1   959 use Data::Dumper qw/Dumper/;
  1         4823  
  1         50  
15 1     1   432 use English qw/ -no_match_vars /;
  1         2571  
  1         5  
16 1     1   707 use File::chdir;
  1         2152  
  1         70  
17 1     1   709 use Path::Tiny;
  1         7037  
  1         44  
18 1     1   505 use Getopt::Alt;
  1         168227  
  1         6  
19 1     1   1068 use YAML::Syck;
  1         1474  
  1         640  
20              
21             our $VERSION = version->new('0.0.2');
22              
23             my $opt = Getopt::Alt->new(
24             {
25             helper => 1,
26             help => __PACKAGE__,
27             default => {
28             by => 'name',
29             of => 'commits',
30             },
31             },
32             [
33             'by|b=s',
34             'of|o=s',
35             'verbose|v+',
36             'quiet|q!',
37             ]
38             );
39              
40             sub stats_start {
41 0     0 1   $opt->process;
42              
43 0           return;
44             }
45              
46             my $collected = {};
47             sub stats {
48 0     0 1   my ($self, $name) = @_;
49              
50 0 0         return unless -d $name;
51              
52 0 0         $opt->process if !%{ $opt->opt || {} };
  0 0          
53              
54 0           my $dir = path($CWD);
55              
56 0           local $CWD = $name;
57              
58 0           my $cache = $dir->path('.stats', $name . '.yml');
59 0           $cache->parent->mkpath;
60 0           my %stats;
61              
62 0 0         if ( -f $cache ) {
63 0           %stats = %{ LoadFile($cache) };
  0            
64             }
65              
66 0           open my $pipe, '-|', q{git log --format=format:"%H';'%ai';'%an';'%ae"};
67              
68 0           while (my $log = <$pipe>) {
69 0           chomp $log;
70 0           my ($id, $date, $name, $email) = split q{';'}, $log, 4;
71              
72 0 0         last if $stats{$id};
73              
74             # dodgy date handling but hay
75 0           $date =~ s/\s.+$//;
76              
77 0           open my $show, '-|', qq{git show $id | grep -v '^[+][+][+]|^[-][-][-]' | grep -v '^[^-+]'};
78 0           my ($added, $removed) = (0, 0);
79 0           while (my $change = <$show>) {
80 0 0         $added++ if $change =~ /^[+]/;
81 0 0         $removed++ if $change =~ /^[-]/;
82             }
83              
84 0           $stats{$id} = {
85             name => $name,
86             email => $email,
87             date => $date,
88             added => $added,
89             removed => $removed,
90             };
91             }
92              
93 0           $cache = $dir->path('.stats', $name . '.yml');
94 0           DumpFile($cache, \%stats);
95              
96 0           $collected->{$name} = \%stats;
97              
98 0           return;
99             }
100              
101             sub stats_end {
102 0 0   0 1   if ( -d '.stats' ) {
103 0           DumpFile('.stats/collated.yml', $collected);
104              
105 0 0         my $type = $opt->opt->by eq 'email' ? 'email'
    0          
    0          
    0          
    0          
106             : $opt->opt->by eq 'name' ? 'name'
107             : $opt->opt->by eq 'date' ? 'date'
108             : $opt->opt->by eq 'total' ? 'total'
109             : $opt->opt->by eq 'repo' ? ''
110             : die "Unknown --by '" . $opt->opt->by . "'! (must be one of email, name or date)\n";
111              
112 0 0         my $of = $opt->opt->of eq 'commits' ? 'commits'
    0          
    0          
113             : $opt->opt->of eq 'additions' ? 'added'
114             : $opt->opt->of eq 'removals' ? 'removed'
115             : die "Unknown --of '" . $opt->opt->of . "'! (must be one of commits, additions or removals)\n";
116              
117 0           my %stats;
118 0           for my $repo (keys %{ $collected }) {
  0            
119 0           for my $id (keys %{ $collected->{$repo} }) {
  0            
120 0   0       $stats{ $collected->{$repo}{$id}{$type} // $repo } += $collected->{$repo}{$id}{$of} // 1;
      0        
121             }
122             }
123              
124 0           my @items = sort { $stats{$a} <=> $stats{$b} } keys %stats;
  0            
125 0           my $max = max map {length $_} @items;
  0            
126 0           for my $item (@items) {
127 0           printf "%-${max}s %d\n", $item, $stats{$item};
128             }
129             }
130              
131 0           return;
132             }
133              
134             1;
135              
136             __END__
137              
138             =head1 NAME
139              
140             Group::Git::Cmd::Stats - Group-Git tools to show statistics accross many repositories
141              
142             =head1 VERSION
143              
144             This documentation refers to Group::Git::Cmd::Stats version 0.0.2
145              
146             =head1 SYNOPSIS
147              
148             use Group::Git::Cmd::Stats;
149              
150             # Brief but working code example(s) here showing the most common usage(s)
151             # This section will be as far as many users bother reading, so make it as
152             # educational and exemplary as possible.
153              
154              
155             =head1 DESCRIPTION
156              
157             Adds the stats command to L<Group::Git> which allows you to collect statistics
158             accross many repositories.
159              
160             =head1 SUBROUTINES/METHODS
161              
162             =head2 C<stats ($name)>
163              
164             Collects the stats for each repository.
165              
166             =head2 C<stats_start ()>
167              
168             Initialises stats
169              
170             =head2 C<stats_end ()>
171              
172             Outputs the stats results.
173              
174             =head1 DIAGNOSTICS
175              
176             =head1 CONFIGURATION AND ENVIRONMENT
177              
178             =head1 DEPENDENCIES
179              
180             =head1 INCOMPATIBILITIES
181              
182             =head1 BUGS AND LIMITATIONS
183              
184             There are no known bugs in this module.
185              
186             Please report problems to Ivan Wills (ivan.wills@gmail.com).
187              
188             Patches are welcome.
189              
190             =head1 AUTHOR
191              
192             Ivan Wills - (ivan.wills@gmail.com)
193              
194             =head1 LICENSE AND COPYRIGHT
195              
196             Copyright (c) 2013 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
197             All rights reserved.
198              
199             This module is free software; you can redistribute it and/or modify it under
200             the same terms as Perl itself. See L<perlartistic>. This program is
201             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
202             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
203             PARTICULAR PURPOSE.
204              
205             =cut