File Coverage

blib/lib/App/GitHooks/Utils.pm
Criterion Covered Total %
statement 15 54 27.7
branch 0 16 0.0
condition 0 16 0.0
subroutine 5 11 45.4
pod 4 4 100.0
total 24 101 23.7


line stmt bran cond sub pod time code
1             package App::GitHooks::Utils;
2              
3 13     13   18333 use strict;
  13         19  
  13         395  
4 13     13   52 use warnings;
  13         13  
  13         287  
5              
6             # External dependencies.
7 13     13   59 use Carp;
  13         20  
  13         656  
8 13     13   62 use File::Spec;
  13         16  
  13         239  
9 13     13   5968 use Try::Tiny;
  13         13247  
  13         8459  
10              
11             # No internal dependencies - keep this as a leaf module in the graph so that we
12             # can include it everywhere.
13              
14              
15             =head1 NAME
16              
17             App::GitHooks::Utils - Support functions for App::GitHooks and its plugins.
18              
19              
20             =head1 VERSION
21              
22             Version 1.7.3
23              
24             =cut
25              
26             our $VERSION = '1.7.3';
27              
28              
29             =head2 get_project_prefixes()
30              
31             Get an arrayref of valid project prefixes.
32              
33             my $project_prefixes = App::GitHooks::Utils::get_project_prefixes( $app );
34              
35             Arguments:
36              
37             =over 4
38              
39             =item * $app
40              
41             An C instance.
42              
43             =back
44              
45             =cut
46              
47             sub get_project_prefixes
48             {
49 0     0 1   my ( $app ) = @_;
50 0   0       my $config_line = $app->get_config()->{'_'}->{'project_prefixes'} // '';
51              
52             # Strip leading/trailing whitespace.
53 0           $config_line =~ s/(?:^\s+|\s+$)//g;
54              
55 0           return [ split( /\s*[, ]\s*/, $config_line ) ];
56             }
57              
58              
59             =head2 get_project_prefix_regex()
60              
61             Return a non-capturing regex that will match all the valid project prefixes.
62              
63             my $project_prefix_regex = App::GitHooks::Utils::get_project_prefix_regex( $app );
64              
65             Arguments:
66              
67             =over 4
68              
69             =item * $app
70              
71             An C instance.
72              
73             =back
74              
75             =cut
76              
77             sub get_project_prefix_regex
78             {
79 0     0 1   my ( $app ) = @_;
80              
81 0           my $prefixes = get_project_prefixes( $app );
82              
83 0 0         if ( scalar( @$prefixes ) == 0 )
    0          
84             {
85 0           return '';
86             }
87             elsif ( scalar( @$prefixes ) == 1 )
88             {
89 0           return $prefixes->[0];
90             }
91             else
92             {
93 0           return '(?:' . join( '|', @$prefixes ) . ')';
94             }
95             }
96              
97              
98             =head2 get_ticket_id_from_commit_regex()
99              
100             Return a regex that will extract a ticket ID from a commit message, if it
101             exists.
102              
103             my $ticket_id_regex = App::GitHooks::Utils::get_ticket_id_from_commit_regex( $app );
104              
105             Arguments:
106              
107             =over 4
108              
109             =item * $app
110              
111             An C instance.
112              
113             =back
114              
115             =cut
116              
117             sub get_ticket_id_from_commit_regex
118             {
119 0     0 1   my ( $app ) = @_;
120 0           my $config = $app->get_config();
121              
122             # Retrieve the regular expression from the config or use a default.
123 0   0       my $ticket_regex = $app->get_config()->get_regex( '_', 'extract_ticket_id_from_commit' )
124             // '^($project_prefixes-\d+|--)\: ?';
125              
126             # Replace the list of project prefixes if it is mentioned in the regex.
127 0           my $project_prefix_regex = get_project_prefix_regex( $app );
128 0           $ticket_regex =~ s/\$project_prefixes/$project_prefix_regex/g;
129              
130 0           return $ticket_regex;
131             }
132              
133              
134             =head2 get_ticket_id_from_branch_name()
135              
136             Return the ticket ID derived from the name of the current branch for this
137             repository.
138              
139             my $ticket_id = App::GitHooks::Utils::get_ticket_id_from_branch_name( $app );
140              
141             Arguments:
142              
143             =over 4
144              
145             =item * $app
146              
147             An C instance.
148              
149             =back
150              
151             =cut
152              
153             sub get_ticket_id_from_branch_name
154             {
155 0     0 1   my ( $app ) = @_;
156 0           my $repository = $app->get_repository();
157 0           my $config = $app->get_config();
158              
159             # If the config doesn't specify a way to extract the ticket ID from the
160             # branch, there's nothing we can do here.
161 0           my $ticket_regex = $config->get_regex( '_', 'extract_ticket_id_from_branch' );
162             return undef
163 0 0         if !defined( $ticket_regex );
164              
165             # Check if we're in a rebase. During a rebase (regardless of whether it's
166             # interractive or not), the HEAD goes in a detached state, and we won't be
167             # able to call symbolic-ref on it to get a branch name.
168 0           my $git_directory = $repository->git_dir();
169             return undef
170 0 0 0       if ( -d File::Spec->catfile( $git_directory, 'rebase-merge' ) ) # detect rebase -i
171             || ( -d File::Spec->catfile( $git_directory, 'rebase-apply' ) ); # detect rebase
172              
173 0           my $ticket_id;
174             try
175             {
176              
177             # Retrieve the branch name.
178 0     0     my $branch_name = $repository->run('symbolic-ref', 'HEAD');
179 0           my ( $branch_name_without_prefixes ) = $branch_name =~ /([^\/]+)$/;
180              
181             # Extract the ticket ID from the branch name.
182 0           my $project_prefix_regex = get_project_prefix_regex( $app );
183 0           $ticket_regex =~ s/\$project_prefixes/$project_prefix_regex/g;
184 0           ( $ticket_id ) = $branch_name_without_prefixes =~ /$ticket_regex/i;
185              
186 0           my $normalize = $config->get( '_', 'normalize_branch_ticket_id' );
187 0 0 0       if ( defined( $ticket_id ) && defined( $normalize ) && ( $normalize =~ /\S/ ) )
      0        
188             {
189 0           my ( $match, $replacement ) = $normalize =~ m|^\s*s/(.*?)(?
190 0 0 0       croak "Invalid format for 'normalize_branch_ticket_id' in configuration file."
191             if !defined( $match ) || !defined( $replacement );
192 0 0         croak "Unsafe matching pattern in 'normalize_branch_ticket_id', escape your slashes"
193             if $match =~ /(?
194 0 0         croak "Unsafe replacement pattern in 'normalize_branch_ticket_id', escape your slashes"
195             if $replacement =~ /(?
196 0           eval( "\$ticket_id =~ s/$match/$replacement/i" ); ## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval)
197             }
198             }
199             catch
200             {
201 0     0     carp "ERROR: $_";
202 0           };
203              
204 0           return $ticket_id;
205             }
206              
207              
208             =head1 BUGS
209              
210             Please report any bugs or feature requests through the web interface at
211             L.
212             I will be notified, and then you'll automatically be notified of progress on
213             your bug as I make changes.
214              
215              
216             =head1 SUPPORT
217              
218             You can find documentation for this module with the perldoc command.
219              
220             perldoc App::GitHooks::Utils
221              
222              
223             You can also look for information at:
224              
225             =over
226              
227             =item * GitHub's request tracker
228              
229             L
230              
231             =item * AnnoCPAN: Annotated CPAN documentation
232              
233             L
234              
235             =item * CPAN Ratings
236              
237             L
238              
239             =item * MetaCPAN
240              
241             L
242              
243             =back
244              
245              
246             =head1 AUTHOR
247              
248             L,
249             C<< >>.
250              
251              
252             =head1 COPYRIGHT & LICENSE
253              
254             Copyright 2013-2015 Guillaume Aubert.
255              
256             This program is free software: you can redistribute it and/or modify it under
257             the terms of the GNU General Public License version 3 as published by the Free
258             Software Foundation.
259              
260             This program is distributed in the hope that it will be useful, but WITHOUT ANY
261             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
262             PARTICULAR PURPOSE. See the GNU General Public License for more details.
263              
264             You should have received a copy of the GNU General Public License along with
265             this program. If not, see http://www.gnu.org/licenses/
266              
267             =cut
268              
269             1;