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