File Coverage

blib/lib/App/Git/Workflow/Command/Watch.pm
Criterion Covered Total %
statement 107 110 97.2
branch 39 44 88.6
condition 17 18 94.4
subroutine 11 11 100.0
pod 5 5 100.0
total 179 188 95.2


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 2     2   77425 use warnings;
  2         10  
  2         57  
10 2     2   9 use version;
  2         4  
  2         71  
11 2     2   313 use English qw/ -no_match_vars /;
  2         1364  
  2         11  
12 2     2   495 use App::Git::Workflow;
  2         2460  
  2         10  
13 2     2   893 use App::Git::Workflow::Command qw/get_options/;
  2         5  
  2         68  
14 2     2   343  
  2         3  
  2         1898  
15             our $VERSION = version->new(1.1.20);
16             our $workflow = App::Git::Workflow->new;
17             our ($name) = $PROGRAM_NAME =~ m{^.*/(.*?)$}mxs;
18             our %option;
19             my %actions = (
20             show => 1,
21             do => 1,
22             );
23              
24             %option = (
25             max => 10,
26 9     9 1 46 sleep => 60,
27             pull_options => '',
28             );
29             get_options(
30             \%option,
31 9         62 'all|a',
32             'branch|b=s',
33             'pull|p',
34             'pull_options|pull-options|P=s',
35             'file|f=s',
36             'max|m=i',
37             'runs|R=i',
38             'once|1',
39             'quiet|q',
40             'remote|r',
41             'sleep|s=i',
42             );
43              
44             # do stuff here
45             my $action = @ARGV && $actions{$ARGV[0]} ? shift @ARGV : @ARGV ? 'do' : 'show';
46             my ($last) = git_state();
47 9 100 100     58 my $once
    100          
48 9         29 = $option{once} ? -1
49             : $option{runs} ? -$option{runs}
50             : 1;
51              
52 9 0       32 while ($once) {
    50          
53             eval {
54 9         29 my ($id, @rest) = git_state(1);
55 10         17 spin() if $option{verbose};
56 10         19  
57 10 100       42 if ( $last ne $id ) {
58             $once++;
59 10 100       901 my $changes = changes($last, $id, @rest);
60 9         19  
61 9         31 if ( found($changes) ) {
62             if ( $action eq 'show' ) {
63 8 100       22 my $time = $option{verbose} ? ' @ ' . localtime $changes->{time} : '';
64 7 100       21 print "$id$time\n";
65 6 100       142  
66 6         337 if ( !$option{quiet} ) {
67             my $join = $option{verbose} ? "\n " : '';
68 6 100       36 print " Branches: ";
69 5 100       22 print $join, join +($join || ', '), sort keys %{ $changes->{branches} };
70 5         52 print "\n";
71 5   100     28 print " Files: ";
  5         62  
72 5         44 print $join, join +($join || ', '), sort keys %{ $changes->{files} };
73 5         40 print "\n";
74 5   100     25 print " Users: ";
  5         58  
75 5         41 print $join, join +($join || ', '), sort keys %{ $changes->{user} };
76 5         40 print "\n\n";
77 5   100     27 }
  5         63  
78 5         66 }
79             else {
80             $ENV{WATCH_SHA} = $id;
81             $ENV{WATCH_USERS} = join ',', keys %{ $changes->{user} };
82 1         10 $ENV{WATCH_EMAILS} = join ',', keys %{ $changes->{email} };
83 1         3 $ENV{WATCH_FILES} = join ',', keys %{ $changes->{files} };
  1         7  
84 1         3 $ENV{WATCH_BRANCHES} = join ',', keys %{ $changes->{branches} };
  1         7  
85 1         3 system @ARGV;
  1         11  
86 1         3 }
  1         5  
87 1         5289 }
88             }
89              
90             $last = $id;
91             };
92 9         100 sleep $option{sleep};
93             }
94 10         1638  
95             return;
96             }
97 9         70  
98             my ($fetch) = @_;
99             my @out;
100              
101 19     19 1 37 if ( $option{all} || $option{remote} ) {
102 19         23 if ($fetch) {
103             $workflow->git->fetch;
104 19 100 100     87 }
105 8 100       68 @out = $workflow->git->rev_list('--all', "-$option{max}");
106 4         21 }
107             else {
108 8         55 $workflow->git->pull(split /\s+/, $option{pull_options}) if $fetch && $option{pull};
109             @out = $workflow->git->log('--oneline', "-$option{max}");
110             }
111 11 100 100     29  
112 11         40 return map {/^([0-9a-f]+)\s*/; $1} @out;
113             }
114              
115 19         43 my ($changes) = @_;
  163         265  
  163         300  
116              
117             if ($option{file}) {
118             return 1 if grep {/$option{file}/} keys %{ $changes->{files} };
119 8     8 1 18 }
120              
121 8 100       23 if ($option{branch}) {
122 2 100       5 return 1 if grep {/$option{branch}/} keys %{ $changes->{branches} };
  6         59  
  2         8  
123             }
124              
125 7 100       19 return !$option{file} && !$option{branch};
126 2 100       6 }
  4         37  
  2         93  
