File Coverage

blib/lib/Git/Lint/Check/Commit.pm
Criterion Covered Total %
statement 71 73 97.2
branch 24 26 92.3
condition 5 6 83.3
subroutine 10 10 100.0
pod 4 4 100.0
total 114 119 95.8


line stmt bran cond sub pod time code
1             package Git::Lint::Check::Commit;
2              
3 7     7   4865 use strict;
  7         18  
  7         174  
4 7     7   30 use warnings;
  7         12  
  7         180  
5              
6 7     7   30 use parent 'Git::Lint::Check';
  7         9  
  7         54  
7              
8 7     7   2459 use Git::Lint::Command;
  7         19  
  7         4490  
9              
10             our $VERSION = '0.015';
11              
12             sub diff {
13 1     1 1 10 my $self = shift;
14              
15 1         3 my $diff_arref = $self->_diff_index( $self->_against );
16              
17 1         5 return $diff_arref;
18             }
19              
20             sub _against {
21 3     3   70 my $self = shift;
22              
23 3         7 my @git_head_cmd = (qw{ git show-ref --head });
24              
25 3         6 my $against;
26 3         8 my ( $stdout, $stderr, $exit ) = Git::Lint::Command::run( \@git_head_cmd );
27              
28             # show-ref --head returns 1 if there are no prior commits, but doesn't
29             # return a message to stderr. since we need to halt for other errors and
30             # can't rely on the error code alone, checking for stderr seems like the
31             # least worst way to detect if we encountered any other errors.
32             # checking the error string for 'fatal: Needed a single revision' was
33             # the previous way we were checking for initial commit, but seemed more
34             # brittle over the long term to check for a specific error string.
35 3 100 66     18 if ( $exit && $stderr ) {
36 1         12 die "git-lint: $stderr\n";
37             }
38              
39 2 100       6 if ($stdout) {
40 1         2 $against = 'HEAD';
41             }
42             else {
43             # Initial commit: diff against an empty tree object
44 1         3 $against = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
45             }
46              
47 2         5 return $against;
48             }
49              
50             sub _diff_index {
51 2     2   51 my $self = shift;
52 2         3 my $against = shift;
53              
54 2         5 my @git_diff_index_cmd = ( qw{ git diff-index -p -M --cached }, $against );
55              
56 2         6 my ( $stdout, $stderr, $exit ) = Git::Lint::Command::run( \@git_diff_index_cmd );
57              
58 2 100       11 die "git-lint: $stderr\n" if $exit;
59              
60 1         4 return [ split( /\n/, $stdout ) ];
61             }
62              
63             sub format_issue {
64 6     6 1 124 my $self = shift;
65 6         22 my $args = {
66             filename => undef,
67             check => undef,
68             lineno => undef,
69             @_,
70             };
71              
72 6         20 foreach ( keys %{$args} ) {
  6         16  
73             die "$_ is a required argument"
74 14 100       52 unless defined $args->{$_};
75             }
76              
77 3         11 my $message = $args->{check} . ' (line ' . $args->{lineno} . ')';
78              
79 3         19 return { filename => $args->{filename}, message => $message };
80             }
81              
82             sub get_filename {
83 9     9 1 9 my $self = shift;
84 9         12 my $line = shift;
85              
86 9         11 my $filename;
87 9 100       18 if ( $line =~ m|^diff --git a/(.*) b/\1$| ) {
88 1         2 $filename = $1;
89             }
90              
91 9         16 return $filename;
92             }
93              
94             sub parse {
95 5     5 1 148 my $self = shift;
96 5         14 my $args = {
97             input => undef,
98             match => undef,
99             check => undef,
100             @_,
101             };
102              
103 5         11 foreach ( keys %{$args} ) {
  5         14  
104             die "$_ is a required argument"
105 12 100       49 unless defined $args->{$_};
106             }
107              
108             die 'match argument must be a code ref'
109 2 100       13 unless ref $args->{match} eq 'CODE';
110              
111 1         2 my @issues;
112             my $filename;
113 1         0 my $lineno;
114              
115 1         2 foreach my $line ( @{ $args->{input} } ) {
  1         2  
116 9         15 my $ret = $self->get_filename($line);
117 9 100       13 if ($ret) {
118 1         2 $filename = $ret;
119 1         2 next;
120             }
121              
122 8 100       15 if ( $line =~ /^@@ -\S+ \+(\d+)/ ) {
123 1         3 $lineno = $1 - 1;
124 1         1 next;
125             }
126              
127 7 50       11 if ( $line =~ /^ / ) {
128 0         0 $lineno++;
129 0         0 next;
130             }
131              
132 7 100 100     22 if ( $line =~ /^--- / || $line =~ /^\+\+\+ / ) {
133 2         3 $lineno++;
134 2         3 next;
135             }
136              
137 5 100       13 if ( $line =~ s/^\+// ) {
138 2         3 $lineno++;
139 2         3 chomp $line;
140              
141 2 50       5 if ( $args->{match}->($line) ) {
142             push @issues,
143             $self->format_issue(
144             filename => $filename,
145             check => $args->{check},
146 2         15 lineno => $lineno,
147             );
148             }
149             }
150             }
151              
152 1         4 return @issues;
153             }
154              
155             1;
156              
157             __END__