File Coverage

blib/lib/App/BitBucketCli/Core.pm
Criterion Covered Total %
statement 36 158 22.7
branch 0 28 0.0
condition 0 5 0.0
subroutine 12 24 50.0
pod 7 7 100.0
total 55 222 24.7


line stmt bran cond sub pod time code
1             package App::BitBucketCli::Core;
2              
3             # Created on: 2017-04-24 08:14:30
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 1     1   14 use Moo;
  1         3  
  1         6  
10 1     1   362 use warnings;
  1         2  
  1         34  
11 1     1   5 use Carp;
  1         2  
  1         61  
12 1     1   6 use WWW::Mechanize;
  1         2  
  1         26  
13 1     1   4 use JSON::XS qw/decode_json encode_json/;
  1         2  
  1         60  
14 1     1   7 use Data::Dumper qw/Dumper/;
  1         2  
  1         45  
15 1     1   6 use English qw/ -no_match_vars /;
  1         54  
  1         7  
16 1     1   954 use App::BitBucketCli::Project;
  1         4  
  1         34  
17 1     1   470 use App::BitBucketCli::Repository;
  1         4  
  1         35  
18 1     1   434 use App::BitBucketCli::Branch;
  1         4  
  1         34  
19 1     1   498 use App::BitBucketCli::PullRequest;
  1         4  
  1         40  
20 1     1   510 use YAML::Syck qw/Dump/;
  1         2068  
  1         1472  