127              
128             my ($last, $newest, @ids) = @_;
129 6   66     42 my $changes = $workflow->commit_details($newest, branches => 1, files => 1, user => 1 );
130              
131             $changes->{user} = { $changes->{user} => 1 };
132             $changes->{email} = { $changes->{email} => 1 };
133 9     9 1 41  
134 9         59 for my $id (@ids) {
135             last if $id eq $last;
136 9         43 my $change = $workflow->commit_details($id, branches => 1, files => 1, user => 1 );
137 9         30  
138             $changes->{files} = { %{$changes->{files}}, %{$change->{files}} };
139 9         34 $changes->{branches} = { %{$changes->{branches}}, %{$change->{branches}} };
140 12 100       35 $changes->{user} = { %{$changes->{user}}, $change->{user} => 1 };
141 4         16 $changes->{email} = { %{$changes->{email}}, $change->{email} => 1 };
142             }
143 3         18  
  3         11  
  3         17  
144 3         11 return $changes;
  3         10  
  3         16  
145 3         7 }
  3         139  
146 3         8  
  3         25  
147             {
148             my $spinner;
149 8         23 if (!defined $spinner) {
150             $spinner = 0;
151             eval { require Term::Spinner };
152             return if $@;
153             $spinner = Term::Spinner->new();
154             }
155 2 100   2 1 12 elsif (!$spinner) {
    50          
156 1         3 print {*STDERR} '.';
157 1         2 return;
  1         360  
158 1 50       454356 }
159 1         13  
160             return $spinner->advance;
161             }
162 0         0 }
  0         0  
163 0         0  
164             1;
165              
166 2         2551  
167             =head1 NAME
168              
169             git-watch - Watch for changes in repository up-stream
170              
171             =head1 VERSION
172              
173             This documentation refers to git-watch version 1.1.20
174              
175             =head1 SYNOPSIS
176              
177             git-watch show [-1|--once] [(-f|--file) file ...]
178             git-watch [do] [-1|--once] [(-f|--file) file ...] [--] cmd
179              
180             SUB-COMMAND
181             show Simply show when a file
182             do Execute a shell script cmd when a change occurs
183              
184             OPTIONS:
185             -1 --once Run once then exit
186             -R --runs[=]int
187             Run at most this number of times.
188             -p --pull Before checking if anything has changed do a git pull to the
189             current branch. (see notes below)
190             -P --pull-options[=]flags
191             When using --pull add these options to the pull command.
192             -f --file[=]regex
193             Watch file any files changing that match "regex"
194             -b --branch[=]regex
195             Watch for any changes to branches matching "regex"
196             by default looks only at local branches
197             -r --remote With --branch only look at remote branches
198             -a --all With --branch look at all branches (local and remote)
199             -m --max[=]int
200             Look only --max changes back in history to see what is
201             happening (Default 10)
202             -s --sleep[=]int
203             Sleep time between fetches (devault 60s)
204             -q --quiet Suppress notifying of what files and branches have changed
205             -v --verbose Show more detailes
206             --version Prints the version information
207             --help Prints this help information
208             --man Prints the full documentation for git-watch
209              
210             =head1 DESCRIPTION
211              
212             The C<git-watch> command allows you to run a command when something changes.
213             The simple option is C<show> which just shows what has changed when it changes
214             and nothing else, this is useful for seeing what is happening in the
215             repository. The the C<do> sub-command actually runs a script every time a
216             change is detected.
217              
218             =head2 show
219              
220             The output of C<show> is changed with the C<--quiet> and C<--verbose> options to
221             show more or less information.
222              
223             =head2 do
224              
225             When the C<do> sub-command runs it sets the environment variables C<$WATCH_SHA>,
226             C<$WATCH_FILES> and C<$WATCH_BRANCHES> with the latest commit SHA, the files
227             that have changed and the branches that have changed respectively. The files
228             and branches are comma separated for your command to inspect.
229              
230             A simple example:
231              
232             git watch 'echo $WATCH_FILES'
233              
234             This would just echo the files that have changed with each change.
235              
236             =head2 Notes
237              
238             If trying to watch a branch that is connected to a remote branch the C<--pull>
239             isn't currently working as expected. The workaround is to watch the remote
240             branch and do the pull your self. eg
241              
242             $ git watch do -rb origin/master -- 'git pull --ff -r; your-command'
243              
244             =head1 SUBROUTINES/METHODS
245              
246             =head2 C<run ()>
247              
248             Executes the git workflow command
249              
250             =head2 C<git_state ()>
251              
252             =head2 C<found ()>
253              
254             =head2 C<changes ()>
255              
256             =head2 C<spin ()>
257              
258             Helper providing access to Term::Spinner if installed
259              
260             =head1 DIAGNOSTICS
261              
262             =head1 CONFIGURATION AND ENVIRONMENT
263              
264             =head1 DEPENDENCIES
265              
266             =head1 INCOMPATIBILITIES
267              
268             =head1 BUGS AND LIMITATIONS
269              
270             There are no known bugs in this module.
271              
272             Please report problems to Ivan Wills (ivan.wills@gmail.com).
273              
274             Patches are welcome.
275              
276             =head1 AUTHOR
277              
278             Ivan Wills - (ivan.wills@gmail.com)
279              
280             =head1 LICENSE AND COPYRIGHT
281              
282             Copyright (c) 2014 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
283             All rights reserved.
284              
285             This module is free software; you can redistribute it and/or modify it under
286             the same terms as Perl itself. See L<perlartistic>. This program is
287             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
288             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
289             PARTICULAR PURPOSE.
290              
291             =cut