File Coverage

blib/lib/Git/Hook/PostReceive.pm
Criterion Covered Total %
statement 93 105 88.5
branch 42 52 80.7
condition 5 9 55.5
subroutine 14 15 93.3
pod 3 7 42.8
total 157 188 83.5


line stmt bran cond sub pod time code
1             package Git::Hook::PostReceive;
2             $Git::Hook::PostReceive::VERSION = '0.3';
3 2     2   53330 use warnings;
  2         5  
  2         88  
4 2     2   12 use strict;
  2         4  
  2         66  
5 2     2   31 use v5.14;
  2         7  
  2         94  
6 2     2   14 use feature "switch";
  2         12  
  2         250  
7              
8             #ABSTRACT: Parses git commit information in post-receive hook scripts
9 2     2   13 use Cwd;
  2         8  
  2         150  
10 2     2   14 use File::Basename;
  2         3  
  2         209  
11 2     2   3071 use Encode;
  2         29892  
  2         3875  
12              
13             sub new {
14 5     5 0 318490 my ( $class, %args ) = @_;
15 5 100       609 my $self = bless { utf8 => $args{utf8} ? 1 : 0, }, $class;
16 5         176 $self;
17             }
18              
19             sub read_stdin {
20 6     6 1 6210 my $self = shift;
21 6 50       64 my @lines = @_ ? map { split "\n" } @_ : <>;
  7         47  
22 6         26 my @branches;
23              
24 6         33 foreach my $line (@lines) {
25 6         54 chomp $line;
26 6         62 my $payload = $self->run( split /\s+/, $line );
27 6 100       64 if (wantarray) {
28 2         36 push @branches, $payload;
29             }
30             else {
31 4         119 return $payload;
32             }
33             }
34 2 100       47 return wantarray ? @branches : ();
35             }
36              
37             sub _git_cmd {
38 22     22   65 my $self = shift;
39 22         102 my @args = qw(git);
40 22 50       112 push @args, "--git-dir=" . $self->{git_dir} if $self->{git_dir};
41 22 50       71 push @args, "--work-tree=" . $self->{work_tree} if $self->{work_tree};
42 22         199472 return @args;
43             }
44              
45             sub detect_action {
46 0     0 1 0 my ( $self, $before, $after ) = @_;
47 0         0 chomp $before;
48 0         0 chomp $after;
49 0 0       0 if ( $before ne '0000000000000000000000000000000000000000' ) {
50 0         0 $before = qx(@{[ $self->_git_cmd() ]} rev-parse $before);
  0         0  
51             }
52             else {
53 0         0 return { created => $before };
54             }
55 0 0       0 if ( $after ne '0000000000000000000000000000000000000000' ) {
56 0         0 $after = qx(@{[ $self->_git_cmd() ]} rev-parse $after);
  0         0  
57             }
58             else {
59 0         0 return { deleted => $after };
60             }
61 0         0 return { pushed => [ $before, $after ] };
62             }
63              
64             sub get_repo {
65 6     6 0 37 my $self = shift;
66 6 50       46 return $self->{git_dir} if $self->{git_dir};
67 6 50       50 return $self->{work_tree} if $self->{work_tree};
68 6         255 return getcwd();
69             }
70              
71             sub run {
72 6     6 1 23 my ( $self, $before, $after, $ref ) = @_;
73              
74 6 50 33     144 return unless $before and $after and $ref;
      33        
75              
76 6         21 my ( $created, $deleted ) = ( 0, 0 );
77 6 100       37 if ( $before ne '0000000000000000000000000000000000000000' ) {
78 3         9 $before = qx(@{[ $self->_git_cmd() ]} rev-parse $before);
  3         21  
79 3         392 chomp $before;
80             }
81             else {
82 3         12 $created = 1;
83             }
84              
85 6 100       98 if ( $after ne '0000000000000000000000000000000000000000' ) {
86 5         15 $after = qx(@{[ $self->_git_cmd() ]} rev-parse $after);
  5         65  
87 5         679 chomp $after;
88             }
89             else {
90 1         17 $deleted = 1;
91             }
92              
93             return {
94 6         162 before => $before,
95             after => $after,
96             repository => $self->get_repo(),
97             ref => $ref,
98             created => $created,
99             deleted => $deleted,
100             commits => [ $self->get_commits( $before, $after ) ]
101              
102             # head_commit => ... # ?
103             };
104             }
105              
106             sub get_commits {
107 6     6 0 113 my ( $self, $before, $after ) = @_;
108              
109 6         21 my $log_string;
110              
111 6 100 100     99 if ( $before ne '0000000000000000000000000000000000000000'
    100          
112             && $after ne '0000000000000000000000000000000000000000' )
113             {
114 2         12 $log_string = qx(@{[ $self->_git_cmd() ]} rev-list $before...$after);
  2         28  
115             }
116             elsif ( $after ne '0000000000000000000000000000000000000000' ) {
117 3         14 $log_string = qx(@{[ $self->_git_cmd() ]} rev-list $after);
  3         48  
118             }
119              
120 6 100       371 return () unless $log_string;
121              
122 5         154 return reverse map { $self->commit_info($_) } split /\n/, $log_string;
  9         127  
123             }
124              
125             sub commit_info {
126 9     9 0 55 my ( $self, $hash ) = @_;
127              
128 9         23 my $commit
129 9         111 = qx{@{[ $self->_git_cmd() ]} show --format=fuller --date=iso --name-status $hash};
130 9 100       416 $commit = decode( 'utf8', $commit ) if $self->{utf8};
131              
132 9         1036 my @lines = split /\n/, $commit;
133              
134 9         167 my $info = {
135             added => [],
136             removed => [],
137             modified => [] };
138              
139 9         107 for my $line (@lines) {
140 102         208 $_ = $line;
141 102 100       1272 if (m{^commit (.*)$}i) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
142 9         257 $info->{id} = $1;
143             }
144             elsif (m{^author:\s+(.*?)\s<(.*?)>}i) {
145 9         375 $info->{author} = { name => $1, email => $2 };
146             }
147             elsif (m{^commit:\s+(.*?)\s<(.*?)>}i) {
148 9         141 $info->{commiter} = { name => $1, email => $2 };
149             }
150             elsif (m{^authordate:\s+(.*)$}i) {
151 9         64 $info->{timestamp} = $1;
152 9         85 $info->{timestamp} =~ s/ /T/;
153 9         168 $info->{timestamp} =~ s/ ([+-])(\d\d)(\d\d)/$1$2:$3/;
154             }
155             elsif (m{^merge: (\w+)\s+(\w+)}i) {
156 1         37 $info->{merge} = { parent1 => $1, parent2 => $2 };
157             }
158             elsif (m{^A\t(.+)}) {
159 13         20 push @{ $info->{added} }, $1;
  13         77  
160             }
161             elsif (m{^D\t(.+)}) {
162 4         8 push @{ $info->{removed} }, $1;
  4         38  
163             }
164             elsif (m{^M\t(.+)}) {
165 5         9 push @{ $info->{modified} }, $1;
  5         36  
166             }
167             elsif (m{^ (.*)}) {
168 17         84 $info->{message} .= $1 . "\n";
169             }
170             }
171 9         45 chomp $info->{message};
172 9         315 return $info;
173             }
174              
175             1;
176              
177             __END__