File Coverage

lib/App/TimeTracker/Command/GitHub.pm
Criterion Covered Total %
statement 20 37 54.0
branch 0 10 0.0
condition n/a
subroutine 7 9 77.7
pod 0 1 0.0
total 27 57 47.3


line stmt bran cond sub pod time code
1             use strict;
2 1     1   532 use warnings;
  1         2  
  1         25  
3 1     1   3 use 5.020;
  1         2  
  1         18  
4 1     1   13  
  1         3  
5             # ABSTRACT: App::TimeTracker GitHub plugin
6             use App::TimeTracker::Utils qw(error_message warning_message);
7 1     1   410  
  1         8475  
  1         59  
8             our $VERSION = "1.001";
9              
10             use Moose::Role;
11 1     1   415 use Pithub;
  1         383339  
  1         4  
12 1     1   5360  
  1         245083  
  1         509  
13             has 'issue' => (
14             is => 'rw',
15             isa => 'Str',
16             documentation => 'github issue',
17             predicate => 'has_issue'
18             );
19              
20             has 'github_client' => (
21             is => 'rw',
22             isa => 'Maybe[Pithub]',
23             lazy_build => 1,
24             traits => ['NoGetopt'],
25             );
26              
27             my $self = shift;
28             my $config = $self->config->{github};
29 0     0      
30 0           my %args;
31              
32 0           # required
33             for my $fld (qw(user repo token)) {
34             error_message( "Please configure github." . $fld . ". in your TimeTracker config" )
35 0           unless $config->{$fld};
36             $args{$fld} = $config->{$fld};
37 0 0         }
38 0            
39             # optional
40             $args{api_uri} = $config->{api_uri} if $config->{api_uri};
41              
42 0 0         if ( $config->{upstream} ) {
43             for my $fld (qw(user repo)) {
44 0 0         error_message( "You set upstream, but did not set '" . $fld . "'!" )
45 0           unless $config->{upstream}->{$fld};
46             $args{$fld} = $config->{upstream}->{$fld};
47 0 0         }
48 0           }
49              
50             return Pithub->new(%args);
51             }
52 0            
53             before [ 'cmd_start', 'cmd_continue', 'cmd_append' ] => sub {
54             my $self = shift;
55             return unless $self->has_issue;
56              
57             my $issuename = 'issue#' . $self->issue;
58             $self->insert_tag($issuename);
59              
60             my $cfg = $self->config->{github};
61             my $response =
62             $self->github_client->issues->get( repo => $cfg->{repo}, issue_id => $self->issue );
63             unless ( $response->success ) {
64             error_message( "Cannot find issue %s in %s/%s", $self->issue, $cfg->@{ 'user', 'repo' } );
65             return;
66             }
67             my $issue = $response->content;
68             my $name = $issue->{title};
69              
70             #use Data::Dumper; $Data::Dumper::Maxdepth=3;$Data::Dumper::Sortkeys=1;warn Data::Dumper::Dumper $data;
71              
72             if ( defined $self->description ) {
73             $self->description( $self->description . ' ' . $name );
74             }
75             else {
76             $self->description($name);
77             }
78              
79             if ( $self->meta->does_role('App::TimeTracker::Command::Git') ) {
80             my $branch = $self->issue;
81             if ($name) {
82             $branch = $self->safe_branch_name( $self->issue . ' ' . $name );
83             }
84             $branch =~ s/_/-/g;
85             $self->branch( lc($branch) ) unless $self->branch;
86             }
87              
88             ## reopen
89             #if ($self->config->{github}{reopen} && $issue->{state} eq 'closed') {
90             # $self->_call('PUT','projects/'.$self->project_id.'/issues/'.$issue_id.'?state_event=reopen');
91             # say "reopend closed issue";
92             #}
93             #
94             ## set assignee
95             #if ($self->config->{github}{set_assignee}) {
96             # my $assignee;
97             # if ($issue->{assignees} && $issue->{assignees}[0] && $issue->{assignees}[0]{username}) {
98             # $assignee = $issue->{assignees}[0]{username};
99             # }
100             # elsif ( $issue->{assignee} && $issue->{assignee}{username}) {
101             # $assignee = $issue->{assignee}{username};
102             # }
103             #
104             # if (my $user = $self->_call('GET','user')) {
105             # if ($assignee) {
106             # if ($assignee ne $user->{username}) {
107             # warning_message("Assignee already set to ".$assignee);
108             # }
109             # }
110             # else {
111             # $self->_call('PUT','projects/'.$self->project_id.'/issues/'.$issue_id.'?assignee_id='.$user->{id});
112             # say "Assignee set to you";
113             # }
114             # }
115             # else {
116             # error_message("Cannot get user-id, thus cannot assign issue");
117             # }
118             #}
119             #
120             ## un/set labels
121             #if (my $on_start = $self->config->{github}{labels_on_start}) {
122             # my %l = map {$_ => 1} @{$issue->{labels}};
123             # if (my $add = $on_start->{add}) {
124             # foreach my $new (@$add) {
125             # $l{$new}=1;
126             # }
127             # }
128             # if (my $remove = $on_start->{remove}) {
129             # foreach my $remove (@$remove) {
130             # delete $l{$remove};
131             # }
132             # }
133             # $self->_call('PUT','projects/'.$self->project_id.'/issues/'.$issue_id.'?labels='.uri_escape(join(',',keys %l)));
134             # say "Labels are now: ".join(', ',sort keys %l);
135             #}
136             };
137              
138             my $self = shift;
139             foreach my $tag ( @{ $self->tags } ) {
140             next unless $tag =~ /^issue#(\d+)/;
141 0     0 0   return $1;
142 0           }
  0            
