File Coverage

blib/lib/App/GitHooks/Plugin/PreventTrailingWhitespace.pm
Criterion Covered Total %
statement 43 48 89.5
branch 8 14 57.1
condition n/a
subroutine 8 8 100.0
pod 3 3 100.0
total 62 73 84.9


line stmt bran cond sub pod time code
1             package App::GitHooks::Plugin::PreventTrailingWhitespace;
2              
3 11     11   25373542 use strict;
  11         24  
  11         384  
4 11     11   57 use warnings;
  11         16  
  11         330  
5              
6 11     11   58 use base 'App::GitHooks::Plugin';
  11         23  
  11         3642  
7              
8             # External dependencies.
9 11     11   4225 use File::Slurp;
  11         51309  
  11         931  
10              
11             # Internal dependencies.
12 11     11   3064 use App::GitHooks::Constants qw( :PLUGIN_RETURN_CODES );
  11         1021  
  11         8686  
13              
14              
15             =head1 NAME
16              
17             App::GitHooks::Plugin::PreventTrailingWhitespace - Prevent trailing whitespace from being committed.
18              
19              
20             =head1 DESCRIPTION
21              
22             Prevent pesky trailing whitespace from being committed.
23              
24             =head1 VERSION
25              
26             Version 1.0.1
27              
28             =cut
29              
30             our $VERSION = '1.0.1';
31              
32              
33             =head1 METHODS
34              
35             =head2 get_file_pattern()
36              
37             Return a pattern to filter the files this plugin should analyze.
38              
39             my $file_pattern = App::GitHooks::Plugin::PreventTrailingWhitespace->get_file_pattern(
40             app => $app,
41             );
42              
43             =cut
44              
45             sub get_file_pattern
46             {
47 9     9 1 19440370 return qr/\.(?:pl|pm|t|cgi|js|tt|css|html|rb)$/x;
48             }
49              
50              
51             =head2 get_file_check_description()
52              
53             Return a description of the check performed on files by the plugin and that
54             will be displayed to the user, if applicable, along with an indication of the
55             success or failure of the plugin.
56              
57             my $description = App::GitHooks::Plugin::PreventTrailingWhitespace->get_file_check_description();
58              
59             =cut
60              
61             sub get_file_check_description
62             {
63 9     9 1 9086 return 'The file has no lines with trailing white space.';
64             }
65              
66              
67             =head2 run_pre_commit_file()
68              
69             Code to execute for each file as part of the pre-commit hook.
70              
71             This is where the magic happens.
72              
73             my $success = App::GitHooks::Plugin::PreventTrailingWhitespace->run_pre_commit_file();
74              
75             =cut
76              
77             sub run_pre_commit_file
78             {
79 4     4 1 10073 my ( $class, %args ) = @_;
80 4         282 my $file = delete( $args{'file'} );
81 4         92 my $git_action = delete( $args{'git_action'} );
82 4         71 my $app = delete( $args{'app'} );
83 4         285 my $staged_changes = $app->get_staged_changes();
84 4         295 my $repository = $app->get_repository();
85              
86             # Ignore deleted files.
87 4 50       202 return $PLUGIN_RETURN_SKIPPED
88             if $git_action eq 'D';
89              
90             # Ignore merges, since they correspond mostly to code written by other people.
91 4 50       176 return $PLUGIN_RETURN_SKIPPED
92             if $staged_changes->is_merge();
93              
94             # Ignore revert commits.
95 4 50       663 return $PLUGIN_RETURN_SKIPPED
96             if $staged_changes->is_revert();
97              
98             # Determine what lines were written by the current user.
99 4         87 my @review_lines = ();
100 4 50       54 if ( $git_action eq 'A' )
101             {
102             # "git blame" fails on new files, so we need to add the entire file
103             # separately.
104 4         179 my @lines = File::Slurp::read_file( $file );
105 4         4836 foreach my $i ( 0 .. scalar( @lines ) - 1 )
106             {
107 17         64 chomp( $lines[$i] );
108 17         109 push(
109             @review_lines,
110             {
111             line_number => $i,
112             code => $lines[$i],
113             }
114             );
115             }
116             }
117             else
118             {
119             # Find uncommitted lines only.
120 0         0 my $blame_lines = $repository->blame(
121             $file,
122             use_cache => 1,
123             );
124              
125 0         0 foreach my $blame_line ( @$blame_lines )
126             {
127 0         0 my $commit_attributes = $blame_line->get_commit_attributes();
128 0 0       0 next unless $commit_attributes->{'author-mail'} eq 'not.committed.yet';
129 0         0 push(
130             @review_lines,
131             {
132             line_number => $blame_line->get_line_number(),
133             code => $blame_line->get_line(),
134             }
135             );
136             }
137             }
138              
139             # Inspect uncommitted lines for trailing white space
140 4         19 my @whitespace_violations = ();
141 4         27 foreach my $line ( @review_lines )
142             {
143 17         46 my $code = $line->{'code'};
144 17         158 my ( $trailing_whitespace ) = $code =~ m/(\s+)$/;
145 17 100       82 next if !defined( $trailing_whitespace );
146              
147 3         128 my $redspace = '';
148 3         65 $redspace .= $app->color('on_red', $_) foreach (split //, $trailing_whitespace);
149 3         1141 ( my $badline = $code ) =~ s/\s+$/$redspace/;
150 3         78 push(
151             @whitespace_violations,
152             sprintf( "line #%d: %s\n", $line->{'line_number'}, $badline )
153             );
154             }
155              
156 4 100       158 die "Trailing white space found:\n" . join( '', @whitespace_violations ) . "\n"
157             if scalar( @whitespace_violations ) != 0;
158              
159 1         9 return $PLUGIN_RETURN_PASSED;
160             }
161              
162             =head1 BUGS
163              
164             Please report any bugs or feature requests through the web interface at
165             L.
166              
167              
168             =head1 SUPPORT
169              
170             You can find documentation for this module with the perldoc command.
171              
172             perldoc App::GitHooks::Plugin::PreventTrailingWhitespace
173              
174              
175             You can also look for information at:
176              
177             =over
178              
179             =item * GitHub's request tracker
180              
181             L
182              
183             =item * AnnoCPAN: Annotated CPAN documentation
184              
185             L
186              
187             =item * CPAN Ratings
188              
189             L
190              
191             =item * MetaCPAN
192              
193             L
194              
195             =back
196              
197              
198             =head1 AUTHOR
199              
200             L,
201             C<< >>.
202              
203             =head1 ACKNOWLEDGEMENTS
204              
205             For guidance on this module and for creating App::GitHooks, big thanks to:
206              
207             L,
208             C<< >>.
209              
210             =head1 COPYRIGHT & LICENSE
211              
212             Copyright 2013-2014 Ben Arwin.
213              
214             This program is free software: you can redistribute it and/or modify it under
215             the terms of the GNU General Public License version 3 as published by the Free
216             Software Foundation.
217              
218             This program is distributed in the hope that it will be useful, but WITHOUT ANY
219             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
220             PARTICULAR PURPOSE. See the GNU General Public License for more details.
221              
222             You should have received a copy of the GNU General Public License along with
223             this program. If not, see http://www.gnu.org/licenses/
224              
225             =cut
226              
227             1;