File Coverage

blib/lib/App/Git/Workflow/Command/BranchClean.pm
Criterion Covered Total %
statement 74 78 94.8
branch 42 44 95.4
condition 8 10 80.0
subroutine 11 11 100.0
pod 5 5 100.0
total 140 148 94.5


line stmt bran cond sub pod time code
1              
2             # Created on: 2014-03-11 20:58:59
3             # Create by: Ivan Wills
4             # $Id$
5             # $Revision$, $HeadURL$, $Date$
6             # $Revision$, $Source$, $Date$
7              
8             use strict;
9 3     3   149648 use warnings;
  3         22  
  3         79  
10 3     3   13 use version;
  3         6  
  3         67  
11 3     3   629 use English qw/ -no_match_vars /;
  3         2786  
  3         16  
12 3     3   914 use App::Git::Workflow;
  3         5011  
  3         17  
13 3     3   1513 use App::Git::Workflow::Command qw/get_options/;
  3         8  
  3         109  
14 3     3   749  
  3         5  
  3         2562  
15             our $VERSION = version->new(1.1.20);
16             our $workflow = App::Git::Workflow->new;
17             my ($name) = $PROGRAM_NAME =~ m{^.*/(.*?)$}mxs;
18             our %option;
19             our %p2u_extra;
20              
21             my ($self) = @_;
22              
23 11     11 1 36 %option = (
24             exclude => [],
25             max_age => ( $ENV{GIT_WORKFLOW_MAX_AGE} || $workflow->config('workflow.max') || 120 ),
26             tag_prefix => '',
27 11   100     60 tag_suffix => '',
28             );
29             get_options(
30             \%option,
31 11 100       42 'remote|r',
32             'all|a',
33             'exclude|e=s@',
34             'exclude_file|exclude-file|f=s',
35             'max_age|max-age|m=i',
36             'min_age|min-age|n=i',
37             'tag|t!',
38             'tag_prefix|tag-prefix|p=s',
39             'tag_suffix|tag-suffix|s=s',
40             'test!',
41             ) or return;
42              
43             # get the list of branches to look at
44             my $max = 0;
45             my @branches = $workflow->branches($option{remote} ? 'remote' : $option{all} ? 'both' : undef );
46 10         18 my @excludes = @{ $option{exclude} };
47 10 100       51 my $action = 'do_' . ( $ARGV[0] || 'delete' );
    100          
48 10         13 my ($total, $deleted) = (0, 0);
  10         18  
49 10   50     41  
50 10         17 if (!$self->can($action)) {
51             warn "Unknown action $ARGV[0]!\n";
52 10 50       55 Pod::Usage::pod2usage( %p2u_extra, -verbose => 1 );
53 0         0 return 1;
54 0         0 }
55 0         0  
56             if ($option{exclude_file}) {
57             for my $exclude ($workflow->slurp($option{exclude_file})) {
58 10 100       30 chomp $exclude;
59 1         7 next if !$exclude;
60 3         6 next if $exclude =~ /^\s*(?:[#].*)$/xms;
61 3 100       6 push @excludes, $exclude;
62 2 100       8 }
63 1         3 }
64              
65             BRANCH:
66             for my $branch (@branches) {
67             # skip master branches
68 10         18 next BRANCH if $branch =~ m{^ (?:[^/]+/)? master $}xms;
69             next BRANCH if grep {$branch =~ /$_/} @excludes;
70 31 100       89  
71 19 100       36 # get branch details
  2         14  
72             my $details = $workflow->commit_details($branch, branches => 0);
73              
74 18         50 # don't delete young branches even if merged
75             next BRANCH if too_young_to_die($details);
76              
77 18 100       36 $max = $details->{time} if $max < $details->{time};
78             $deleted += __PACKAGE__->$action($branch, $details);
79 16 100       50 $total++;
80 16         46 }
81 16         48  
82             warn "Deleted $deleted of $total branches\nMax = " . (int $max/60/60/24) . "\n";
83              
84 10         184 return;
85             }
86 10         49  
87             my ($self, $branch, $details) = @_;
88              
89             my $too_old = too_old($details);
90 16     16 1 25 my $in_master;
91              
92 16         35 if (!$too_old) {
93 16         21 $in_master = in_master($details);
94             }
95 16 100       31  
96 15         25 if ( $in_master || $too_old ) {
97             warn 'deleting ' . ($in_master ? 'merged' : 'old') . " branch $branch\n";
98              
99 16 100 100     54 my ($remote, $name) = $branch =~ m{/} ? split m{/}, $branch, 2 : (undef, $branch);
100 10 100       353  
101             if ( $option{tag} ) {
102 10 100       61 my $tag = $option{tag_prefix} . $name . $option{tag_suffix};
103             $workflow->git->tag(qw/-a -m /, "Converting '$name' to the tag '$tag'", $tag) if !$option{test};
104 10 100       34 }
105 5         15  
106 5 100       20 if ( !$option{test} ) {
107             if ($remote) {
108             eval {
109 10 100       35 $workflow->git->push($remote, '--no-verify', ":refs/heads/$name");
110 8 100       15 1;
111             } or do {
112 2         8 return 0;
113 2         6 }
114 2 50       3 }
115 0         0 else {
116             $workflow->git->branch('-D', "$name");
117             }
118             }
119 6         18  
120             return 1;
121             }
122              
123 10         26 return 0;
124             }
125              
126 6         11 my ($details) = @_;
127              
128             my %branches = map { $_ => 1 } $workflow->branches('both', $details->{sha});
129              
130 15     15 1 20 return $branches{master} || $branches{'origin/master'};
131             }
132 15         37  
  23         55  