143 0 0         }
144 0            
145             no Moose::Role;
146              
147             q{ listening to: Train noises on my way from Wien to Graz }
148 1     1   8  
  1         1  
  1         9  
149              
150             =pod
151              
152             =encoding UTF-8
153              
154             =head1 NAME
155              
156             App::TimeTracker::Command::GitHub - App::TimeTracker GitHub plugin
157              
158             =head1 VERSION
159              
160             version 1.001
161              
162             =head1 DESCRIPTION
163              
164             Connect tracker with L<GitHub|https://github.com/>.
165              
166             Using the GitHub plugin, tracker can fetch the name of an issue and use
167             it as the task's description; generate a nicely named C<git> branch
168             (if you're also using the C<Git> plugin).
169              
170             =head1 CONFIGURATION
171              
172             =head2 plugins
173              
174             Add C<GitHub> to the list of plugins.
175              
176             =head2 github
177              
178             add a hash named C<github>, containing the following keys:
179              
180             =head3 user [REQUIRED]
181              
182             Your github user name. Best stored in your global TimeTracker config file.
183              
184             =head3 token [REQUIRED]
185              
186             Your personal access token. Get it from your github settings
187             (Developer Settings, Personal access token): https://github.com/settings/tokens
188              
189             Best stored in your global TimeTracker config file.
190              
191             =head3 repo [REQUIRED]
192              
193             The name of the repository you are working on. Currently a required
194             entry to the config file, but we might upgrade it to a command line
195             param and/or try to guess it from the current working dir or your git
196             config.
197              
198             =head3 api_uri
199              
200             Optional.
201              
202             Set this to the URL of your local GitHub Enterprise installation.
203              
204             =head3 upstream
205              
206             Optional.
207              
208             If the project you are working on has an upstream project where issues are
209             handled, then you can set upstream to a hash of user and repo (like on a normal
210             project) to fetch issues from there.
211              
212             =head1 NEW COMMANDS
213              
214             No new commands
215              
216             =head1 CHANGES TO OTHER COMMANDS
217              
218             =head2 start, continue
219              
220             =head3 --issue
221              
222             ~/perl/Your-Project$ tracker start --issue 42
223              
224             If C<--issue> is set and we can find an issue with this id in your current repo
225              
226             =over
227              
228             =item * set or append the issue name in the task description ("Rev up FluxCompensator!!")
229              
230             =item * add the issue id to the tasks tags ("issue#42")
231              
232             =item * if C<Git> is also used, determine a save branch name from the issue name, and change into this branch ("42-rev-up-fluxcompensator")
233              
234             =item * TODO: assign to your user, if C<set_assignee> is set and issue is not assigned
235              
236             =item * TODO: reopen a closed issue if C<reopen> is set
237              
238             =item * TODO: modifiy the labels by adding all labels listed in C<labels_on_start.add> and removing all lables listed in C<labels_on_start.add>
239              
240             =back
241              
242             =head1 Contributors
243              
244             =over
245              
246             =item * L<Thomas MANTL|https://github.com/TM2500>
247              
248             =back
249              
250             =head1 AUTHOR
251              
252             Thomas Klausner <domm@plix.at>
253              
254             =head1 COPYRIGHT AND LICENSE
255              
256             This software is copyright (c) 2020 by Thomas Klausner.
257              
258             This is free software; you can redistribute it and/or modify it under
259             the same terms as the Perl 5 programming language system itself.
260              
261             =cut