File Coverage

blib/lib/Git/Reduce/Tests.pm
Criterion Covered Total %
statement 15 118 12.7
branch 0 58 0.0
condition n/a
subroutine 5 12 41.6
pod 3 4 75.0
total 23 192 11.9


line stmt bran cond sub pod time code
1             package Git::Reduce::Tests;
2 1     1   592 use strict;
  1         2  
  1         56  
3             our $VERSION = '0.10';
4 1     1   450 use Git::Wrapper;
  1         24810  
  1         33  
5 1     1   6 use Carp;
  1         1  
  1         47  
6 1     1   558 use Data::Dumper;$Data::Dumper::Indent=1;
  1         4392  
  1         63  
7 1     1   5 use File::Find qw( find );
  1         1  
  1         1007  
8              
9             =head1 NAME
10              
11             Git::Reduce::Tests - Create a branch with fewer test files for faster development
12              
13             =head1 SYNOPSIS
14              
15             use Git::Reduce::Tests;
16              
17             my $self = Git::Reduce::Tests->new($params);
18             my $reduced_branch = $self->prepare_reduced_branch();
19             $self->push_to_remote($reduced_branch);
20              
21             =head1 DESCRIPTION
22              
23             Git::Reduce::Tests holds the implementation for command-line utility
24             F, which is stored in this distribution's F directory.
25             See that program's documentation (available after installation via C
26             reduce-tests>) or the F for an explanation of that program's
27             functionality.
28              
29             This package exports no functions.
30              
31             =head1 METHODS
32              
33             Git::Reduce::Tests is currently structured as three publicly available methods
34             intended to be called in sequence.
35              
36             =head2 C
37              
38             =over 4
39              
40             =item * Purpose
41              
42             Git::Reduce::Tests constructor. Checks that the directory passed to the
43             C<--dir> option is a git repository and that there are no files there with a
44             modified status.
45              
46             =item * Arguments
47              
48             $self = Git::Reduce::Tests->new($params);
49              
50             Reference to a hash of parameters, typically that provided by
51             C. See that package's
52             documentation for a description of those parameters.
53              
54             =item * Return Value
55              
56             Git::Reduce::Tests object.
57              
58             =back
59              
60             =cut
61              
62             sub new {
63 0     0 1   my ($class, $params) = @_;
64 0           my %data;
65              
66 0           while (my ($k,$v) = each %{$params}) {
  0            
67 0           $data{params}{$k} = $v;
68             }
69 0           $data{git} = Git::Wrapper->new($params->{dir});
70              
71             # Make sure we can check out the branch needing testing.
72 0           check_status(\%data);
73             {
74 0           local $@;
  0            
75 0           eval {$data{git}->checkout($data{params}->{branch}) };
  0            
76 0 0         croak($@) if $@;
77             }
78 0           return bless \%data, $class;
79             }
80              
81             =head2 C
82              
83             =over 4
84              
85             =item * Purpose
86              
87             Creates a new branch whose name is that of the starting branch either (a)
88             prepended with the value of the C<--prefix> option or (b) appended with the
89             value of the C<--suffix> option -- but not B (a) and (b). C<--prefix>
90             is given preference and defaults to C.
91              
92             The method then reduces the size of that branch's test suite either by
93             specifying a limited number of files to be B in the test suite --
94             the comma-delimited argument to the C<--include> option -- or by specifying
95             those files to be B from the test suite -- the comma-delimited
96             argument to the C<--exclude> option.
97              
98             =item * Arguments
99              
100             $reduced_branch = $self->prepare_reduced_branch();
101              
102             None.
103              
104             =item * Return Value
105              
106             String containing the name of the new branch with smaller test suite.
107              
108             =back
109              
110             =cut
111              
112             sub prepare_reduced_branch {
113 0     0 1   my $self = shift;
114              
115             # reduced_branch: temporary branch whose test suite has been reduced in
116             # size
117             # Compose name for reduced_branch
118 0           my $branches = $self->_get_branches();
119 0 0         my $reduced_branch =
120             defined($self->{params}->{suffix})
121             ? $self->{params}->{branch} . $self->{params}->{suffix}
122             : $self->{params}->{prefix} . $self->{params}->{branch};
123              
124             # Customarily, delete any existing branch with temporary branch's name.
125 0 0         unless($self->{params}->{no_delete}) {
126 0 0         if (exists($branches->{$reduced_branch})) {
127 0 0         print "Deleting branch '$reduced_branch'\n"
128             if $self->{params}->{verbose};
129 0           $self->{git}->branch('-D', $reduced_branch);
130             }
131             }
132 0 0         if ($self->{params}->{verbose}) {
133 0           print "Current branches:\n";
134 0           $self->_dump_branches();
135             }
136              
137             # Create the reduced branch.
138             {
139 0           local $@;
  0            
140 0           eval { $self->{git}->checkout('-b', $reduced_branch); };
  0            
141 0 0         croak($@) if $@;
142 0 0         print "Creating branch '$reduced_branch'\n"
143             if $self->{params}->{verbose};
144             }
145              
146             # Locate all test files.
147 0           my @tfiles = ();
148             find(
149             sub {
150 0 0   0     $_ =~ m/\.$self->{params}->{test_extension}$/ and
151             push(@tfiles, $File::Find::name)
152             },
153 0           $self->{params}->{dir}
154             );
155              
156 0           my (@includes, @excludes);
157 0 0         if ($self->{params}->{include}) {
158 0           @includes = split(',' => $self->{params}->{include});
159 0 0         croak("Did not specify test files to be included in reduced branch")
160             unless @includes;
161             }
162 0 0         if ($self->{params}->{exclude}) {
163 0           @excludes = split(',' => $self->{params}->{exclude});
164 0 0         croak("Did not specify test files to be exclude from reduced branch")
165             unless @excludes;
166             }
167 0 0         if ($self->{params}->{verbose}) {
168 0           print "Test files:\n";
169 0           print Dumper [ sort @tfiles ];
170 0 0         if ($self->{params}->{include}) {
171 0           print "Included test files:\n";
172 0           print Dumper(\@includes);
173             }
174 0 0         if ($self->{params}->{exclude}) {
175 0           print "Excluded test files:\n";
176 0           print Dumper(\@excludes);
177             }
178             }
179             # Create lookup tables for test files to be included in,
180             # or excluded from, the reduced branch.
181 0           my %included = map { +qq{$self->{params}->{dir}/$_} => 1 } @includes;
  0            
182 0           my %excluded = map { +qq{$self->{params}->{dir}/$_} => 1 } @excludes;
  0            
183 0           my @removed = ();
184 0 0         if ($self->{params}->{include}) {
185 0           @removed = grep { ! exists($included{$_}) } sort @tfiles;
  0            
186             }
187 0 0         if ($self->{params}->{exclude}) {
188 0           @removed = grep { exists($excluded{$_}) } sort @tfiles;
  0            
189             }
190 0 0         if ($self->{params}->{verbose}) {
191 0           print "Test files to be removed:\n";
192 0           print Dumper(\@removed);
193             }
194              
195             # Remove undesired test files and commit the reduced branch.
196 0           $self->{git}->rm(@removed);
197 0           $self->{git}->commit( '-m', "Remove unwanted test files" );
198 0           return ($reduced_branch);
199             }
200              
201             =head2 C
202              
203             =over 4
204              
205             =item * Purpose
206              
207             Push the reduced branch to the remote specified in the C<--remote> option,
208             which defaults to C. This, of course, assumes that the user has
209             permission to perform that action, has proper credentials such as SSH keys,
210             etc.
211              
212             =item * Arguments
213              
214             $self->push_to_remote($reduced_branch);
215              
216             String holding name of branch with reduced test suite -- typically the return
217             value of the C method.
218              
219             =item * Return Value
220              
221             Implicitly returns a true value upon success.
222              
223             =back
224              
225             =cut
226              
227             sub push_to_remote {
228 0     0 1   my ($self, $reduced_branch) = @_;
229 0 0         unless ($self->{params}->{no_push}) {
230 0           local $@;
231 0           eval { $self->{git}->push($self->{params}->{remote}, "+$reduced_branch"); };
  0            
232 0 0         croak($@) if $@;
233 0 0         print "Pushing '$reduced_branch' to $self->{params}->{remote}\n"
234             if $self->{params}->{verbose};
235             }
236 0 0         print "Finished!\n" if $self->{params}->{verbose};
237             }
238              
239             ##### INTERNAL METHODS #####
240              
241             sub _get_branches {
242 0     0     my $self = shift;
243 0           my @branches = $self->{git}->branch;
244 0           my %branches;
245              
246 0           for (@branches) {
247 0 0         if (m/^\*\s+(.*)/) {
248 0           my $br = $1;
249 0           $branches{$br} = 'current';
250             }
251             else {
252 0 0         if (m/^\s+(.*)/) {
253 0           my $br = $1;
254 0           $branches{$br} = 1;
255             }
256             else {
257 0           croak "Could not get branch";
258             }
259             }
260             }
261 0           return \%branches;
262             }
263              
264             sub _dump_branches {
265 0     0     my $self = shift;
266 0           my $branches = $self->_get_branches();
267 0           print Dumper $branches;
268             }
269              
270             ##### INTERNAL SUBROUTINE #####
271              
272             sub check_status {
273 0     0 0   my $dataref = shift;
274 0           my $statuses = $dataref->{git}->status;
275 0 0         if (! $statuses->is_dirty) {
276 0 0         print "git status okay\n" if $dataref->{params}->{verbose};
277 0           return 1;
278             }
279 0           my $msg = '';
280 0           for my $type (qw) {
281 0 0         my @states = $statuses->get($type)
282             or next;
283 0           $msg .= "Files in state $type\n";
284 0           for (@states) {
285 0           $msg .= ' ' . $_->mode . ' ' . $_->from;
286 0 0         if ($_->mode eq 'renamed') {
287 0           $msg .= ' renamed to ' . $_->to;
288             }
289 0           $msg .= "\n";
290             }
291             }
292 0           croak($msg);
293             }
294              
295             =head1 BUGS
296              
297             There are no bug reports outstanding as of the most recent
298             CPAN upload date of this distribution.
299              
300             =head1 SUPPORT
301              
302             Please report any bugs by mail to C
303             or through the web interface at L.
304              
305             =head1 AUTHOR
306              
307             James E. Keenan (jkeenan@cpan.org). When sending correspondence, please
308             include 'reduce-tests' or 'Git-Reduce-Tests' in your subject line.
309              
310             Creation date: August 03 2014. Last modification date: August 04 2014.
311              
312             Development repository: L
313              
314             =head1 COPYRIGHT
315              
316             Copyright (c) 2014 James E. Keenan. United States. All rights reserved.
317             This is free software and may be distributed under the same terms as Perl
318             itself.
319              
320             =head1 DISCLAIMER OF WARRANTY
321              
322             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
323             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
324             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
325             PROVIDE THE SOFTWARE ''AS IS'' WITHOUT WARRANTY OF ANY KIND, EITHER
326             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
327             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
328             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
329             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
330             NECESSARY SERVICING, REPAIR, OR CORRECTION.
331              
332             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
333             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
334             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
335             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
336             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
337             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
338             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
339             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
340             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
341             SUCH DAMAGES.
342              
343             =cut
344              
345             1;