File Coverage

blib/lib/Net/GitHub/V3/Repos.pm
Criterion Covered Total %
statement 18 151 11.9
branch 0 40 0.0
condition 0 10 0.0
subroutine 6 36 16.6
pod 15 24 62.5
total 39 261 14.9


line stmt bran cond sub pod time code
1             package Net::GitHub::V3::Repos;
2              
3 1     1   7 use Moo;
  1         2  
  1         7  
4              
5             our $VERSION = '1.05';
6             our $AUTHORITY = 'cpan:FAYLAND';
7              
8 1     1   339 use Carp;
  1         2  
  1         65  
9 1     1   6 use URI::Escape;
  1         2  
  1         128  
10 1     1   7 use URI;
  1         2  
  1         44  
11 1     1   451 use HTTP::Request::Common qw(POST);
  1         2203  
  1         2220  
12              
13             with 'Net::GitHub::V3::Query';
14              
15             sub list {
16 0     0 1   my ( $self, $args ) = @_;
17              
18 0           return $self->query(_repos_arg2url($args));
19             }
20              
21              
22             sub next_repo {
23 0     0 1   my ( $self, $args ) = @_;
24              
25 0           return $self->next(_repos_arg2url($args));
26             }
27              
28             sub close_repo {
29 0     0 0   my ( $self, $args ) = @_;
30              
31 0           return $self->close(_repos_arg2url($args));
32             }
33              
34             sub _repos_arg2url {
35 0     0     my ($args) = @_;
36              
37             # for old
38 0 0         unless (ref($args) eq 'HASH') {
39 0           $args = { type => $args };
40             }
41              
42 0           my $uri = URI->new('/user/repos');
43 0           $uri->query_form($args);
44 0           return $uri->as_string;
45             }
46              
47              
48             sub list_all {
49 0     0 1   my ( $self, $since ) = @_;
50              
51 0           return $self->query(_all_repos_arg2url($since));
52             }
53              
54             sub next_all_repo {
55 0     0 1   my ( $self, $since ) = @_;
56              
57 0           return $self->next(_all_repos_arg2url($since));
58             }
59              
60             sub close_all_repo {
61 0     0 0   my ( $self, $since ) = @_;
62              
63 0           return $self->close(_all_repos_arg2url($since));
64             }
65              
66             sub _all_repos_arg2url {
67 0     0     my ( $since ) = @_;
68 0   0       $since ||= 'first';
69 0           my $u = '/repositories';
70 0 0         $u .= '?since=' . $since if $since ne 'first';
71 0           return $u;
72             }
73              
74             sub list_user {
75 0     0 1   my $self = shift;
76              
77 0           return $self->query($self->_user_repos_arg2url(@_));
78             }
79              
80             sub next_user_repo {
81 0     0 1   my $self = shift;
82              
83 0           return $self->next($self->_user_repos_arg2url(@_));
84             }
85              
86             sub close_user_repo {
87 0     0 0   my $self = shift;
88              
89 0           return $self->close($self->_user_repos_arg2url(@_));
90             }
91              
92             sub _user_repos_arg2url {
93 0     0     my ($self, $user, $args) = @_;
94 0   0       $user ||= $self->u;
95              
96             # for old
97 0 0         unless (ref($args) eq 'HASH') {
98 0           $args = { type => $args };
99             }
100              
101 0           my $uri = URI->new("/users/" . uri_escape($user) . "/repos");
102 0           $uri->query_form($args);
103 0           return $uri->as_string;
104             }
105              
106             sub list_org {
107 0     0 1   my $self = shift;
108              
109 0           return $self->query($self->_org_repos_arg2url(@_));
110             }
111              
112             sub next_org_repo {
113 0     0 1   my $self = shift;
114              
115 0           return $self->next($self->_org_repos_arg2url(@_));
116             }
117              
118             sub close_org_repo {
119 0     0 0   my $self = shift;
120              
121 0           return $self->close($self->_org_repos_arg2url(@_));
122             }
123              
124             sub _org_repos_arg2url {
125 0     0     my ($self, $org, $type) = @_;
126 0   0       $type ||= 'all';
127 0           my $u = "/orgs/" . uri_escape($org) . "/repos";
128 0 0         $u .= '?type=' . $type if $type ne 'all';
129 0           return $u;
130             }
131              
132              
133             sub create {
134 0     0 1   my ( $self, $data ) = @_;
135              
136 0           my $u = '/user/repos';
137 0 0         if (exists $data->{org}) {
138 0           my $o = delete $data->{org};
139 0           $u = "/orgs/" . uri_escape($o) . "/repos";
140             }
141              
142 0           return $self->query('POST', $u, $data);
143             }
144              
145             sub upload_asset {
146 0     0 1   my $self = shift;
147 0 0         unshift @_, $self->u, $self->repo if @_ < 5;
148 0           my ($user, $repos, $release_id, $name, $content_type, $file_content) = @_;
149              
150 0           my $ua = $self->ua;
151 0           my $url = $self->upload_url . "/repos/$user/$repos/releases/$release_id/assets?name=" . uri_escape($name);
152 0           my $req = HTTP::Request->new( 'POST', $url );
153 0           $req->accept_decodable;
154 0           $req->content($file_content);
155 0           $req->header( 'Content-Type', $content_type );
156              
157 0           my $res = $ua->request($req);
158              
159 0           my $data;
160 0 0 0       if ($res->header('Content-Type') and $res->header('Content-Type') =~ 'application/json') {
161 0           my $json = $res->decoded_content;
162 0           $data = eval { $self->json->decode($json) };
  0            
163 0 0         unless ($data) {
164             # We tolerate bad JSON for errors,
165             # otherwise we just rethrow the JSON parsing problem.
166 0 0         die unless $res->is_error;
167 0           $data = { message => $res->message };
168             }
169             } else {
170 0           $data = { message => $res->message };
171             }
172              
173 0 0         return wantarray ? %$data : $data;
174             }
175              
176             sub commits {
177 0     0 1   my $self = shift;
178              
179 0           return $self->query($self->_commits_arg2url(@_));
180             }
181              
182             sub next_commit {
183 0     0 0   my $self = shift;
184              
185 0           return $self->next($self->_commits_arg2url(@_));
186             }
187              
188             sub close_commit {
189 0     0 0   my $self = shift;
190              
191 0           return $self->close($self->_commits_arg2url(@_));
192             }
193              
194             sub _commits_arg2url {
195 0     0     my $self = shift;
196 0 0         if (@_ < 2) {
197 0           unshift @_, $self->repo;
198 0           unshift @_, $self->u;
199             }
200 0           my ($user, $repos, $args) = @_;
201              
202 0           my $uri = URI->new("/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/commits');
203 0           $uri->query_form($args);
204 0           return $uri->as_string;
205             }
206              
207              
208              
209             sub list_deployments {
210 0     0 1   my $self = shift;
211              
212 0           return $self->query($self->deployments_arg2url(@_));
213             }
214              
215             sub next_deployment {
216 0     0 1   my $self = shift;
217              
218 0           return $self->next($self->deployments_arg2url(@_));
219             }
220              
221             sub close_deployment {
222 0     0 0   my $self = shift;
223              
224 0           return $self->close($self->deployments_arg2url(@_));
225             }
226              
227             sub _deployments_arg2url {
228 0     0     my $self = shift;
229 0 0         if (@_ < 2) {
230 0           unshift @_, $self->repo;
231 0           unshift @_, $self->u;
232             }
233 0           my ($user, $repos, $args) = @_;
234              
235 0           my $uri = URI->new("/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/deployments');
236 0           $uri->query_form($args);
237 0           return $uri->as_string;
238             }
239              
240              
241             ## build methods on fly
242             my %__methods = (
243              
244             get => { url => "/repos/%s/%s" },
245             update => { url => "/repos/%s/%s", method => 'PATCH', args => 1 },
246             contributors => { url => "/repos/%s/%s/contributors", paginate => 1 },
247             languages => { url => "/repos/%s/%s/languages" },
248             teams => { url => "/repos/%s/%s/teams", paginate => 1 },
249             tags => { url => "/repos/%s/%s/tags", paginate => 1 },
250             branches => { url => "/repos/%s/%s/branches", paginate => 1 },
251             branch => { url => "/repos/%s/%s/branches/%s" },
252             delete => { url => "/repos/%s/%s", method => 'DELETE', check_status => 204 },
253              
254             # http://developer.github.com/v3/repos/collaborators/
255             collaborators => { url => "/repos/%s/%s/collaborators", paginate => 1 },
256             is_collaborator => { url => "/repos/%s/%s/collaborators/%s", check_status => 204 },
257             add_collaborator => { url => "/repos/%s/%s/collaborators/%s", method => 'PUT', check_status => 204 },
258             delete_collaborator => { url => "/repos/%s/%s/collaborators/%s", method => 'DELETE', check_status => 204 },
259              
260             # http://developer.github.com/v3/repos/commits/
261             commit => { url => "/repos/%s/%s/commits/%s" },
262             comments => { url => "/repos/%s/%s/comments", paginate => 1 },
263             comment => { url => "/repos/%s/%s/comments/%s" },
264             commit_comments => { url => "/repos/%s/%s/commits/%s/comments", paginate => 1 },
265             create_comment => { url => "/repos/%s/%s/commits/%s/comments", method => 'POST', args => 1 },
266             update_comment => { url => "/repos/%s/%s/comments/%s", method => 'PATCH', args => 1 },
267             delete_comment => { url => "/repos/%s/%s/comments/%s", method => 'DELETE', check_status => 204 },
268             compare_commits => { url => "/repos/%s/%s/compare/%s...%s" },
269              
270             # http://developer.github.com/v3/repos/contents/
271             readme => { url => "/repos/%s/%s/readme" },
272             get_content => { url => "/repos/:owner/:repo/contents/:path", v => 2 },
273              
274             # http://developer.github.com/v3/repos/downloads/
275             downloads => { url => "/repos/%s/%s/downloads", paginate => 1 },
276             download => { url => "/repos/%s/%s/downloads/%s" },
277             delete_download => { url => "/repos/%s/%s/downloads/%s", method => 'DELETE', check_status => 204 },
278              
279             # http://developer.github.com/v3/repos/releases/
280             releases => { url => "/repos/%s/%s/releases", paginate => 1 },
281             release => { url => "/repos/%s/%s/releases/%s" },
282             create_release => { url => "/repos/%s/%s/releases", method => 'POST', args => 1 },
283             update_release => { url => "/repos/%s/%s/releases/%s", method => 'PATCH', args => 1 },
284             delete_release => { url => "/repos/%s/%s/releases/%s", method => 'DELETE', check_status => 204 },
285              
286             release_assets => { url => "/repos/%s/%s/releases/%s/assets", paginate => 1 },
287             release_asset => { url => "/repos/%s/%s/releases/%s/assets/%s" },
288             update_release_asset => { url => "/repos/%s/%s/releases/%s/assets/%s", method => 'PATCH', args => 1 },
289             delete_release_asset => { url => "/repos/%s/%s/releases/%s/assets/%s", method => 'DELETE', check_status => 204 },
290              
291             forks => { url => "/repos/%s/%s/forks", paginate => 1 },
292              
293             # http://developer.github.com/v3/repos/keys/
294             keys => { url => "/repos/%s/%s/keys", paginate => 1 },
295             key => { url => "/repos/%s/%s/keys/%s" },
296             create_key => { url => "/repos/%s/%s/keys", method => 'POST', args => 1 },
297             update_key => { url => "/repos/%s/%s/keys/%s", method => 'PATCH', check_status => 204, args => 1 },
298             delete_key => { url => "/repos/%s/%s/keys/%s", method => 'DELETE', check_status => 204 },
299              
300             # http://developer.github.com/v3/repos/watching/
301             watchers => { url => "/repos/%s/%s/watchers", paginate => 1 },
302             is_watching => { url => "/user/watched/%s/%s", is_u_repo => 1, check_status => 204 },
303             watch => { url => "/user/watched/%s/%s", is_u_repo => 1, method => 'PUT', check_status => 204 },
304             unwatch => { url => "/user/watched/%s/%s", is_u_repo => 1, method => 'DELETE', check_status => 204 },
305              
306             subscribers => { url => "/repos/%s/%s/subscribers", paginate => 1 },
307             subscription => { url => "/repos/%s/%s/subscription" },
308             is_subscribed => { url => "/repos/%s/%s/subscription", check_status => 200 },
309             subscribe => { url => "/repos/%s/%s/subscription", method => 'PUT',
310             check_status => 200, args => 1 },
311             unsubscribe => { url => "/repos/%s/%s/subscription", method => 'DELETE', check_status => 204 },
312              
313             # http://developer.github.com/v3/repos/hooks/
314             hooks => { url => "/repos/%s/%s/hooks", paginate => 1 },
315             hook => { url => "/repos/%s/%s/hooks/%s" },
316             delete_hook => { url => "/repos/%s/%s/hooks/%s", method => 'DELETE', check_status => 204 },
317             test_hook => { url => "/repos/%s/%s/hooks/%s/test", method => 'POST', check_status => 204 },
318             create_hook => { url => "/repos/%s/%s/hooks", method => 'POST', args => 1 },
319             update_hook => { url => "/repos/%s/%s/hooks/%s", method => 'PATCH', args => 1 },
320              
321             # http://developer.github.com/v3/repos/merging/
322             merges => { url => "/repos/%s/%s/merges", method => 'POST', args => 1 },
323              
324             # http://developer.github.com/v3/repos/statuses/
325             list_statuses => { url => "/repos/%s/%s/statuses/%s", paginate => { name => 'status' } },
326             create_status => { url => "/repos/%s/%s/statuses/%s", method => 'POST', args => 1 },
327              
328             # https://developer.github.com/v3/repos/deployments
329             create_deployment => { url => "/repos/%s/%s/deployments", method => 'POST', args => 1 },
330             create_deployment_status => { url => "/repos/%s/%s/deployments/%s/statuses", method => 'POST', args => 1},
331             list_deployment_statuses => { url => "/repos/%s/%s/deployments/%s/statuses", method => 'GET', paginate => { name => 'deployment_status' } },
332              
333             contributor_stats => { url => "/repos/%s/%s/stats/contributors", method => 'GET'},
334             commit_activity => { url => "/repos/%s/%s/stats/commit_activity", method => 'GET'},
335             code_frequency => { url => "/repos/%s/%s/stats/code_frequency", method => 'GET'},
336             participation => { url => "/repos/%s/%s/stats/participation", method => 'GET'},
337             punch_card => { url => "/repos/%s/%s/stats/punch_card", method => 'GET'},
338              
339             # https://docs.github.com/en/rest/branches/branch-protection
340             branch_protection => { url => "/repos/%s/%s/branches/%s/protection", method => 'GET'},
341             delete_branch_protection => { url => "/repos/%s/%s/branches/%s/protection", method => 'DELETE', check_status => 204 },
342             update_branch_protection => { url => "/repos/%s/%s/branches/%s/protection", method => 'PUT', args => 1 },
343             );
344             __build_methods(__PACKAGE__, %__methods);
345              
346             sub create_download {
347 0     0 0   my $self = shift;
348              
349 0 0         if (@_ == 1) {
350 0           unshift @_, $self->repo;
351 0           unshift @_, $self->u;
352             }
353 0           my ($user, $repos, $download) = @_;
354              
355 0           my $file = delete $download->{file};
356              
357 0           my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/downloads';
358 0           my $d = $self->query('POST', $u, $download);
359 0 0         if (defined $file) {
360 0           return $self->upload_download($d, $file);
361             } else {
362 0           return $d;
363             }
364             }
365              
366             sub upload_download {
367 0     0 0   my $self = shift;
368              
369 0 0         if (@_ < 3) {
370 0           unshift @_, $self->repo;
371 0           unshift @_, $self->u;
372             }
373 0           my ($user, $repos, $download, $file) = @_;
374              
375             # must successful on create_download
376 0 0         return 0 unless exists $download->{s3_url};
377              
378             ## POST form-data
379             my %data = (
380             Content_Type => 'form-data',
381             Content => [
382             'key' => $download->{path},
383             'acl' => $download->{acl},
384             'success_action_status' => 201,
385             'Filename' => $download->{name},
386             'AWSAccessKeyId' => $download->{accesskeyid},
387             'Policy' => $download->{policy},
388             'Signature' => $download->{signature},
389             'Content-Type' => $download->{mime_type},
390 0           'file' => [ $file ],
391             ],
392             );
393 0           my $request = POST $download->{s3_url}, %data;
394 0           my $res = $self->ua->request($request);
395 0 0         return $res->code == 201 ? 1 : 0;
396             }
397              
398             ## http://developer.github.com/v3/repos/forks/
399             sub create_fork {
400 0     0 1   my $self = shift;
401              
402 0 0         if (@_ < 2) {
403 0           unshift @_, $self->repo;
404 0           unshift @_, $self->u;
405             }
406 0           my ($user, $repos, $org) = @_;
407              
408 0           my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/forks';
409 0 0         $u .= '?org=' . $org if defined $org;
410 0           return $self->query('POST', $u);
411             }
412              
413             ## http://developer.github.com/v3/repos/watching/
414             sub watched {
415 0     0 1   my ($self, $user) = @_;
416              
417 0 0         my $u = $user ? '/users/' . uri_escape($user). '/watched' : '/user/watched';
418 0           return $self->query($u);
419             }
420              
421 1     1   21 no Moo;
  1         1  
  1         10  
422              
423             1;
424             __END__