App-GitHub
view release on metacpan or search on metacpan
lib/App/GitHub.pm view on Meta::CPAN
package App::GitHub;
use strict;
use warnings;
# ABSTRACT: GitHub Command Tools
use Carp;
use Moose;
use Net::GitHub;
use Term::ReadKey;
use Term::ReadLine;
use JSON::XS;
use IPC::Cmd qw/can_run/;
our $VERSION = '1.0.1';
has 'term' => (
is => 'rw',
required => 1,
default => sub { Term::ReadLine->new('Perl-App-GitHub') }
);
has 'prompt' => (
is => 'rw',
required => 1,
default => sub { 'github> ' }
);
has 'out_fh' => (
is => 'rw',
required => 1,
lazy => 1,
default => sub {
shift->term->OUT || \*STDOUT;
}
);
has 'repo_regexp' => (
is => 'ro',
required => 1,
isa => 'RegexpRef',
default => sub { qr/^([\-\w]+)[\/\\\s]([\-\w]+)$/ }
);
# For non-interactive mode
has 'silent' => (
is => 'rw',
required => 1,
default => 0,
);
sub print_err {
shift->print( @_, 1 );
}
sub print {
my ( $self, $message, $error ) = @_;
return 1 if $self->silent and not $error;
my $fh;
local $@;
my $rows = ( GetTerminalSize( $self->out_fh ) )[1];
my $message_rows = $message =~ tr/\n/\n/;
my $pager_use = 0;
# let less exit if one screen
no warnings 'uninitialized';
local $ENV{LESS} ||= "";
$ENV{LESS} .= " -F";
use warnings;
if ( $@ or $message_rows < $rows ) {
chomp $message;
$message .= "\n";
$fh = $self->out_fh;
}
else {
eval {
open $fh, '|-', $self->_get_pager
or croak "unable to open more: $!";
}
or $fh = $self->out_fh;
$pager_use = 1;
}
no warnings 'uninitialized';
print $fh "$message";
print $fh "\n" if $self->term->ReadLine =~ /Gnu/;
close($fh) if $pager_use;
}
sub _get_pager {
my $pager =
$ENV{PAGER}
|| can_run("less")
|| can_run("more")
|| croak "no pager found";
}
sub read {
my ( $self, $prompt ) = @_;
$prompt ||= $self->prompt;
return $self->term->readline($prompt);
}
has 'github' => (
is => 'rw',
isa => 'Net::GitHub',
);
has '_data' => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
my $dispatch = {
'exit' => sub { exit; },
'quit' => sub { exit; },
'q' => sub { exit; },
'?' => \&help,
'h' => \&help,
# Common
repo => \&set_repo,
login => \&set_login,
loadcfg => \&set_loadcfg,
# Repo
'r.show' => sub { shift->run_basic_repo_cmd( 'repos', 'get', shift ); },
'r.list' => \&repo_list,
'r.watch' => sub { shift->run_basic_repo_cmd( 'repos', 'watch', shift ); },
'r.unwatch' =>
sub { shift->run_basic_repo_cmd( 'repos', 'unwatch', shift ); },
'r.fork' =>
sub { shift->run_basic_repo_cmd( 'repos', 'create_fork', shift ); },
'r.create' => \&repo_create,
'r.set_private' => sub { shift->repo_update( private => \1, shift ); },
'r.set_public' => sub { shift->repo_update( private => \0, shift ); },
# XXX? TODO, deploy_keys collaborators
'r.commit' =>
sub { shift->run_github_with_repo( 'git_data', 'commit', shift ); },
# Issues
'i.list' => sub {
my ( $self, $type ) = @_;
$type ||= 'open';
$self->run_github_with_repo( 'issue', 'repos_issues',
{ state => $type } );
},
'i.view' => sub { shift->run_github_with_repo( 'issue', 'issue', shift ); },
'i.open' => sub { shift->issue_open_or_edit('open') },
'i.edit' => sub { shift->issue_open_or_edit( 'edit', @_ ) },
'i.close' => sub {
shift->run_github_with_repo( 'issue', 'update_issue', shift,
{ state => 'closed' } );
},
'i.reopen' => sub {
shift->run_github_with_repo( 'issue', 'update_issue', shift,
{ state => 'open' } );
},
'i.label' => \&issue_label,
'i.comment' => \&issue_comment,
# User
'u.show' => sub { shift->run_github( 'user', 'show', shift ); },
lib/App/GitHub.pm view on Meta::CPAN
i.list open|closed see a list of issues for a project
i.view :number get data on an individual issue by number
i.open open a new issue (auth required)
i.close :number close an issue (auth required)
i.reopen :number reopen an issue (auth required)
i.edit :number edit an issue (auth required)
i.comment :number
i.label add|del :num :label
add/remove a label (auth required)
Users
u.show get extended information on user
u.update update your users info (auth required)
u.followers
u.following
u.follow :user follow :user (auth required)
u.unfollow :user unfollow :user (auth required)
u.pub_keys Public Key Management (auth required)
u.pub_keys.add
u.pub_keys.del :number
Objects
o.tree :tree_sha1 get the contents of a tree by tree sha
o.trees :tree_sha1 get the contents of a tree by tree sha and recursively descend down the tree
o.blob :sha1 get the data of a blob (tree, file or commits)
Others
r.show :user :repo more in-depth information for a repository
r.list :user list out all the repositories for a user
u.show :user get extended information on :user
HELP
}
sub set_repo {
my ( $self, $repo ) = @_;
# validate
unless ( $repo =~ $self->repo_regexp ) {
$self->print("Wrong repo args ($repo), eg 'fayland perl-app-github'");
return;
}
my ( $owner, $name ) = ( $repo =~ $self->repo_regexp );
$self->{_data}->{owner} = $owner;
$self->{_data}->{repo} = $name;
# when call 'login' before 'repo'
my @logins = ( $self->{_data}->{login} and $self->{_data}->{pass} )
? (
login => $self->{_data}->{login},
pass => $self->{_data}->{pass}
)
: ();
$self->{github} = Net::GitHub->new(
owner => $owner,
repo => $name,
version => 3,
pass => $self->{_data}->{pass},
@logins,
);
$self->{prompt} = "$owner/$name> ";
}
sub set_login {
my ( $self, $login ) = @_;
( $login, my $pass ) = split( /\s+/, $login, 2 );
unless ( $login and $pass ) {
$self->print("Wrong login args ($login $pass), eg fayland password");
return;
}
$self->_do_login( $login, $pass );
}
sub set_loadcfg {
my ( $self, $ign ) = @_;
my $login = `git config --global github.user`;
my $pass = `git config --global github.pass`;
chomp($login);
chomp($pass);
unless ( ( $login and $pass ) or $ign ) {
$self->print("run git config --global github.user|pass fails");
return;
}
$self->_do_login( $login, $pass ) if $login and $pass;
}
sub _do_login {
my ( $self, $login, $pass ) = @_;
# save for set_repo
$self->{_data}->{login} = $login;
$self->{_data}->{pass} = $pass;
if ( $self->{_data}->{repo} ) {
$self->{github} = Net::GitHub->new(
version => 3,
owner => $self->{_data}->{owner},
repo => $self->{_data}->{repo},
login => $self->{_data}->{login},
pass => $self->{_data}->{pass}
);
}
else {
# Create a Net::GitHub object with the owner set to the logged in user
# Super convenient if you don't want to set a user first
$self->{github} = Net::GitHub->new(
version => 3,
login => $self->{_data}->{login},
pass => $self->{_data}->{pass},
owner => $self->{_data}->{login}
);
}
}
sub run_github {
my ( $self, $c1, $c2 ) = @_;
( run in 2.395 seconds using v1.01-cache-2.11-cpan-6aa56a78535 )