1package Net::GitHub::V3::Repos; 2 3use Moo; 4 5our $VERSION = '1.02'; 6our $AUTHORITY = 'cpan:FAYLAND'; 7 8use Carp; 9use URI::Escape; 10use URI; 11use HTTP::Request::Common qw(POST); 12 13with 'Net::GitHub::V3::Query'; 14 15sub list { 16 my ( $self, $args ) = @_; 17 18 return $self->query(_repos_arg2url($args)); 19} 20 21 22sub next_repo { 23 my ( $self, $args ) = @_; 24 25 return $self->next(_repos_arg2url($args)); 26} 27 28sub close_repo { 29 my ( $self, $args ) = @_; 30 31 return $self->close(_repos_arg2url($args)); 32} 33 34sub _repos_arg2url { 35 my ($args) = @_; 36 37 # for old 38 unless (ref($args) eq 'HASH') { 39 $args = { type => $args }; 40 } 41 42 my $uri = URI->new('/user/repos'); 43 $uri->query_form($args); 44 return $uri->as_string; 45} 46 47 48sub list_all { 49 my ( $self, $since ) = @_; 50 51 return $self->query(_all_repos_arg2url($since)); 52} 53 54sub next_all_repo { 55 my ( $self, $since ) = @_; 56 57 return $self->next(_all_repos_arg2url($since)); 58} 59 60sub close_all_repo { 61 my ( $self, $since ) = @_; 62 63 return $self->close(_all_repos_arg2url($since)); 64} 65 66sub _all_repos_arg2url { 67 my ( $since ) = @_; 68 $since ||= 'first'; 69 my $u = '/repositories'; 70 $u .= '?since=' . $since if $since ne 'first'; 71 return $u; 72} 73 74sub list_user { 75 my $self = shift; 76 77 return $self->query($self->_user_repos_arg2url(@_)); 78} 79 80sub next_user_repo { 81 my $self = shift; 82 83 return $self->next($self->_user_repos_arg2url(@_)); 84} 85 86sub close_user_repo { 87 my $self = shift; 88 89 return $self->close($self->_user_repos_arg2url(@_)); 90} 91 92sub _user_repos_arg2url { 93 my ($self, $user, $args) = @_; 94 $user ||= $self->u; 95 96 # for old 97 unless (ref($args) eq 'HASH') { 98 $args = { type => $args }; 99 } 100 101 my $uri = URI->new("/users/" . uri_escape($user) . "/repos"); 102 $uri->query_form($args); 103 return $uri->as_string; 104} 105 106sub list_org { 107 my $self = shift; 108 109 return $self->query($self->_org_repos_arg2url(@_)); 110} 111 112sub next_org_repo { 113 my $self = shift; 114 115 return $self->next($self->_org_repos_arg2url(@_)); 116} 117 118sub close_org_repo { 119 my $self = shift; 120 121 return $self->close($self->_org_repos_arg2url(@_)); 122} 123 124sub _org_repos_arg2url { 125 my ($self, $org, $type) = @_; 126 $type ||= 'all'; 127 my $u = "/orgs/" . uri_escape($org) . "/repos"; 128 $u .= '?type=' . $type if $type ne 'all'; 129 return $u; 130} 131 132 133sub create { 134 my ( $self, $data ) = @_; 135 136 my $u = '/user/repos'; 137 if (exists $data->{org}) { 138 my $o = delete $data->{org}; 139 $u = "/orgs/" . uri_escape($o) . "/repos"; 140 } 141 142 return $self->query('POST', $u, $data); 143} 144 145sub upload_asset { 146 my $self = shift; 147 unshift @_, $self->u, $self->repo if @_ < 5; 148 my ($user, $repos, $release_id, $name, $content_type, $file_content) = @_; 149 150 my $ua = $self->ua; 151 my $url = $self->upload_url . "/repos/$user/$repos/releases/$release_id/assets?name=" . uri_escape($name); 152 my $req = HTTP::Request->new( 'POST', $url ); 153 $req->accept_decodable; 154 $req->content($file_content); 155 $req->header( 'Content-Type', $content_type ); 156 157 my $res = $ua->request($req); 158 159 my $data; 160 if ($res->header('Content-Type') and $res->header('Content-Type') =~ 'application/json') { 161 my $json = $res->decoded_content; 162 $data = eval { $self->json->decode($json) }; 163 unless ($data) { 164 # We tolerate bad JSON for errors, 165 # otherwise we just rethrow the JSON parsing problem. 166 die unless $res->is_error; 167 $data = { message => $res->message }; 168 } 169 } else { 170 $data = { message => $res->message }; 171 } 172 173 return wantarray ? %$data : $data; 174} 175 176sub commits { 177 my $self = shift; 178 179 return $self->query($self->_commits_arg2url(@_)); 180} 181 182sub next_commit { 183 my $self = shift; 184 185 return $self->next($self->_commits_arg2url(@_)); 186} 187 188sub close_commit { 189 my $self = shift; 190 191 return $self->close($self->_commits_arg2url(@_)); 192} 193 194sub _commits_arg2url { 195 my $self = shift; 196 if (@_ < 2) { 197 unshift @_, $self->repo; 198 unshift @_, $self->u; 199 } 200 my ($user, $repos, $args) = @_; 201 202 my $uri = URI->new("/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/commits'); 203 $uri->query_form($args); 204 return $uri->as_string; 205} 206 207 208 209sub list_deployments { 210 my $self = shift; 211 212 return $self->query($self->deployments_arg2url(@_)); 213} 214 215sub next_deployment { 216 my $self = shift; 217 218 return $self->next($self->deployments_arg2url(@_)); 219} 220 221sub close_deployment { 222 my $self = shift; 223 224 return $self->close($self->deployments_arg2url(@_)); 225} 226 227sub _deployments_arg2url { 228 my $self = shift; 229 if (@_ < 2) { 230 unshift @_, $self->repo; 231 unshift @_, $self->u; 232 } 233 my ($user, $repos, $args) = @_; 234 235 my $uri = URI->new("/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/deployments'); 236 $uri->query_form($args); 237 return $uri->as_string; 238} 239 240 241## build methods on fly 242my %__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/:owner/:repo/commits/:ref", v => 2 }, 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); 340__build_methods(__PACKAGE__, %__methods); 341 342sub create_download { 343 my $self = shift; 344 345 if (@_ == 1) { 346 unshift @_, $self->repo; 347 unshift @_, $self->u; 348 } 349 my ($user, $repos, $download) = @_; 350 351 my $file = delete $download->{file}; 352 353 my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/downloads'; 354 my $d = $self->query('POST', $u, $download); 355 if (defined $file) { 356 return $self->upload_download($d, $file); 357 } else { 358 return $d; 359 } 360} 361 362sub upload_download { 363 my $self = shift; 364 365 if (@_ < 3) { 366 unshift @_, $self->repo; 367 unshift @_, $self->u; 368 } 369 my ($user, $repos, $download, $file) = @_; 370 371 # must successful on create_download 372 return 0 unless exists $download->{s3_url}; 373 374 ## POST form-data 375 my %data = ( 376 Content_Type => 'form-data', 377 Content => [ 378 'key' => $download->{path}, 379 'acl' => $download->{acl}, 380 'success_action_status' => 201, 381 'Filename' => $download->{name}, 382 'AWSAccessKeyId' => $download->{accesskeyid}, 383 'Policy' => $download->{policy}, 384 'Signature' => $download->{signature}, 385 'Content-Type' => $download->{mime_type}, 386 'file' => [ $file ], 387 ], 388 ); 389 my $request = POST $download->{s3_url}, %data; 390 my $res = $self->ua->request($request); 391 return $res->code == 201 ? 1 : 0; 392} 393 394## http://developer.github.com/v3/repos/forks/ 395sub create_fork { 396 my $self = shift; 397 398 if (@_ < 2) { 399 unshift @_, $self->repo; 400 unshift @_, $self->u; 401 } 402 my ($user, $repos, $org) = @_; 403 404 my $u = "/repos/" . uri_escape($user) . "/" . uri_escape($repos) . '/forks'; 405 $u .= '?org=' . $org if defined $org; 406 return $self->query('POST', $u); 407} 408 409## http://developer.github.com/v3/repos/watching/ 410sub watched { 411 my ($self, $user) = @_; 412 413 my $u = $user ? '/users/' . uri_escape($user). '/watched' : '/user/watched'; 414 return $self->query($u); 415} 416 417no Moo; 418 4191; 420__END__ 421 422=head1 NAME 423 424Net::GitHub::V3::Repos - GitHub Repos API 425 426=head1 SYNOPSIS 427 428 use Net::GitHub::V3; 429 430 my $gh = Net::GitHub::V3->new; # read L<Net::GitHub::V3> to set right authentication info 431 my $repos = $gh->repos; 432 433 # set :user/:repo for simple calls 434 $repos->set_default_user_repo('fayland', 'perl-net-github'); 435 my @contributors = $repos->contributors; # don't need pass user and repos 436 437 438=head1 DESCRIPTION 439 440=head2 METHODS 441 442=head3 Repos 443 444L<http://developer.github.com/v3/repos/> 445 446=over 4 447 448=item list 449 450=item list_all 451 452 # All public repositories on Github 453 my @rp = $repos->list_all; 454 # starting at id 500 455 my @rp = $repos->list_all(500); 456 457=item list_user 458 459=item list_org 460 461 my @rp = $repos->list; # or my $rp = $repos->list; 462 my @rp = $repos->list({ 463 type => 'private' 464 sort => 'updated' 465 }); 466 my @rp = $repos->list_user('c9s'); 467 my @rp = $repos->list_user('c9s', { 468 type => 'member' 469 }); 470 my @rp = $repos->list_org('perlchina'); 471 my @rp = $repos->list_org('perlchina', 'public'); 472 473=item next_repo, next_all_repo, next_user_repo, next_org_repo 474 475 # Iterate over your repositories 476 while (my $repo = $repos->next_repo) { ...; } 477 # Iterate over all public repositories 478 while (my $repo = $repos->next_all_repo(500)) { ...; } 479 # Iterate over repositories of another user 480 while (my $repo = $repos->next_user_repo('c9s')) { ...; } 481 # Iterate over repositories of an organisation 482 while (my $repo = $repos->next_org_repo('perlchina','public')) { ...; } 483 484=item create 485 486 # create for yourself 487 my $rp = $repos->create( { 488 "name" => "Hello-World", 489 "description" => "This is your first repo", 490 "homepage" => "https://github.com" 491 } ); 492 # create for organization 493 my $rp = $repos->create( { 494 "org" => "perlchina", ## the organization 495 "name" => "Hello-World", 496 "description" => "This is your first repo", 497 "homepage" => "https://github.com" 498 } ); 499 500=item get 501 502 my $rp = $repos->get('fayland', 'perl-net-github'); 503 504=back 505 506B<To ease the keyboard, we provied two ways to call any method which starts with :user/:repo> 507 5081. SET user/repos before call methods below 509 510 $gh->set_default_user_repo('fayland', 'perl-net-github'); # take effects for all $gh-> 511 $repos->set_default_user_repo('fayland', 'perl-net-github'); # only take effect to $gh->repos 512 my @contributors = $repos->contributors; 513 5142. If it is just for once, we can pass :user, :repo before any arguments 515 516 my @contributors = $repos->contributors($user, $repo); 517 518=over 4 519 520=item update 521 522 $repos->update({ homepage => 'https://metacpan.org/module/Net::GitHub' }); 523 524=item delete 525 526 $repos->delete(); 527 528=item contributors 529 530=item languages 531 532=item teams 533 534=item tags 535 536=item contributors 537 538 my @contributors = $repos->contributors; 539 my @languages = $repos->languages; 540 my @teams = $repos->teams; 541 my @tags = $repos->tags; 542 my @branches = $repos->branches; 543 my $branch = $repos->branch('master'); 544 while (my $contributor = $repos->next_contributor) { ...; } 545 while (my $team = $repos->next_team) { ... ; } 546 while (my $tags = $repos->next_tag) { ... ; } 547 548=back 549 550=head3 Repo Collaborators API 551 552L<http://developer.github.com/v3/repos/collaborators/> 553 554=over 4 555 556=item collaborators 557 558=item is_collaborator 559 560=item add_collaborator 561 562=item delete_collaborator 563 564 my @collaborators = $repos->collaborators; 565 while (my $collaborator = $repos->next_collaborator) { ...; } 566 my $is = $repos->is_collaborator('fayland'); 567 $repos->add_collaborator('fayland'); 568 $repos->delete_collaborator('fayland'); 569 570=back 571 572=head3 Commits API 573 574L<http://developer.github.com/v3/repos/commits/> 575 576=over 4 577 578=item commits 579 580=item commit 581 582 my @commits = $repos->commits; 583 my @commits = $repos->commits({ 584 author => 'fayland' 585 }); 586 my $commit = $repos->commit($sha); 587 while (my $commit = $repos->next_commit({...})) { ...; } 588 589=item comments 590 591=item commit_comments 592 593=item create_comment 594 595=item comment 596 597=item update_comment 598 599=item delete_comment 600 601 my @comments = $repos->comments; 602 while (my $comment = $repos->next_comment) { ...; } 603 my @comments = $repos->commit_comments($sha); 604 while (my $comment = $repos->next_commit_comment($sha)) { ...; } 605 my $comment = $repos->create_comment($sha, { 606 "body" => "Nice change", 607 "commit_id" => "6dcb09b5b57875f334f61aebed695e2e4193db5e", 608 "line" => 1, 609 "path" => "file1.txt", 610 "position" => 4 611 }); 612 my $comment = $repos->comment($comment_id); 613 my $comment = $repos->update_comment($comment_id, { 614 "body" => "Nice change" 615 }); 616 my $st = $repos->delete_comment($comment_id); 617 618=item compare_commits 619 620 my $diffs = $repos->compare_commits($base, $head); 621 622=back 623 624=head3 Forks API 625 626L<http://developer.github.com/v3/repos/forks/> 627 628=over 4 629 630=item forks 631 632=item create_fork 633 634 my @forks = $repos->forks; 635 while (my $fork = $repos->next_fork) { ...; } 636 my $fork = $repos->create_fork; 637 my $fork = $repos->create_fork($org); 638 639=back 640 641=head3 Repos Deploy Keys API 642 643L<http://developer.github.com/v3/repos/keys/> 644 645=over 4 646 647=item keys 648 649=item key 650 651=item create_key 652 653=item update_key 654 655=item delete_key 656 657 my @keys = $repos->keys; 658 while (my $key = $repos->next_key) { ...; } 659 my $key = $repos->key($key_id); # get key 660 $repos->create_key( { 661 title => 'title', 662 key => $key 663 } ); 664 $repos->update_key($key_id, { 665 title => $title, 666 key => $key 667 }); 668 $repos->delete_key($key_id); 669 670=back 671 672=head3 Repo Watching API 673 674L<http://developer.github.com/v3/repos/watching/> 675 676=over 4 677 678=item watchers 679 680 my @watchers = $repos->watchers; 681 while (my $watcher = $repos->next_watcher) { ...; } 682 683=item watched 684 685 my @repos = $repos->watched; # what I watched 686 my @repos = $repos->watched('c9s'); 687 688=item is_watching 689 690 my $is_watching = $repos->is_watching; 691 my $is_watching = $repos->is_watching('fayland', 'perl-net-github'); 692 693=item watch 694 695=item unwatch 696 697 my $st = $repos->watch(); 698 my $st = $repos->watch('fayland', 'perl-net-github'); 699 my $st = $repos->unwatch(); 700 my $st = $repos->unwatch('fayland', 'perl-net-github'); 701 702=back 703 704=head3 Subscriptions 705 706Github changed the ideas of Watchers (stars) and Subscriptions (new watchers). 707 708 https://github.com/blog/1204-notifications-stars 709 710The Watchers code in this module predates the terminology change, so the new 711Watcher methods use the GitHub 'subscription' terminology. 712 713=over 4 714 715=item subscribers 716 717Returns a list of subscriber data hashes. 718 719=item next_subscriber 720 721Returns the next subscriber in the list, or undef if there are no more subscribers. 722 723=item is_subscribed 724 725Returns true or false if you are subscribed 726 727 $repos->is_subscribed(); 728 $repos->is_subscribed('fayland','perl-net-github'); 729 730=item subscription 731 732Returns more information about your subscription to a repo. 733is_subscribed is a shortcut to calling this and checking for 734subscribed => 1. 735 736=item subscribe 737 738Required argument telling github if you want to subscribe or if you want 739to ignore mentions. If you want to change from subscribed to ignores you 740need to unsubscribe first. 741 742 $repos->subscribe('fayland','perl-net-github', { subscribed => 1 }) 743 $repos->subscribe('fayland','perl-net-github', { ignored => 1 }) 744 745=item unsubscribe 746 747 $repos->unsubscribe('fayland','perl-net-github'); 748 749=back 750 751=head3 Hooks API 752 753L<http://developer.github.com/v3/repos/hooks/> 754 755=over 4 756 757=item hooks 758 759=item next_hook 760 761=item hook 762 763=item create_hook 764 765=item update_hook 766 767=item test_hook 768 769=item delete_hook 770 771 my @hooks = $repos->hooks; 772 while (my $hook = $repos->next_hook) { ...; } 773 my $hook = $repos->hook($hook_id); 774 my $hook = $repos->create_hook($hook_hash); 775 my $hook = $repos->update_hook($hook_id, $new_hook_hash); 776 my $st = $repos->test_hook($hook_id); 777 my $st = $repos->delete_hook($hook_id); 778 779=back 780 781=head3 Repo Merging API 782 783L<http://developer.github.com/v3/repos/merging/> 784 785=over 4 786 787=item merges 788 789 my $status = $repos->merges( { 790 "base" => "master", 791 "head" => "cool_feature", 792 "commit_message" => "Shipped cool_feature!" 793 } ); 794 795=back 796 797=head3 Repo Statuses API 798 799L<http://developer.github.com/v3/repos/statuses/> 800 801=over 4 802 803=item list_statuses 804 805 $gh->set_default_user_repo('fayland', 'perl-net-github'); 806 my @statuses = $repos->lists_statuses($sha); 807 808Or: 809 810 my @statuses = $repos->list_statuses('fayland', 'perl-net-github', $sha); 811 812=item next_status 813 814 while (my $status = $repos->next_status($sha)) { ...; } 815 816=item create_status 817 818 $gh->set_default_user_repo('fayland', 'perl-net-github'); 819 my %payload = { 820 "state" => "success", 821 "target_url" => "https://example.com/build/status", 822 "description" => "The build succeeded!", 823 "context" => "build/status" 824 }; 825 my $status = $repos->create_status($sha, %payload); 826 827Or: 828 829 my %payload = { 830 "state" => "success", 831 "target_url" => "https://example.com/build/status", 832 "description" => "The build succeeded!", 833 "context" => "build/status" 834 }; 835 my $status = $repos->create_status( 836 'fayland', 'perl-net-github', $sha, %payload 837 ); 838 839=back 840 841=head3 Repo Releases API 842 843L<http://developer.github.com/v3/repos/releases/> 844 845=over 4 846 847=item releases 848 849 my @releases = $repos->releases(); 850 while (my $release = $repos->next_release) { ...; } 851 852=item release 853 854 my $release = $repos->release($release_id); 855 856=item create_release 857 858 my $release = $repos->create_release({ 859 "tag_name" => "v1.0.0", 860 "target_commitish" => "master", 861 "name" => "v1.0.0", 862 "body" => "Description of the release", 863 "draft" => \1, 864 }); 865 866=item update_release 867 868 my $release = $repos->update_release($release_id, { 869 "tag_name" => "v1.0.0", 870 "target_commitish" => "master", 871 "name" => "v1.0.0", 872 "body" => "Description of the release", 873 }); 874 875=item delete_release 876 877 $repos->delete_release($release_id); 878 879=item release_assets 880 881 my @release_assets = $repos->release_assets($release_id); 882 while (my $asset = $repos->next_release_asset($release_id)) { ...; } 883 884=item upload_asset 885 886 my $asset = $repos->upload_asset($release_id, $name, $content_type, $file_content); 887 888Check examples/upload_asset.pl for a working example. 889 890=item release_asset 891 892 my $release_asset = $repos->release_asset($release_id, $asset_id); 893 894=item update_release_asset 895 896 my $release_asset = $repos->update_release_asset($release_id, $asset_id, { 897 name" => "foo-1.0.0-osx.zip", 898 "label" => "Mac binary" 899 }); 900 901=item delete_release_asset 902 903 my $ok = $repos->delete_release_asset($release_id, $asset_id); 904 905=back 906 907=head3 Contents API 908 909L<https://developer.github.com/v3/repos/contents/> 910 911=over 4 912 913=item get_content 914 915Gets the contents of a file or directory in a repository. 916Specify the file path or directory in $path. 917If you omit $path, you will receive the contents of all files in the repository. 918 919 my $response = $repos->get_content( $owner, $repo, $path ) 920 or 921 $repos->get_content( 922 { owner => $owner, repo => $repo, path => $path }, 923 ) 924 or 925 $repos->get_content( 926 { owner => $owner, repo => $repo, path => $path }, 927 { ref => 'feature-branch' } 928 ) 929 930=back 931 932=head3 Repo Deployment API 933 934L<http://developer.github.com/v3/repos/deployments/> 935 936=over 4 937 938=item list_deployments 939 940 my $response = $repos->list_deployments( $owner, $repo, { 941 'ref' => 'feature-branch', 942 }); 943 944=item next_deployment 945 946 while (my $deployment = $repos->next_deployment( $owner, $repo, { 947 'ref' => 'feature-branch', 948 }) { ...; } 949 950=item create_deployment 951 952 my $response = $repos->create_deployment( $owner, $repo, { 953 "ref" => 'feature-branch', 954 "description" => "deploying my new feature", 955 }); 956 957=item list_deployment_statuses 958 959 my $response = $repos->list_deployment_statuses( $owner, $repo, $deployment_id ); 960 961=item next_deployment_status 962 963 while (my $status = next_deployment_status($o,$r,$id)) { ...; } 964 965=item create_deployment_status 966 967 my $response = $repos->create_deployment_status( $owner, $repo, $deployment_id, { 968 "state": "success", 969 "target_url": "https://example.com/deployment/42/output", 970 "description": "Deployment finished successfully." 971 }); 972 973=back 974 975=head3 Repo Statistics API 976 977L<http://developer.github.com/v3/repos/statistics/> 978 979=over 4 980 981=item contributor stats 982 983=item commit activity 984 985=item code frequency 986 987=item participation 988 989=item punch card 990 991 my $contributor_stats = $repos->contributor_stats($owner, $repo); 992 my $commit_activity = $repos->commit_activity($owner, $repo); 993 my $code_freq = $repos->code_frequency($owner, $repo); 994 my $participation = $repos->participation($owner, $repo); 995 my $punch_card = $repos->punch_card($owner, $repo); 996 997=back 998 999=head1 AUTHOR & COPYRIGHT & LICENSE 1000 1001Refer L<Net::GitHub> 1002