File Coverage

blib/lib/Git/Release.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Git::Release;
2 2     2   50834 use strict;
  2         4  
  2         93  
3 2     2   10 use warnings;
  2         4  
  2         77  
4             our $VERSION = '0.05';
5 2     2   10 use feature qw(say switch);
  2         8  
  2         253  
6 2     2   10846 use Moose;
  0            
  0            
7             use Cwd;
8             use Git;
9             use Getopt::Long;
10             use List::MoreUtils qw(uniq);
11             use DateTime;
12             use File::Spec;
13             use Git::Release::Config;
14             use Git::Release::Branch;
15             use Git::Release::BranchManager;
16             use Git::Release::RemoteManager;
17              
18             has directory => ( is => 'rw' , default => sub { getcwd() } );
19              
20             has repo => (
21             is => 'rw',
22             default => sub {
23             my $self = shift;
24             return Git->repository( Directory => $self->directory );
25             }
26             );
27              
28             has config => ( is => 'rw' );
29              
30             has branch => (
31             is => 'rw',
32             isa => 'Git::Release::BranchManager',
33             default => sub {
34             my $self = shift;
35             return Git::Release::BranchManager->new( manager => $self );
36             });
37              
38             has remote => (
39             is => 'rw',
40             isa => 'Git::Release::RemoteManager',
41             default => sub {
42             my $self = shift;
43             return Git::Release::RemoteManager->new( manager => $self );
44             }
45             );
46              
47             sub BUILD {
48             my ($self,$args) = @_;
49             $self->directory( $args->{directory} ) if $args->{directory};
50             $self->config( Git::Release::Config->new( repo => $self->repo ) );
51             return $self;
52             }
53              
54             sub strip_remote_names {
55             my $self = shift;
56             map { s{^remotes\/.*?\/}{}; $_ } @_;
57             }
58              
59             # list all remote, all local branches
60             # contains
61             # local-branch
62             # remotes/origin/branch_name
63              
64             sub list_all_branches {
65             my $self = shift;
66              
67             # remove remtoes names, strip star char.
68             return uniq
69             map { chomp; $_; }
70             map { s/^\*?\s*//; $_; }
71             $self->repo->command( 'branch' , '-a' );
72             }
73              
74             sub list_remote_branches {
75             return $_[0]->branch->remote_branches;
76             }
77              
78             sub list_local_branches {
79             return $_[0]->branch->local_branches;
80             }
81              
82             sub get_current_branch_name {
83             return $_[0]->branch->current_name;
84             }
85              
86             sub get_current_branch {
87             return $_[0]->branch->current;
88             }
89              
90             # return branches with ready prefix.
91             sub get_ready_branches {
92             my $self = shift;
93             my $prefix = $self->config->ready_prefix;
94             my @branches = $self->list_all_branches;
95             my @ready_branches = grep /$prefix/, @branches;
96             return map { $self->_new_branch( ref => $_ ) } @ready_branches;
97             }
98              
99             sub get_release_branches {
100             my $self = shift;
101             my $prefix = $self->config->release_prefix;
102             my @branches = $self->list_all_branches;
103             my @release_branches = sort grep /$prefix/, @branches;
104             return map { $self->_new_branch( ref => $_ ) } @release_branches; # release branch not found.
105             }
106              
107             sub install_hooks {
108             my $self = shift;
109             my $repo_path = $self->repo->repo_path;
110              
111             my $checkout_hook = File::Spec->join( $repo_path , 'hooks' , 'post-checkout' );
112             print "$checkout_hook\n";
113             open my $fh , ">" , $checkout_hook;
114              
115             print $fh <<"END";
116             #!/usr/bin/env perl
117             use Git::Release;
118             my \$m = Git::Release->new; # release manager
119             \$m->branch->current->print_doc;
120             END
121              
122             close $fh;
123             chmod 0755, $checkout_hook;
124             }
125              
126             sub tracking_list {
127             my ($self) = @_;
128             my @args = qw(for-each-ref);
129             push @args, '--format';
130             push @args ,'%(refname:short):%(upstream)';
131             push @args, 'refs/heads';
132             my @lines = $self->repo->command(@args);
133              
134             my %tracking = map { split ':', $_ , 2 } @lines;
135             return %tracking;
136             }
137              
138             sub update_remote_refs {
139             my $self = shift;
140             $self->repo->command_oneline(qw(remote update --prune));
141             }
142              
143             sub _new_branch {
144             my ( $self, %args ) = @_;
145             my $branch = Git::Release::Branch->new(
146             %args, manager => $self );
147             return $branch;
148             }
149              
150             sub checkout_release_branch {
151             my $self = shift;
152             my @rbs = $self->get_release_branches;
153             my ($rb) = grep { $_->is_local } @rbs;
154             unless ($rb) {
155             ($rb) = grep { $_->is_remote } @rbs;
156             }
157              
158             unless ($rb) {
159             die 'Release branch not found.';
160             }
161              
162             $rb->checkout;
163             return $rb;
164             }
165              
166              
167             =head2 find_branch
168              
169             Find a specific branch from the branch list (remote and local).
170              
171             =cut
172              
173             sub find_branch {
174             my ( $self, $name ) = @_;
175             my @branches = $self->list_all_branches;
176             for my $ref ( @branches ) {
177             my $branch = $self->_new_branch( ref => $ref );
178             return $branch if $branch->name eq $name;
179             }
180             }
181              
182             sub find_develop_branch {
183             my $self = shift;
184             my $dev_branch_name = $self->config->develop_branch;
185             return $self->find_branch( $dev_branch_name );
186             }
187              
188             # checkout or create develop branch
189             sub checkout_develop_branch {
190             my $self = shift;
191             my $name = $self->config->develop_branch;
192             my $branch = $self->branch->find_branches( $name );
193             # if branch found, we should check it out
194             $branch = $self->_new_branch( ref => $name )->create( from => 'master' ) unless $branch;
195             $branch->checkout;
196             return $branch;
197             }
198              
199             sub checkout_rc_branch {
200             my $self = shift;
201             my $name = $self->config->rc_branch;
202             my $rc = $self->branch->find_branches($name);
203             $rc = $self->branch->new_branch($name)->create(from => 'master') unless $rc ;
204             $rc->checkout;
205             return $rc;
206             }
207              
208              
209             sub gc {
210             my $self = shift;
211             my %args = @_;
212             $self->repo->command( 'gc' ,
213             $args{aggressive} ? '--aggressive' : () ,
214             $args{prune} ? '--prune=' . ($args{prune} || 'now') : () );
215             }
216              
217             1;
218             __END__
219              
220             =head1 NAME
221              
222             Git::Release - Release Process Manager
223              
224             =head1 SYNOPSIS
225              
226             use Git::Release;
227              
228             my $manager = Git::Release->new;
229             my @branches = $manager->branch->ready_branches;
230             my @branches = $manager->branch->site_branches;
231             my @branches = $manager->branch->feature_branches;
232             my @branches = $manager->branch->hotfix_branches;
233             my @branches = $manager->branch->find_branches( prefix => 'hotfix' );
234             my @branches = $manager->branch->find_branch( name => 'feature/test' );
235             my $current_branch = $manager->branch->current;
236              
237             my $prefix = $manager->get_ready_prefix; # ready/
238             my $prefix = $manager->get_site_prefix; # site/
239             my $prefix = $manager->get_hotfix_prefix; # hotfix/
240              
241             =head1 DESCRIPTION
242              
243             Git::Release is a release manager for Git.
244              
245             It's based on the basic concepts of git workflow.
246              
247             =head1 AUTHOR
248              
249             Yo-An Lin E<lt>cornelius.howl {at} gmail.comE<gt>
250              
251             =head1 SEE ALSO
252              
253             =head1 LICENSE
254              
255             This library is free software; you can redistribute it and/or modify
256             it under the same terms as Perl itself.
257              
258             =cut