File Coverage

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 6     6   3975 use strict;
  6         12  
  6         152  
4 6     6   28 use warnings;
  6         12  
  6         145  
5              
6 6     6   26 use parent 'Git::Lint::Check';
  6         8  
  6         32  
7              
8 6     6   2324 use Git::Lint::Command;
  6         15  
  6         3743  
9              
10             our $VERSION = '0.016';
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         6 return $diff_arref;
18             }
19              
20             sub _against {
21 3     3   43 my $self = shift;
22              
23 3         7 my @git_head_cmd = (qw{ git show-ref --head });
24              
25 3         4 my $against;
26 3         14 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     16 if ( $exit && $stderr ) {
36 1         7 die "git-lint: $stderr\n";
37             }
38              
39 2 100       8 if ($stdout) {
40 1         2 $against = 'HEAD';
41             }
42             else {
43             # Initial commit: diff against an empty tree object
44 1         2 $against = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
45             }
46              
47 2         5 return $against;
48             }
49              
50             sub _diff_index {
51 2     2   66 my $self = shift;
52 2         6 my $against = shift;
53              
54 2         7 my @git_diff_index_cmd = ( qw{ git diff-index -p -M --cached }, $against );
55              
56 2         10 my ( $stdout, $stderr, $exit ) = Git::Lint::Command::run( \@git_diff_index_cmd );
57              
58 2 100       18 die "git-lint: $stderr\n" if $exit;
59              
60 1         7 return [ split( /\n/, $stdout ) ];
61             }
62              
63             sub format_issue {
64 6     6 1 113 my $self = shift;
65 6         20 my $args = {
66             filename => undef,
67             check => undef,
68             lineno => undef,
69             @_,
70             };
71              
72 6         10 foreach ( keys %{$args} ) {
  6         31  
73             die "$_ is a required argument"
74 13 100       51 unless defined $args->{$_};
75             }
76              
77 3         10 my $message = $args->{check} . ' (line ' . $args->{lineno} . ')';
78              
79 3         23 return { filename => $args->{filename}, message => $message };
80             }
81              
82             sub get_filename {
83 9     9 1 11 my $self = shift;
84 9         13 my $line = shift;
85              
86 9         11 my $filename;
87 9 100       19 if ( $line =~ m|^diff --git a/(.*) b/\1$| ) {
88 1         3 $filename = $1;
89             }
90              
91 9         16 return $filename;
92             }
93              
94             sub parse {
95 5     5 1 146 my $self = shift;
96 5         16 my $args = {
97             input => undef,
98             match => undef,
99             check => undef,
100             @_,
101             };
102              
103 5         8 foreach ( keys %{$args} ) {
  5         14  
104             die "$_ is a required argument"
105 14 100       50 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         13 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       16 if ( $line =~ /^@@ -\S+ \+(\d+)/ ) {
123 1         3 $lineno = $1 - 1;
124 1         2 next;
125             }
126              
127 7 50       12 if ( $line =~ /^ / ) {
128 0         0 $lineno++;
129 0         0 next;
130             }
131              
132 7 100 100     26 if ( $line =~ /^--- / || $line =~ /^\+\+\+ / ) {
133 2         3 $lineno++;
134 2         4 next;
135             }
136              
137 5 100       13 if ( $line =~ s/^\+// ) {
138 2         3 $lineno++;
139 2         4 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         5 return @issues;
153             }
154              
155             1;
156              
157             __END__