############################################################################# # # Role to provide Bugzilla functionality to our command classes. # # Author: Chris Weyl (cpan:RSRCHBOY), <cweyl@alumni.drew.edu> # Company: No company, personal work # Created: 01/06/2009 11:09:28 PM PST # # Copyright (c) 2009 Chris Weyl <cweyl@alumni.drew.edu> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # ############################################################################# package Fedora::App::ReviewTool::Bugzilla; use Moose::Role; use Fedora::Bugzilla; use Fedora::Bugzilla::PackageReviewBug; use IO::Prompt; use Term::ProgressBar; use Term::Size; use Text::SimpleTable; # debugging #use Smart::Comments '###', '####'; use namespace::clean -except => 'meta'; our $VERSION = '0.08'; has userid => ( is => 'rw', isa => 'Str', #cmd_aliases => 'u', documentation => 'bugzilla userid', lazy_build => 1, ); sub _build_userid { my $self = shift @_; #my $def = $self->app->_has__email ? $self->app->_email : q{}; my $userid = prompt "What's your bugzilla login email addy? ", -default => $self->app->_email ? $self->app->_email : q{} ; print "Thanks, $userid. You can set this permanently by running setup.\n"; # force stringification return "$userid"; } has passwd => ( is => 'rw', isa => 'Str', lazy_build => 1, documentation => 'bugzilla password', ); sub _build_passwd { my $self = shift @_; # if we're here, no password anywhere! my $pw = prompt 'Please enter your bugzilla password: ', -echo => '*'; # force stringification return "$pw"; } has _bz => (is => 'ro', isa => 'Fedora::Bugzilla', lazy_build => 1); has _bz => ( is => 'ro', isa => 'Fedora::Bugzilla', lazy_build => 1, ); sub _build__bz { my $self = shift @_; my $bz; if ($Fedora::Bugzilla::VERSION <= 0.04) { # 0.04 and prior don't handle *_cb correctly $bz = Fedora::Bugzilla->new( userid => $self->userid, passwd => $self->passwd, default_bug_class => 'Fedora::Bugzilla::PackageReviewBug', ); } else { # note the use of _cb()'s $bz = Fedora::Bugzilla->new( userid_cb => sub { $self->userid }, passwd_cb => sub { $self->passwd }, default_bug_class => 'Fedora::Bugzilla::PackageReviewBug', ); } # FIXME -- force a login until F::Bz deals with unauth. queries $bz->login; return $bz; } sub find_my_submissions { my $self = shift @_; my $bugs = $self->_bz->search( product => 'Fedora', component => 'Package Review', version => 'rawhide', bug_status => 'NEW,ASSIGNED', reporter => $self->userid, ); return $bugs; } sub find_all_my_submissions { my $self = shift @_; my $bugs = $self->_bz->search( product => 'Fedora', component => 'Package Review', #version => 'rawhide', #bug_status => 'NEW,ASSIGNED', reporter => $self->userid, ); return $bugs; } sub find_all_submissions { my $self = shift @_; my $bugs = $self->_bz->search( product => 'Fedora', component => 'Package Review', #version => 'rawhide', #bug_status => 'NEW,ASSIGNED', #reporter => $self->userid, ); return $bugs; } sub find_my_active_reviews { my $self = shift @_; my $bugs = $self->_bz->search( product => 'Fedora', component => 'Package Review', version => 'rawhide', bug_status => 'NEW,ASSIGNED', assigned_to => $self->userid, 'field0-0-0' => 'flagtypes.name', 'type0-0-0' => 'equals', 'value0-0-0' => 'fedora-review?', 'field0-0-1' => 'flagtypes.name', 'type0-0-1' => 'equals', 'value0-0-1' => 'fedora-review+', ); return $bugs; } sub find_bug_for_pkg { my $self = shift @_; my $pkg = shift @_ or die "Must pass package name!"; ### searching bugzilla for: $pkg my $bugs = $self->_bz->search( product => 'Fedora', component => 'Package Review', version => 'rawhide', #bug_status => [ 'CLOSED' ], #bug_status => 'NEW,ASSIGNED,CLOSED', # hot dang! this works! short_desc_type => 'substring', short_desc => "$pkg", ); ### found this many bugs: $bugs->num_bugs return wantarray ? $bugs->ids : $bugs->first_bug; # FIXME this is future... not going to sort it out right now; playing dumb if ($bugs->num_bugs == 1) { my $bug = $bugs->first_bug; #if (($bug->status eq 'CLOSED') && ($bug->resolution ne 'NEXTRELEASE')) { if ($bug->full_status eq 'CLOSED') { return $bug if $bug->resolution eq 'NEXTRELEASE'; warn "A closed bug was found, but not NEXTRELEASE: $bug\n"; return; } } } sub bug_table { my ($self, $bugs) = @_; # refactor to ::Bugs $bugs = Fedora::Bugzilla::Bugs->new(bz => $self->_bz, ids => [ "$bugs" ]) if $bugs->isa('Fedora::Bugzilla::Bug'); # figure out how much we have to play with my ($cols, $rows) = Term::Size::chars *STDOUT{IO}; my $len = $cols - (6+1+1 + 3*3 + 2*2); ### doing submitted... my $t = Text::SimpleTable->new( [ 6, 'Bug' ], [ 1, 'R' ], [ 1, 'C' ], [ $len, 'Name' ], #[ 20, 'Last Update' ] ); # Note this is still useful, even though we're gathering all the data # available through XML-RPC via one Bug.get() call, as our flags require # that we pull the XML representation of the bug as well. my $pbar = Term::ProgressBar->new({ #count => $bugs->num_bugs, count => $bugs->num_ids, name => 'Fetching bugzilla data', ETA => 'linear', }); my $i = 0; $pbar->update($i); #my $tz = DateTime::TimeZone->new('local' => 'x'); my $tz = DateTime::TimeZone::Local->TimeZone(); BUG_LOOP: for my $bug ($bugs->bugs) { my $pkg = $bug->package_name; my $name = "$pkg\n" . ' ' . $bug->full_status . '; last changed: ' . $bug->last_change_time->set_time_zone($tz) . "\n" . ' R: ' . $bug->reporter . "\n" . ' A: ' . $bug->assigned_to ; my $update = $bug->last_change_time . "\n " . $bug->status; # add our table row $t->row( "$bug", $self->flag($bug, 'fedora-review'), $self->flag($bug, 'fedora-cvs'), $name, #$update ); $pbar->update(++$i); } return $t->draw; } sub flag { my ($self, $bug, $flag) = @_; return $bug->has_flag($flag) ? $bug->get_flag($flag) : '*' ; } =head2 _pick_srpm_uri(...) Given one or more URI's, pick the newest one. =cut sub _pick_srpm_uri { my $self = shift @_; my @uris = @_; # FIXME probably a better way to do this my @abc = ('a'..'z'); my $ret = prompt 'Please pick the correct URI...', -1, -menu => [ @uris ], -default => $abc[$#uris], ; return URI->new($ret); } 1; __END__ =head1 NAME Fedora::App::ReviewTool::Bugzilla - bugzilla command role =head1 SYNOPSIS package ... use Moose; extends ...; with 'Fedora::App::ReviewTool::Bugzilla; # profit! (there's a lot of that around here) =head1 DESCRIPTION Provide a few common attributes / methods for working with Bugzilla. =head1 ATTRIBUTES =over 4 =item B<userid> Bugzilla userid. =item B<passwd> Bugzilla passwd. =item B<_bz> The actual L<Fedora::Bugzilla> instance. =back =head1 SUBROUTINES/METHODS =over 4 =item B<find_my_submissions> Search for open tix under 'Fedora/Package Reviews' with b<userid> as the reporter. =item B<find_bug_for_pkg (pkg name)> Given a package name, try to find a corresponding review tix. Returns the bug iff one and only one is found; undef if none is found. If more than one review tix is found, the result is undefined. This is a known issue. =head1 CONFIGURATION AND ENVIRONMENT FIXME a bit about the config file would be nice =head1 SEE ALSO L<Fedora::App::ReviewTool>, L<Fedora::Bugzilla>. =head1 AUTHOR Chris Weyl <cweyl@alumni.drew.edu> =head1 LICENSE AND COPYRIGHT Copyright (c) 2009 Chris Weyl <cweyl@alumni.drew.edu> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc. 59 Temple Place, Suite 330 Boston, MA 02111-1307 USA =cut