133             my ($details) = @_;
134 15   66     51  
135             return if !$option{max_age};
136              
137             return time - $option{max_age} * 60 * 60 * 24 > $details->{time};
138 16     16 1 22 }
139              
140 16 100       28 my ($details) = @_;
141              
142 15         38 return if !$option{min_age};
143              
144             return time - $option{min_age} * 60 * 60 * 24 < $details->{time};
145             }
146 18     18 1 26  
147             1;
148 18 100       39  
149              
150 4         16 =head1 NAME
151              
152             git-branch-clean - Clean old branches out of the repository
153              
154             =head1 VERSION
155              
156             This documentation refers to git-branch-clean version 1.1.20
157              
158             =head1 SYNOPSIS
159              
160             git-branch-clean [option]
161              
162             OPTIONS:
163             -r --remote Only remote branches (defaults to local branches)
164             -a --all All branches
165             -m --max-age[=]days
166             Maximum age of a branch with out changes before it is cleaned
167             weather it's merged to master or not. (Default 0, no max age)
168             -n --min-age[=]days
169             Leave branches this number of days or new alone even if merged
170             to master. (default 7 days)
171             -e --exclude[=]regex
172             Regular expression to exclude specific branches from deletion.
173             You can specify --exclude multiple times for more control.
174             --exclude-file[=]file
175             A file of exclude regular expressions, blank lines and lines
176             starting with a hash (#) are ignored.
177             -t --tag Create tags of the same name as the branch
178             -p --tag-prefix[=]str
179             When converting a branch to a tag prepend it with "str"
180             -s --tag-suffix[=]str
181             When converting a branch to a tag apend it with "str"
182             --test Don't actually delete branches just report on what branches
183             would be deleted.
184              
185             -v --verbose Show more detailed option
186             --version Prints the version information
187             --help Prints this help information
188             --man Prints the full documentation for git-branch-clean
189              
190             =head1 DESCRIPTION
191              
192             C<git-branch-clean> deletes branches merged to master (but not newer than
193             C<--min-age> days). Optionally also deleting branches that haven't been
194             modified more than C<--max-age> days. When deleting branches they can be
195             converted to tags (C<--tag>) with optional an prefix (C<--tag-prefix>) and/or
196             an optional suffix (C<--tag-suffix>) added.
197              
198             =head1 SUBROUTINES/METHODS
199              
200             =head2 C<run ()>
201              
202             Executes the git workflow command
203              
204             =head2 C<do_delete ($branch, $details)>
205              
206             Performs the deleting of old branches.
207              
208             =head2 C<in_master ($details)>
209              
210             The branch with C<$details> has been merged to master
211              
212             =head2 C<too_old ($details)>
213              
214             The branch with C<$details> has not been modified in greater than C<--max-age>
215             days.
216              
217             =head2 C<too_young_to_die ($details)>
218              
219             The branch was only recently used and should be cleaned.
220              
221             =head1 DIAGNOSTICS
222              
223             =head1 CONFIGURATION AND ENVIRONMENT
224              
225             =head1 DEPENDENCIES
226              
227             =head1 INCOMPATIBILITIES
228              
229             =head1 BUGS AND LIMITATIONS
230              
231             There are no known bugs in this module.
232              
233             Please report problems to Ivan Wills (ivan.wills@gmail.com).
234              
235             Patches are welcome.
236              
237             =head1 AUTHOR
238              
239             Ivan Wills - (ivan.wills@gmail.com)
240              
241             =head1 LICENSE AND COPYRIGHT
242              
243             Copyright (c) 2014 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
244             All rights reserved.
245              
246             This module is free software; you can redistribute it and/or modify it under
247             the same terms as Perl itself. See L<perlartistic>. This program is
248             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
249             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
250             PARTICULAR PURPOSE.
251              
252             =cut