aboutsummaryrefslogtreecommitdiff
path: root/contrib/bz_webservice_demo.pl
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bz_webservice_demo.pl')
-rwxr-xr-xcontrib/bz_webservice_demo.pl434
1 files changed, 434 insertions, 0 deletions
diff --git a/contrib/bz_webservice_demo.pl b/contrib/bz_webservice_demo.pl
new file mode 100755
index 0000000..3b87cf5
--- /dev/null
+++ b/contrib/bz_webservice_demo.pl
@@ -0,0 +1,434 @@
+#!/usr/bin/perl -w
+# 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/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+=head1 NAME
+
+bz_webservice_demo.pl - Show how to talk to Bugzilla via XMLRPC
+
+=head1 SYNOPSIS
+
+C<bz_webservice_demo.pl [options]>
+
+C<bz_webservice_demo.pl --help> for detailed help
+
+=cut
+
+use strict;
+use lib qw(lib);
+use Getopt::Long;
+use Pod::Usage;
+use File::Basename qw(dirname);
+use File::Spec;
+use HTTP::Cookies;
+use XMLRPC::Lite;
+
+# If you want, say “use Bugzilla::WebService::Constants” here to get access
+# to Bugzilla's web service error code constants.
+# If you do this, remember to issue a “use lib” pointing to your Bugzilla
+# installation directory, too.
+
+my $help;
+my $Bugzilla_uri;
+my $Bugzilla_login;
+my $Bugzilla_password;
+my $Bugzilla_remember;
+my $bug_id;
+my $product_name;
+my $create_file_name;
+my $legal_field_values;
+my $add_comment;
+my $private;
+my $work_time;
+my $fetch_extension_info = 0;
+my $debug;
+
+GetOptions('help|h|?' => \$help,
+ 'uri=s' => \$Bugzilla_uri,
+ 'login:s' => \$Bugzilla_login,
+ 'password=s' => \$Bugzilla_password,
+ 'rememberlogin!' => \$Bugzilla_remember,
+ 'bug_id:s' => \$bug_id,
+ 'product_name:s' => \$product_name,
+ 'create:s' => \$create_file_name,
+ 'field:s' => \$legal_field_values,
+ 'comment:s' => \$add_comment,
+ 'private:i' => \$private,
+ 'worktime:f' => \$work_time,
+ 'extension_info' => \$fetch_extension_info,
+ 'debug' => \$debug
+ ) or pod2usage({'-verbose' => 0, '-exitval' => 1});
+
+=head1 OPTIONS
+
+=over
+
+=item --help, -h, -?
+
+Print a short help message and exit.
+
+=item --uri
+
+URI to Bugzilla's C<xmlrpc.cgi> script, along the lines of
+C<http://your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi>.
+
+=item --login
+
+Bugzilla login name. Specify this together with B<--password> in order to log in.
+
+Specify this without a value in order to log out.
+
+=item --password
+
+Bugzilla password. Specify this together with B<--login> in order to log in.
+
+=item --rememberlogin
+
+Gives access to Bugzilla's "Bugzilla_remember" option.
+Specify this option while logging in to do the same thing as ticking the
+C<Bugzilla_remember> box on Bugilla's log in form.
+Don't specify this option to do the same thing as unchecking the box.
+
+See Bugzilla's rememberlogin parameter for details.
+
+=item --bug_id
+
+Pass a bug ID to have C<bz_webservice_demo.pl> do some bug-related test calls.
+
+=item --product_name
+
+Pass a product name to have C<bz_webservice_demo.pl> do some product-related
+test calls.
+
+=item --create
+
+Specify a file that contains settings for the creating of a new bug.
+
+=item --field
+
+Pass a field name to get legal values for this field. It must be either a
+global select field (such as bug_status, resolution, rep_platform, op_sys,
+priority, bug_severity) or a custom select field.
+
+=item --comment
+
+A comment to add to a bug identified by B<--bug_id>. You must also pass a B<--login>
+and B<--password> to log in to Bugzilla.
+
+=item --private
+
+An optional non-zero value to specify B<--comment> as private.
+
+=item --worktime
+
+An optional double precision number specifying the work time for B<--comment>.
+
+=item --extension_info
+
+If specified on the command line, the script returns the information about the
+extensions that are installed.
+
+=item --debug
+
+Enable tracing at the debug level of XMLRPC requests and responses.
+
+=back
+
+=head1 DESCRIPTION
+
+=cut
+
+pod2usage({'-verbose' => 1, '-exitval' => 0}) if $help;
+_syntaxhelp('URI unspecified') unless $Bugzilla_uri;
+
+# We will use this variable for SOAP call results.
+my $soapresult;
+
+# We will use this variable for function call results.
+my $result;
+
+# Open our cookie jar. We save it into a file so that we may re-use cookies
+# to avoid the need of logging in every time. You're encouraged, but not
+# required, to do this in your applications, too.
+# Cookies are only saved if Bugzilla's rememberlogin parameter is set to one of
+# - on
+# - defaulton (and you didn't pass 0 as third parameter to User.login)
+# - defaultoff (and you passed 1 as third parameter to User.login)
+my $cookie_jar =
+ new HTTP::Cookies('file' => File::Spec->catdir(dirname($0), 'cookies.txt'),
+ 'autosave' => 1);
+
+=head2 Initialization
+
+Using the XMLRPC::Lite class, you set up a proxy, as shown in this script.
+Bugzilla's XMLRPC URI ends in C<xmlrpc.cgi>, so your URI looks along the lines
+of C<http://your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi>.
+
+=cut
+
+my $proxy = XMLRPC::Lite->proxy($Bugzilla_uri,
+ 'cookie_jar' => $cookie_jar);
+
+=head2 Debugging
+
+Enable tracing at the debug level of XMLRPC requests and responses if requested.
+
+=cut
+
+if ($debug) {
+ $proxy->import(+trace => 'debug');
+}
+
+=head2 Checking Bugzilla's version
+
+To make sure the Bugzilla you're connecting to supports the methods you wish to
+call, you may want to compare the result of C<Bugzilla.version> to the
+minimum required version your application needs.
+
+=cut
+
+$soapresult = $proxy->call('Bugzilla.version');
+_die_on_fault($soapresult);
+print 'Connecting to a Bugzilla of version ' . $soapresult->result()->{version} . ".\n";
+
+=head2 Checking Bugzilla's timezone
+
+To make sure that you understand the dates and times that Bugzilla returns to you, you may want to call C<Bugzilla.timezone>.
+
+=cut
+
+$soapresult = $proxy->call('Bugzilla.timezone');
+_die_on_fault($soapresult);
+print 'Bugzilla\'s timezone is ' . $soapresult->result()->{timezone} . ".\n";
+
+=head2 Getting Extension Information
+
+Returns all the information any extensions have decided to provide to the webservice.
+
+=cut
+
+if ($fetch_extension_info) {
+ $soapresult = $proxy->call('Bugzilla.extensions');
+ _die_on_fault($soapresult);
+ my $extensions = $soapresult->result()->{extensions};
+ foreach my $extensionname (keys(%$extensions)) {
+ print "Extension '$extensionname' information\n";
+ my $extension = $extensions->{$extensionname};
+ foreach my $data (keys(%$extension)) {
+ print ' ' . $data . ' => ' . $extension->{$data} . "\n";
+ }
+ }
+}
+
+=head2 Logging In and Out
+
+=head3 Using Bugzilla's Environment Authentication
+
+Use a
+C<http://login:password@your.bugzilla.installation/path/to/bugzilla/xmlrpc.cgi>
+style URI.
+You don't log out if you're using this kind of authentication.
+
+=head3 Using Bugzilla's CGI Variable Authentication
+
+Use the C<User.login> and C<User.logout> calls to log in and out, as shown
+in this script.
+
+The C<Bugzilla_remember> parameter is optional.
+If omitted, Bugzilla's defaults apply (as specified by its C<rememberlogin>
+parameter).
+
+Bugzilla hands back cookies you'll need to pass along during your work calls.
+
+=cut
+
+if (defined($Bugzilla_login)) {
+ if ($Bugzilla_login ne '') {
+ # Log in.
+ $soapresult = $proxy->call('User.login',
+ { login => $Bugzilla_login,
+ password => $Bugzilla_password,
+ remember => $Bugzilla_remember } );
+ _die_on_fault($soapresult);
+ print "Login successful.\n";
+ }
+ else {
+ # Log out.
+ $soapresult = $proxy->call('User.logout');
+ _die_on_fault($soapresult);
+ print "Logout successful.\n";
+ }
+}
+
+=head2 Retrieving Bug Information
+
+Call C<Bug.get> with the ID of the bug you want to know more of.
+The call will return a C<Bugzilla::Bug> object.
+
+Note: You can also use "Bug.get_bugs" for compatibility with Bugzilla 3.0 API.
+
+=cut
+
+if ($bug_id) {
+ $soapresult = $proxy->call('Bug.get', { ids => [$bug_id] });
+ _die_on_fault($soapresult);
+ $result = $soapresult->result;
+ my $bug = $result->{bugs}->[0];
+ foreach my $field (keys(%$bug)) {
+ my $value = $bug->{$field};
+ if (ref($value) eq 'HASH') {
+ foreach (keys %$value) {
+ print "$_: " . $value->{$_} . "\n";
+ }
+ }
+ else {
+ print "$field: $value\n";
+ }
+ }
+}
+
+=head2 Retrieving Product Information
+
+Call C<Product.get> with the name of the product you want to know more of.
+The call will return a C<Bugzilla::Product> object.
+
+=cut
+
+if ($product_name) {
+ $soapresult = $proxy->call('Product.get', {'names' => [$product_name]});
+ _die_on_fault($soapresult);
+ $result = $soapresult->result()->{'products'}->[0];
+
+ # Iterate all entries, the values may be scalars or array refs with hash refs.
+ foreach my $key (sort(keys %$result)) {
+ my $value = $result->{$key};
+
+ if (ref($value)) {
+ my $counter = 0;
+ foreach my $hash (@$value) {
+ while (my ($innerKey, $innerValue) = each %$hash) {
+ print "$key.$counter.$innerKey: $innerValue\n";
+ }
+ ++$counter;
+ }
+ }
+ else {
+ print "$key: $value\n"
+ }
+ }
+}
+
+=head2 Creating A Bug
+
+Call C<Bug.create> with the settings read from the file indicated on
+the command line. The file must contain a valid anonymous hash to use
+as argument for the call to C<Bug.create>.
+The call will return a hash with a bug id for the newly created bug.
+
+=cut
+
+if ($create_file_name) {
+ $soapresult = $proxy->call('Bug.create', do "$create_file_name" );
+ _die_on_fault($soapresult);
+ $result = $soapresult->result;
+
+ if (ref($result) eq 'HASH') {
+ foreach (keys(%$result)) {
+ print "$_: $$result{$_}\n";
+ }
+ }
+ else {
+ print "$result\n";
+ }
+
+}
+
+=head2 Getting Legal Field Values
+
+Call C<Bug.legal_values> with the name of the field (including custom
+select fields). The call will return a reference to an array with the
+list of legal values for this field.
+
+=cut
+
+if ($legal_field_values) {
+ $soapresult = $proxy->call('Bug.legal_values', {field => $legal_field_values} );
+ _die_on_fault($soapresult);
+ $result = $soapresult->result;
+
+ print join("\n", @{$result->{values}}) . "\n";
+}
+
+=head2 Adding a comment to a bug
+
+Call C<Bug.add_comment> with the bug id, the comment text, and optionally the number
+of hours you worked on the bug, and a boolean indicating if the comment is private
+or not.
+
+=cut
+
+if ($add_comment) {
+ if ($bug_id) {
+ $soapresult = $proxy->call('Bug.add_comment', {id => $bug_id,
+ comment => $add_comment, private => $private, work_time => $work_time});
+ _die_on_fault($soapresult);
+ print "Comment added.\n";
+ }
+ else {
+ print "A --bug_id must be supplied to add a comment.";
+ }
+}
+
+=head1 NOTES
+
+=head2 Character Set Encoding
+
+Make sure that your application either uses the same character set
+encoding as Bugzilla does, or that it converts correspondingly when using the
+web service API.
+By default, Bugzilla uses UTF-8 as its character set encoding.
+
+=head2 Format For Create File
+
+The create format file is a piece of Perl code, that should look something like
+this:
+
+ {
+ product => "TestProduct",
+ component => "TestComponent",
+ summary => "TestBug - created from bz_webservice_demo.pl",
+ version => "unspecified",
+ description => "This is a description of the bug... hohoho",
+ op_sys => "All",
+ platform => "All",
+ priority => "P4",
+ severity => "normal"
+ };
+
+=head1 SEE ALSO
+
+There are code comments in C<bz_webservice_demo.pl> which might be of further
+help to you.
+
+=cut
+
+sub _die_on_fault {
+ my $soapresult = shift;
+
+ if ($soapresult->fault) {
+ my ($package, $filename, $line) = caller;
+ die $soapresult->faultcode . ' ' . $soapresult->faultstring .
+ " in SOAP call near $filename line $line.\n";
+ }
+}
+
+sub _syntaxhelp {
+ my $msg = shift;
+
+ print "Error: $msg\n";
+ pod2usage({'-verbose' => 0, '-exitval' => 1});
+}