diff options
Diffstat (limited to 'extensions/ExternalBugs/lib/WebService.pm')
-rw-r--r-- | extensions/ExternalBugs/lib/WebService.pm | 1205 |
1 files changed, 1205 insertions, 0 deletions
diff --git a/extensions/ExternalBugs/lib/WebService.pm b/extensions/ExternalBugs/lib/WebService.pm new file mode 100644 index 000000000..7822f55b0 --- /dev/null +++ b/extensions/ExternalBugs/lib/WebService.pm @@ -0,0 +1,1205 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package Bugzilla::Extension::ExternalBugs::WebService; + +use strict; +use warnings; +use 5.10.1; + +use base qw(Bugzilla::WebService); +use List::MoreUtils qw(uniq); +use Scalar::Util qw(looks_like_number); + +use Bugzilla; +use Bugzilla::Constants; +use Bugzilla::Error; +use Bugzilla::Field; +use Bugzilla::Util qw(trick_taint); +use Bugzilla::WebService::Util qw(validate); + +use Bugzilla::Extension::ExternalBugs::Bug; +use Bugzilla::Extension::ExternalBugs::Type; +use Bugzilla::Extension::ExternalBugs::Util qw(resolve_ext_tracker_url); + +use constant PUBLIC_METHODS => qw( + get_ext_data + add_external_bug + update_external_bug + remove_external_bug + get_tracker + create_tracker + edit_tracker +); + +sub get_ext_data { + my ($self, $params) = @_; + my $input = Bugzilla->input_params; + + Bugzilla->login(LOGIN_REQUIRED); + + my $id = $input->{'id'}; + $id || ThrowCodeError('param_required', {param => 'id'}); + + my $ext_bug = Bugzilla::Extension::ExternalBugs::Bug->new($id); + $ext_bug->update_ext_info(); + + return { + id => $ext_bug->id, + ext_bz_id => $ext_bug->ext_bz_id, + ext_bz_bug_id => $ext_bug->ext_bz_bug_id, + ext_status => $ext_bug->ext_status, + ext_priority => $ext_bug->ext_priority, + ext_description => $ext_bug->ext_description, + ext_last_updated => $ext_bug->ext_last_updated + }; +} + +## REDHAT EXTENSION START 725627 +sub add_external_bug { + my ($self, $params) = validate(@_, 'bug_ids'); + + my $user = Bugzilla->login(LOGIN_REQUIRED); + my $dbh = Bugzilla->dbh; + + my $bug_ids = delete $params->{bug_ids}; + defined $bug_ids || ThrowCodeError('param_required', {param => 'bug_ids'}); + + my @bugs = map { Bugzilla::Bug->check($_) } @$bug_ids; + my @result = (); + my $minor_update = delete $params->{minor_update} ? 1 : 0; + + # Turn the external_bugs param into something useful + my $external_bugs = $self->_get_external_bugs_details($params->{external_bugs}); + scalar(@$external_bugs) + || ThrowCodeError('param_required', {param => 'external_bugs'}); + + my %api_name = reverse %{Bugzilla::Bug::FIELD_MAP()}; + + # This doesn't normally belong in FIELD_MAP, but we do want to translate + # "bug_group" back into "groups". + $api_name{'bug_group'} = 'groups'; + + # Add the values + $dbh->bz_start_transaction(); + foreach my $bug (@bugs) { + $bug->set_all({external_bug => {add => $external_bugs}}); + my $changes = $bug->update(); + + # We don't need to do anything if nothing changed + next unless scalar keys %$changes; + + $bug->send_changes($changes, undef, $minor_update); + + # The below is straight out of Bugzilla/WebService/Bug.pm (update sub) + my %hash = ( + id => $self->type('int', $bug->id), + last_change_time => $self->type('dateTime', $bug->delta_ts), + changes => {}, + ); + + ## REDHAT EXTENSION BEGIN + # Extention: Aliases are arrays not strings at Red Hat + # alias is returned in case users pass a mixture of ids and aliases, + # so that they can know which set of changes relates to which value + # they passed. + $hash{alias} = [map { $self->type('string', $_) } @{$bug->alias}]; + ## REDHAT EXTENSION END + + foreach my $field (keys %$changes) { + my $change = $changes->{$field}; + my $api_field = $api_name{$field} || $field; + + # We normalize undef to an empty string, so that the API + # stays consistent for things like Deadline that can become + # empty. + $change->[0] = '' if !defined $change->[0]; + $change->[1] = '' if !defined $change->[1]; + $hash{changes}->{$api_field} = { + removed => $self->type('string', $change->[0]), + added => $self->type('string', $change->[1]) + }; + } + + push(@result, \%hash); + } + $dbh->bz_commit_transaction(); + + return {bugs => \@result}; +} + +sub update_external_bug { + my ($self, $params) = @_; + + Bugzilla->login(LOGIN_REQUIRED); + + # Make sure at least one update value is provided + unless (exists $params->{ext_description} + or exists $params->{ext_priority} + or exists $params->{ext_status}) + { + ThrowCodeError('params_required', + {params => [qw/ext_description ext_priority ext_status/]}); + } + + # Lets get the external bug(s) + my $external_bugs = $self->_get_external_bugs($params); + + foreach my $external_bug (@$external_bugs) { + if (exists $params->{ext_description}) { + trick_taint($params->{ext_description}); + $external_bug->set_ext_description($params->{ext_description}); + } + if (exists $params->{ext_priority}) { + trick_taint($params->{ext_priority}); + $external_bug->set_ext_priority($params->{ext_priority}); + } + if (exists $params->{ext_status}) { + trick_taint($params->{ext_status}); + $external_bug->set_ext_status($params->{ext_status}); + } + $external_bug->update(); + } + + return {external_bugs => $self->_external_bugs_to_hash($external_bugs)}; +} + +sub remove_external_bug { + my ($self, $params) = @_; + + Bugzilla->login(LOGIN_REQUIRED); + + # Lets get the external bug(s) + my $external_bugs = $self->_get_external_bugs($params); + my $minor_update = delete $params->{minor_update} ? 1 : 0; + + # Get group them by bug id + my %bug_ids = (); + foreach my $external_bug (@$external_bugs) { + push @{$bug_ids{$external_bug->bug_id}}, $external_bug; + } + + # Make the changes and send notification + foreach my $bug_id (keys %bug_ids) { + my $bug = Bugzilla::Bug->check($bug_id); + $bug->set_all({external_bug => {remove => $bug_ids{$bug_id}}}); + my $changes = $bug->update(); + + # We don't need to do anything if nothing changed + next unless scalar keys %$changes; + + $bug->send_changes($changes, undef, $minor_update); + } + + return {external_bugs => $self->_external_bugs_to_hash($external_bugs)}; +} + +sub _get_external_bugs_details { + + # Santises the external_bugs array + my $self = shift; + my $external_bugs = shift; + my @external_bugs = (); + + foreach my $external_bug (@$external_bugs) { + my %fields = (); + + # Rewrite all this crap for external tracking + # If there's a URL, resolve it to a tracker ID and tracker URL. + if (defined($external_bug->{ext_bz_bug_url})) { + my ($tracker_id, $tracker_url) + = resolve_ext_tracker_url($external_bug->{ext_bz_bug_url}); + delete $external_bug->{ext_bz_bug_url}; + $external_bug->{ext_type_id} = $tracker_id; + $external_bug->{ext_bz_bug_id} = $tracker_url; + } + + foreach my $key (qw/ext_status ext_description ext_priority ext_bz_bug_id/) { + $fields{$key} = ''; + $fields{$key} = delete $external_bug->{$key} if exists $external_bug->{$key}; + } + + $fields{ext_bz_id} = $self->_get_ext_bz($external_bug)->id; + + # ext_bz_bug_id is mandatory + unless ($fields{ext_bz_bug_id}) { + ThrowCodeError('param_required', {param => 'ext_bz_bug_id'}); + } + + # Any non blank fields left over is an error + my @missing = grep { $external_bug->{$_} } keys %$external_bug; + if (scalar @missing) { + ThrowCodeError('ext_bug_not_param', {keys => \@missing}); + } + + push @external_bugs, \%fields; + } + + return \@external_bugs; +} + +sub _get_ext_bz { + + # Turns ext_type_id, ext_type_description or ext_type_url into + # a ExternalTracker Type object + my ($self, $params) = @_; + + my %match = (); + foreach my $key (qw/id description url/) { + if ($params->{"ext_type_$key"}) { + $match{$key} = delete $params->{"ext_type_$key"}; + } + } + + if (scalar(keys(%match)) == 0) { + ThrowCodeError('ext_bug_type_params_missing'); + } + + my $ext_bzs = Bugzilla::Extension::ExternalBugs::Type->match(\%match); + if (scalar @$ext_bzs == 0) { + ThrowCodeError('ext_bug_type_no_match'); + } + if (scalar @$ext_bzs > 1) { + ThrowCodeError('ext_bug_type_not_unique'); + } + + return $ext_bzs->[0]; +} + +sub _get_external_bugs { + + # Given some params, will find all external tracker bugs that match + # that criteria that the logged in user can see. + + my ($self, $params) = @_; + + my $external_bugs = (); + if (my $ids = $params->{ids}) { + $external_bugs = Bugzilla::Extension::ExternalBugs::Bug->new_from_list($ids); + } + else { + my %match = (); + $match{ext_bz_id} = $self->_get_ext_bz($params)->id; # Always returns a value + $match{ext_bz_bug_id} = $params->{ext_bz_bug_id} + || ThrowCodeError('param_required', {param => 'ext_bz_bug_id'}); + $match{bug_id} = $params->{bug_ids} if defined $params->{bug_ids}; + + $external_bugs = Bugzilla::Extension::ExternalBugs::Bug->match(\%match); + if (scalar @$external_bugs == 0) { + ThrowCodeError('ext_bug_no_match'); + } + } + + # We need to filter the list to bugs the user can see + @$external_bugs + = grep { Bugzilla->user->can_see_bug($_->bug_id) } @$external_bugs; + + if (scalar @$external_bugs == 0) { + ThrowCodeError('ext_bug_no_match'); + } + + return $external_bugs; +} + +## REDHAT EXTENSION END 725627 + +sub _external_bugs_to_hash { + my ($self, $external_bugs) = @_; + + my @ets; + + foreach my $et (@$external_bugs) { + my %hash = ( + "ext_status" => $et->ext_status, + "ext_bz_bug_id" => $et->ext_bz_bug_id, + "bug_id" => $et->bug_id, + "ext_description" => $et->ext_description, + "ext_priority" => $et->ext_priority, + "ext_bz_id" => $et->ext_bz_id, + "type" => { + "description" => $et->type->description, + "url" => $et->type->url, + "full_url" => $et->type->full_url, + "type" => $et->type->type, + "id" => $et->type->id, + }, + ); + + push(@ets, \%hash); + } + + return (\@ets); +} + +sub _load_tracker { + my $id = shift; + + my $tracker; + + if (looks_like_number($id)) { + $tracker = Bugzilla::Extension::ExternalBugs::Type->new($id); + } + + unless ($tracker) { + $tracker = Bugzilla::Extension::ExternalBugs::Type->new({name => $id}); + } + + ThrowUserError("ext_bz_invalid_ext_bz_id", {badvalue => $id}) unless $tracker; + + return ($tracker); +} + +sub get_tracker { + my ($self, $params) = @_; + + my $user = Bugzilla->login(LOGIN_REQUIRED); + + my $trackers = $params->{'trackers'}; + my $all = $params->{'all'}; + my @trackers; + my @results; + + if ($trackers && @$trackers) { + foreach my $tracker (@$trackers) { + push(@trackers, _load_tracker($tracker)); + } + } + elsif ($all) { + @trackers = @{Bugzilla::Extension::ExternalBugs::Type->match()}; + } + else { + ThrowCodeError('params_required', {params => ['trackers', 'all']}); + } + + foreach my $tracker (@trackers) { + if ($user->can_see_ext_bz($tracker->id)) { + push(@results, _tracker_to_hash($tracker)); + } + } + + return (\@results); +} + +sub create_tracker { + my ($self, $params) = @_; + + my $user = Bugzilla->login(LOGIN_REQUIRED); + $user->in_group('editcomponents') + || ThrowUserError("auth_failure", + {group => "editcomponents", action => "edit", object => "external_bugzilla"}); + + my $args = {description => $params->{description} // $params->{'tracker'},}; + + my @fields = qw( + url + full_url + type + can_get + matchrx + format + ); + + foreach my $field (@fields) { + $args->{$field} = $params->{$field} if (defined($params->{$field})); + } + + $args->{ext_bz_regex_id} = $params->{regex} if (defined($params->{regex})); + + if (defined($params->{groups})) { + $args->{groups} + = ref $params->{groups} ? $params->{groups} : [$params->{groups}]; + } + + my $tracker = Bugzilla::Extension::ExternalBugs::Type->create($args); + + return _tracker_to_hash($tracker); +} + +sub edit_tracker { + my ($self, $params) = @_; + + my $user = Bugzilla->login(LOGIN_REQUIRED); + $user->in_group('editcomponents') + || ThrowUserError("auth_failure", + {group => "editcomponents", action => "edit", object => "external_bugzilla"}); + + my $id = $params->{'tracker'}; + + my $tracker; + if ($id) { + $tracker = _load_tracker($id); + } + else { + ThrowCodeError('params_required', {params => ['tracker',]}); + } + + my $groups = []; + if (defined $params->{groups}) { + $groups = ref $params->{groups} ? $params->{groups} : [$params->{groups}]; + } + +## $tracker->set_description($params->{'description'}) if (defined($params->{'description'})); + $tracker->set_url($params->{'url'}) if (defined($params->{'url'})); + $tracker->set_full_url($params->{'full_url'}) + if (defined($params->{'full_url'})); + $tracker->set_type($params->{'type'}) if (defined($params->{'type'})); + $tracker->set_regex($params->{'regex'}) if (defined($params->{'regex'})); + $tracker->set_can_get($params->{'can_get'}) if (defined($params->{'can_get'})); +## $tracker->set_can_send($params->{'can_send'}) if (defined($params->{'can_send'})); +## $tracker->set_must_send($params->{'must_send'}) if (defined($params->{'must_send'})); +## $tracker->set_send_once($params->{'send_once'}) if (defined($params->{'send_once'})); + $tracker->set_matchrx($params->{'matchrx'}) if (defined($params->{'matchrx'})); + $tracker->set_format($params->{'format'}) if (defined($params->{'format'})); + $tracker->set_groups($groups) if (defined($params->{'groups'})); + my $changes = $tracker->update(); + +## return _tracker_to_hash($tracker); + return $changes; +} + +sub _tracker_to_hash { + my $tracker = shift; + + my %hash = ( + "description" => $tracker->description, + "url" => $tracker->url, + "full_url" => $tracker->full_url, + "type" => $tracker->type, + "id" => $tracker->id, + "regexs" => $tracker->regex_description, + "can_get" => $tracker->can_get, + "can_send" => $tracker->can_send, + "must_send" => $tracker->must_send, + "send_once" => $tracker->send_once, + "matchrx" => $tracker->matchrx, + "format" => $tracker->format, + ); + + my @groups = map { $_->name } @{$tracker->groups}; + $hash{"groups"} = \@groups; + + return \%hash; +} + +1; + +__END__ + +=head1 NAME + +Bugzilla::Extension::ExternalBugs::WebService - The API for creating, +changing, and deleting external bug trackers. + +=head1 DESCRIPTION + +This part of the Bugzilla API allows you to create, change and delete +external bug tracking information for existing bugs in Red Hat Bugzilla. +This is a Red Hat specific extension. + +=head1 METHODS + +See L<Bugzilla::WebService> for a description of how parameters are passed, +and what B<STABLE>, B<UNSTABLE>, and B<EXPERIMENTAL> mean. + +=head1 Functions + +All functions require that you are logged in. + +=head1 Webservice Group + +All functions belong to the ExternalBugs group, for example: ExternalBugs.add_external_bug + +=head2 get_ext_data + +B<UNSTABLE> + +=over + +=item B<Description> + +Get the current data for an external tracker, inlcuding attempting to sync data. + +B<Note:> This method will not send bug mail. + +=item B<Params> + +=over + +=item C<id> + +C<int> The id of the external tracker bug. + +=back + +=item B<Returns> + +A C<hash> with the following fields: + +=over + +=item C<id> + +C<int> The id of the bug that was updated. + +=item C<ext_bz_id> + +C<int> The id of the external tracker. + +=item C<ext_bz_bug_id> + +C<int> The bug id of the external tracker bug (i.e. the bug number of the +external tracker) + +=item C<ext_status> + +C<string> The status of the external bug + +=item C<ext_priority> + +C<string> The priority of the external bug + +=item C<ext_description> + +C<string> The description of the external bug + +=item C<ext_last_updated> + +C<string> The date the External Bug was last synced. + +=back + +=back + +=head2 add_external_bug + +B<UNSTABLE> + +=over + +=item B<Description> + +Add one or more external tracker bugs to one or more existing bugs. + +=item B<Params> + +=over + +=item C<bug_ids> + +C<array> - An array of bug ids. + +=item C<external_bugs> + +C<array> - An array of C<struct>s representing the external +trackers you wish to add. Each hash has the following keys. +either one of C<ext_bz_bug_id> or C<ext_bz_bug_url> must be supplied. + +If C<ext_bz_bug_url> is given, no other parameters are required. + +If C<ext_bz_bug_id> is given, at least one of ext_type_id, +ext_type_description or ext_type_url must also be specified. + +=over + +=item C<ext_bz_bug_url> + +C<string> The full URL to the external bug to be linked to + +=item C<ext_type_id> + +C<int> The internal id of the external bugzilla type + +=item C<ext_type_description> + +C<string> The description the external bugzilla type + +=item C<ext_type_url> + +C<string> The URL value the external bugzilla type + +=item C<ext_bz_bug_id> + +C<string> The external bug id (i.e. the bug number of the external tracker) + +=item C<ext_status> + +C<string> The status of the external bug + +=item C<ext_description> + +C<string> The description of the external bug + +=item C<ext_priority> + +C<string> The priority of the external bug + +=back + +=item C<minor_update> + +C<boolean> If set to true, this is considered a minor update and no mail is sent +to users who do not want minor update emails. If current user is not in the +minor_update_group, this parameter is simply ignored. + +=back + +=item B<Returns> + +A C<hash> with a single field, "bugs". This points to an C<array> of +C<struct>s with the following fields: + +=over + +=item C<id> + +C<int> The id of the bug that was updated. + +=item C<alias> + +C<string> The alias of the bug that was updated, if aliases are enabled and +this bug has an alias. + +=item C<last_change_time> + +C<dateTime> The exact time that this update was done at, for this bug. +If no update was done (that is, no fields had their values changed and +no comment was added) then this will instead be the last time the bug +was updated. + +=item C<changes> + +C<hash> The changes that were actually done on this bug. The keys are +the names of the fields that were changed, and the values are a hash +with two keys: + +=over + +=item C<added> (C<string>) The values that were added to this field, +possibly a comma-and-space-separated list if multiple values were added. + +=item C<removed> (C<string>) The values that were removed from this +field, possibly a comma-and-space-separated list if multiple values were +removed. + +=back + +=back + +=item B<Errors> + +=over + +=item 50 (Parameter required) + +You did not specify a required option + +=item 1001 (Invalid field) + +You specified a field in the external_bugs array that is not valid. + +=item 1002 (External Tracker type not specified) + +You must specify at least one of ext_type_id, ext_type_description +or ext_type_url. + +=item 1003 (External Tracker type not found) + +The combination of ext_type_* fields did not match any External Trackers. + +=item 1004 (External Tracker type not unique) + +The combination of ext_type_* fields matched more than one External Tracker. + +=back + +=back + +=head2 update_external_bug + +B<UNSTABLE> + +=over + +=item B<Description> + +Changes one or more external tracker bugs. + +B<Note:> This method will not send bug mail. + +=item B<Params> + +At least one of ext_desciption, ext_priority or ext_status must be specified. +Additionally, either ids, or one ext_type_* and ext_bz_bug_id must be +specified. If the 'ids' key is specified, all other values are ignored for +determining which external tracker bugs are updated. + +=over + +=item C<ids> + +C<array> An array of integer external tracker bug ids. + +=item C<ext_type_id> + +C<int> The internal id of the external bugzilla type + +=item C<ext_type_description> + +C<string> The description the external bugzilla type + +=item C<ext_type_url> + +C<string> The URL value the external bugzilla type + +=item C<ext_bz_bug_id> + +C<sting> or C<array> of C<string>s The external bug id (i.e. the bug number of the external tracker) + +=item C<bug_ids> + +C<array> - An array of bug ids. + +=item C<ext_status> + +C<string> The new status of the external bug + +=item C<ext_description> + +C<string> The new description of the external bug + +=item C<ext_priority> + +C<string> The new priority of the external bug + +=back + +=item B<Returns> + +A C<hash> with a single field, "external_bugs". This points to an C<array> of +C<struct>s with the following fields: + +=over + +=item C<id> + +C<int> The id of the external tracker bug that was updated. + +=item C<bug_id> + +C<int> The Red Hat Bugzilla bug number this external tracker bug is +attached to. + +=item C<ext_bz_id> + +C<int> The id of the external tracker updated. More information is +available in the type field. + +=item C<ext_bz_bug_id> + +C<int> The bug id of the external tracker bug (i.e. the bug number of the +external tracker) + +=item C<ext_status> + +C<string> The status of the external bug + +=item C<ext_description> + +C<string> The description of the external bug + +=item C<ext_priority> + +C<string> The priority of the external bug + +=item C<type> + +C<struct> Contains information about the External Tracker type. + +=back + +=item B<Errors> + +=over + +=item 50 (Parameter required) + +You did not specify a required option + +=item 1002 (External Tracker type not specified) + +You must specify at least one of ext_type_id, ext_type_description +or ext_type_url. + +=item 1003 (External Tracker type not found) + +The combination of ext_type_* fields did not match any External Trackers. + +=item 1004 (External Tracker type not unique) + +The combination of ext_type_* fields matched more than one External Tracker. + +=item 1006 (No External Tracker bugs found) + +No external tracker bugs were found that matched your criteria + +=back + +=item B<History> + +=over + +=item Added in Bugzilla B<4.2.1-2>, as a Red Hat extension. + +=back + +=back + + +=head2 remove_external_bug + +B<UNSTABLE> + +=over + +=item B<Description> + +Removes one or more external tracker bugs. + +=item B<Params> + +Either ids, or one ext_type_* and ext_bz_bug_id must be specified. If the +'ids' key is specified, all other values are ignored. + +=over + +=item C<ids> + +C<array> An array of integer external tracker bug ids. + +=item C<ext_type_id> + +C<int> The internal id of the external bugzilla type + +=item C<ext_type_description> + +C<string> The description the external bugzilla type + +=item C<ext_type_url> + +C<string> The URL value the external bugzilla type + +=item C<ext_bz_bug_id> + +C<sting> or C<array> of C<string>s The external bug id (i.e. the bug number of the external tracker) + +=item C<bug_ids> + +C<array> - An array of bug ids. + +=item C<minor_update> + +C<boolean> If set to true, this is considered a minor update and no mail is sent +to users who do not want minor update emails. If current user is not in the +minor_update_group, this parameter is simply ignored. + +=back + +=item B<Returns> + +A C<hash> with a single field, "external_bugs". This points to an C<array> of +C<struct>s representing the external tracker bugs deleted with the following fields: + +=over + +=item C<id> + +C<int> The id of the external tracker bug that was updated. + +=item C<bug_id> + +C<int> The Red Hat Bugzilla bug number this external tracker bug is +attached to. + +=item C<ext_bz_id> + +C<int> The id of the external tracker updated. More information is +available in the type field. + +=item C<ext_bz_bug_id> + +C<int> The bug id of the external tracker bug (i.e. the bug number of the +external tracker) + +=item C<ext_status> + +C<string> The status of the external bug + +=item C<ext_description> + +C<string> The description of the external bug + +=item C<ext_priority> + +C<string> The priority of the external bug + +=item C<type> + +C<struct> Contains information about the External Tracker type. + +=back + + +=item B<Errors> + +=over + +=item 50 (Parameter required) + +You did not specify a required option + +=item 1002 (External Tracker type not specified) + +You must specify at least one of ext_type_id, ext_type_description +or ext_type_url. + +=item 1003 (External Tracker type not found) + +The combination of ext_type_* fields did not match any External Trackers. + +=item 1004 (External Tracker type not unique) + +The combination of ext_type_* fields matched more than one External Tracker. + +=item 1006 (No External Tracker bugs found) + +No external tracker bugs were found that matched your criteria + +=back + +=item B<History> + +=over + +=item Added in Bugzilla B<4.2.1-2>, as a Red Hat extension. + +=back + +=back + +=head2 get_tracker + +B<UNSTABLE> + +=over + +=item B<Description> + +Get one or more external trackers. + +=item B<Params> + +Either I<trackers>, or I<all> must be specified. + +If a tracker is protected by group membership then it will not be visible if you +are not a member of any of the groups. + +=over + +=item C<trackers> + +C<array> An array of tracker ids or descriptions. + +=item C<all> + +C<boolean> Get all trackers. + +=back + +=back + +=head2 create_tracker + +B<UNSTABLE> + +=over + +=item B<Description> + +Create an external tracker. + +You must be in the I<editcomments> group to use this method. + +=item B<Params> + +=over + +=item C<description|tracker> + +C<string> The description to use for the tracker. + +=item C<can_get> C<Optional> + +C<boolean> Should Bugzilla try and sync data from this tracker? + +=item C<regex> C<Optional> + +C<string> The type of data this field contains. + +If this is not set then IDs are not validated. + + Number | ^[1-9]\d*$ | a number + Mantis Numbers | ^\d+$ | a number with possible leading zeros + JIRA Issue | ^[A-Z\d]+\-\d+$ | upper case letters or digits, a dash, and numbers + Number or Alias | ^(:?[1-9]\d*|[0-9A-Za-z])$ | a number or alias + SFDC Case | ^\d{8}$ | eight digits with possible leading zeros + +=item C<format> C<Optional> + +C<string> A printf style sting for formatting an ID in the UI. + +See L</"matchrx"> below. + +e.g. Github: '%s %s %s %s' + +=item C<full_url> + +C<string> The full URL to a tracker. + +e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=%id% + +=item C<matchrx> C<Optional> + +C<string> A regex used to split up the ID for use in formatting. + +See L</"format"> above. + +e.g. Github: (.*)\/(.*)/(issues|pull)/(.*) + +=item C<type> C<Optional> + +C<integer> The type of tracker that it is. Used for syncing data. + +Supported types: + + None + Bugzilla + Gerrit + GitHub + JIRA + KBase + Redmine + SFDC + SFDC_DEV + SFDC_QA + SFDC_Sandbox + SFDC_Stage + +Type 'None' does not support syncing. + +=item C<url> + +C<string> The root URL for the site. + +e.g. https://bugzilla.mozilla.org + +=item C<groups> C<Optional> + +C<array> of group names to limit access to. + +=back + +=back + +=head2 edit_tracker + +B<UNSTABLE> + +=over + +=item B<Description> + +Edit an external tracker. + +You must be in the I<editcomments> group to use this method. + +=item B<Params> + +=over + +=item C<tracker> + +C<integer|string> The ID or description of the tracker. + +=item C<can_get> C<Optional> + +C<boolean> Should Bugzilla try and sync data from this tracker? + +=item C<regex> C<Optional> + +C<string> The type of data this field contains. + +If this is not set then IDs are not validated. + + Number | ^[1-9]\d*$ | a number + Mantis Numbers | ^\d+$ | a number with possible leading zeros + JIRA Issue | ^[A-Z\d]+\-\d+$ | upper case letters or digits, a dash, and numbers + Number or Alias | ^(:?[1-9]\d*|[0-9A-Za-z])$ | a number or alias + SFDC Case | ^\d{8}$ | eight digits with possible leading zeros + +=item C<format> C<Optional> + +C<string> A printf style sting for formatting an ID in the UI. + +See L</"matchrx"> below. + +e.g. Github: '%s %s %s %s' + +=item C<full_url> + +C<string> The full URL to a tracker. + +e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=%id% + +=item C<matchrx> C<Optional> + +C<string> A regex used to split up the ID for use in formatting. + +See L</"format"> above. + +e.g. Github: (.*)\/(.*)/(issues|pull)/(.*) + +=item C<type> + +C<integer> The type of tracker that it is. Used for syncing data. + +Supported types: + + None + Bugzilla + Gerrit + GitHub + JIRA + KBase + Redmine + SFDC + SFDC_DEV + SFDC_QA + SFDC_Sandbox + SFDC_Stage + +Type 'None' does not support syncing. + +=item C<url> + +C<string> The root URL for the site. + +e.g. https://bugzilla.mozilla.org + +=item C<groups> + +C<array> of group names to limit access to. + +=back + +=back |