21              
22             our $VERSION = 0.007;
23              
24             has url => (
25             is => 'rw',
26             builder => '_url',
27             lazy => 1,
28             );
29             has host => (
30             is => 'rw',
31             required => 1,
32             );
33             has [qw/user pass/] => (
34             is => 'rw',
35             );
36             has mech => (
37             is => 'rw',
38             default => sub { WWW::Mechanize->new },
39             );
40             has opt => (
41             is => 'rw',
42             default => sub {{}},
43             );
44             has max => (
45             is => 'rw',
46             default => 100,
47             );
48              
49             sub projects {
50 0     0 1   my ($self) = @_;
51 0           my @projects;
52 0           my $last_page = 0;
53 0           my $next_page_start = 0;
54 0           my $limit = 30;
55              
56 0           while ( ! $last_page ) {
57 0           my $json;
58             eval {
59 0           $json = $self->_get($self->url . "/projects?limit=$limit&start=$next_page_start");
60 0           1;
61 0 0         } || do {
62 0           warn "Couldn't list repositories: $@\n";
63 0           return [];
64             };
65 0           push @projects, @{ $json->{values} };
  0            
66 0           $last_page = $json->{isLastPage};
67 0           $next_page_start = $json->{nextPageStart};
68             }
69              
70 0           return map {App::BitBucketCli::Project->new($_)} @projects;
  0            
71             }
72              
73             sub repositories {
74 0     0 1   my ($self, $project) = @_;
75 0           my @repositories;
76 0           my $last_page = 0;
77 0           my $next_page_start = 0;
78 0           my $limit = 30;
79              
80 0           while ( ! $last_page ) {
81 0           my $json;
82             eval {
83 0           $json = $self->_get($self->url . "/projects/$project/repos?limit=$limit&start=$next_page_start");
84 0           1;
85 0 0         } || do {
86 0           warn "Couldn't list repositories: $@\n";
87 0           return [];
88             };
89 0           push @repositories, @{ $json->{values} };
  0            
90 0           $last_page = $json->{isLastPage};
91 0           $next_page_start = $json->{nextPageStart};
92             }
93              
94 0           return map {App::BitBucketCli::Repository->new($_)} @repositories;
  0            
95             }
96              
97             sub repository {
98 0     0 1   my ($self, $project, $repository) = @_;
99              
100 0           my $json;
101             eval {
102 0           $json = $self->_get($self->url . "/projects/$project/repos/$repository");
103 0           1;
104 0 0         } || do {
105 0           warn "Couldn't get repository information $@\n";
106 0           return [];
107             };
108              
109 0           return $json;
110             }
111              
112             sub pull_requests {
113 0     0 1   my ($self, $project, $repository, $state) = @_;
114 0   0       $state ||= 'OPEN';
115 0           my @pull_requests;
116 0           my $last_page = 0;
117 0           my $next_page_start = 0;
118 0           my $limit = 30;
119              
120 0           while ( ! $last_page ) {
121 0           my $json;
122             eval {
123 0           $json = $self->_get($self->url . "/projects/$project/repos/$repository/pull-requests?limit=$limit&start=$next_page_start&state=$state");
124 0           1;
125 0 0         } || do {
126 0           warn "Couldn't list pull_requests $@\n";
127 0           return [];
128             };
129 0           push @pull_requests, @{ $json->{values} };
  0            
130 0           $last_page = $json->{isLastPage};
131 0           $next_page_start = $json->{nextPageStart};
132 0 0         last if @pull_requests >= $self->max;
133             }
134              
135 0           return map {App::BitBucketCli::PullRequest->new($_)} @pull_requests;
  0            
136             }
137              
138             sub branch {
139 0     0 1   my ($self, @branches) = @_;
140              
141 0           my $branches = $self->get_branches($self->opt->{project}, $self->opt->{repository});
142              
143 0           for my $branch (sort keys %{ $branches }) {
  0            
144 0 0         next if !grep {$branch eq $_} @branches;
  0            
145 0           print "$branch\n";
146             }
147              
148 0           return;
149             }
150              
151             sub get_pull_requests {
152 0     0 1   my ($self, $project, $repository, $state) = @_;
153 0           my $json;
154             my @prs;
155 0 0         $state = $state ? "?state=$state" : '';
156              
157 0           my $next = $self->_get_all("/projects/$project/repos/$repository/pull-requests$state");
158              
159 0           while ( my $pr = $next->() ) {
160 0           push @prs, App::BitBucketCli::PullRequest->new($pr);
161             }
162              
163 0           return \@prs;
164             }
165              
166             sub get_branches {
167 0     0 1   my ($self, $project, $repository) = @_;
168 0           my @branches;
169 0           my $next = $self->_get_all("/projects/$project/repos/$repository/branches?orderBy=MODIFICATION&details=true");
170              
171 0           while ( my $branch = $next->() ) {
172 0           $branch->{project} = $project;
173 0           $branch->{repository} = $repository;
174 0           push @branches, App::BitBucketCli::Branch->new($branch);
175             }
176              
177 0           return \@branches;
178             }
179              
180             sub _get_all {
181 0     0     my ($self, $url) = @_;
182 0           my $last_page = 0;
183 0           my $next_page_start = 0;
184 0           my $limit = 30;
185              
186 0           my $json;
187              
188             return sub {
189 0 0 0 0     if ( $json && @{ $json->{values} } ) {
  0            
190 0           return shift @{ $json->{values} };
  0            
191             }
192 0 0         if ($last_page) {
193 0           return;
194             }
195              
196 0 0         my $page_url = $self->url . $url . ( $url =~ /[?]/ ? '&' : '?' ) . "limit=$limit&start=$next_page_start";
197 0           $json = $self->_get($page_url);
198              
199 0           $last_page = $json->{isLastPage};
200 0           $next_page_start = $json->{nextPageStart};
201              
202 0 0         return shift @{ $json->{values} || [] };
  0            
203 0           };
204             }
205              
206             sub _get {
207 0     0     my ($self, $url) = @_;
208              
209 0 0         warn "$url\n" if $ENV{BB_SHOW_URLS};
210 0           $self->mech->get($url);
211              
212 0           return decode_json($self->mech->content);
213             }
214              
215             sub _url {
216 0     0     my ($self) = @_;
217 0           my $url = "https://";
218 0 0         if ( $self->user ) {
219 0           $url .= _url_encode($self->user);
220              
221 0 0         if ( $self->pass ) {
222 0           $url .= ':' . _url_encode($self->pass);
223             }
224 0           $url .= '@';
225             }
226 0           $url .= $self->host . "/rest/api/1.0";
227              
228 0           return $url;
229             }
230              
231             sub _url_encode {
232 0     0     my $str = shift;
233 0           $str =~ s/(\W)/sprintf('%%%x',ord($1))/eg;
  0            
234 0           return $str;
235             }
236              
237             1;
238              
239             __END__
240              
241             =head1 NAME
242              
243             App::BitBucketCli::Core - Library for talking to BitBucket Server (or Stash)
244              
245             =head1 VERSION
246              
247             This documentation refers to App::BitBucketCli::Core version 0.007
248              
249              
250             =head1 SYNOPSIS
251              
252             use App::BitBucketCli::Core;
253              
254             # create a stash object
255             my $stash = App::BitBucketCli::Core->new(
256             url => 'http://stash.example.com/',
257             );
258              
259             # Get a list of open pull requests for a repository
260             my $prs = $stash->pull_requests($project, $repository);
261              
262             =head1 DESCRIPTION
263              
264             =head1 SUBROUTINES/METHODS
265              
266             =head2 C<branch ()>
267              
268             =head2 C<get_branches ()>
269              
270             =head2 C<get_pull_requests ()>
271              
272             =head2 C<projects ()>
273              
274             =head2 C<pull_requests ( $project, $repository, $state )>
275              
276             Gets all of the pull requests in C<$state>.
277              
278             =head2 C<repositories ( $project )>
279              
280             Gets details of all repositories of $project
281              
282             =head2 C<repository ( $project, $repository )>
283              
284             Gets details of a repository
285              
286             =head1 ATTRIBUTES
287              
288             =head2 url
289              
290             =head2 host
291              
292             =head2 user
293              
294             =head2 pass
295              
296             =head2 mech
297              
298             =head2 max
299              
300             Set the maximum number of results to collect from BitBucket Server.
301              
302             =head2 opt
303              
304             =head1 DIAGNOSTICS
305              
306             =head1 CONFIGURATION AND ENVIRONMENT
307              
308             =head1 DEPENDENCIES
309              
310             =head1 INCOMPATIBILITIES
311              
312             =head1 BUGS AND LIMITATIONS
313              
314             There are no known bugs in this module.
315              
316             Please report problems to Ivan Wills (ivan.wills@gmail.com).
317              
318             Patches are welcome.
319              
320             =head1 AUTHOR
321              
322             Ivan Wills - (ivan.wills@gmail.com)
323              
324             =head1 LICENSE AND COPYRIGHT
325              
326             Copyright (c) 2017 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
327             All rights reserved.
328              
329             This module is free software; you can redistribute it and/or modify it under
330             the same terms as Perl itself. See L<perlartistic>. This program is
331             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
332             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
333             PARTICULAR PURPOSE.
334              
335             =cut