|
Packit Service |
4b33e2 |
#!/usr/libexec/platform-python
|
|
Packit Service |
4b33e2 |
#
|
|
Packit Service |
4b33e2 |
# bugzilla - a commandline frontend for the python bugzilla module
|
|
Packit Service |
4b33e2 |
#
|
|
Packit Service |
4b33e2 |
# Copyright (C) 2007-2017 Red Hat Inc.
|
|
Packit Service |
4b33e2 |
# Author: Will Woods <wwoods@redhat.com>
|
|
Packit Service |
4b33e2 |
# Author: Cole Robinson <crobinso@redhat.com>
|
|
Packit Service |
4b33e2 |
#
|
|
Packit Service |
4b33e2 |
# This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
4b33e2 |
# under the terms of the GNU General Public License as published by the
|
|
Packit Service |
4b33e2 |
# Free Software Foundation; either version 2 of the License, or (at your
|
|
Packit Service |
4b33e2 |
# option) any later version. See http://www.gnu.org/copyleft/gpl.html for
|
|
Packit Service |
4b33e2 |
# the full text of the license.
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
from __future__ import print_function
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
import locale
|
|
Packit Service |
4b33e2 |
from logging import getLogger, DEBUG, INFO, WARN, StreamHandler, Formatter
|
|
Packit Service |
4b33e2 |
import argparse
|
|
Packit Service |
4b33e2 |
import os
|
|
Packit Service |
4b33e2 |
import re
|
|
Packit Service |
4b33e2 |
import socket
|
|
Packit Service |
4b33e2 |
import sys
|
|
Packit Service |
4b33e2 |
import tempfile
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# pylint: disable=import-error
|
|
Packit Service |
4b33e2 |
if sys.version_info[0] >= 3:
|
|
Packit Service |
4b33e2 |
# pylint: disable=no-name-in-module,redefined-builtin
|
|
Packit Service |
4b33e2 |
from xmlrpc.client import Fault, ProtocolError
|
|
Packit Service |
4b33e2 |
from urllib.parse import urlparse
|
|
Packit Service |
4b33e2 |
basestring = (str, bytes)
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
from xmlrpclib import Fault, ProtocolError
|
|
Packit Service |
4b33e2 |
from urlparse import urlparse
|
|
Packit Service |
4b33e2 |
# pylint: enable=import-error
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
import requests.exceptions
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
import bugzilla
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
DEFAULT_BZ = 'https://bugzilla.redhat.com/xmlrpc.cgi'
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
format_field_re = re.compile("%{([a-z0-9_]+)(?::([^}]*))?}")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
log = getLogger(bugzilla.__name__)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
################
|
|
Packit Service |
4b33e2 |
# Util helpers #
|
|
Packit Service |
4b33e2 |
################
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _is_unittest():
|
|
Packit Service |
4b33e2 |
return bool(os.getenv("__BUGZILLA_UNITTEST"))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _is_unittest_debug():
|
|
Packit Service |
4b33e2 |
return bool(os.getenv("__BUGZILLA_UNITTEST_DEBUG"))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def to_encoding(ustring):
|
|
Packit Service |
4b33e2 |
string = ''
|
|
Packit Service |
4b33e2 |
if isinstance(ustring, basestring):
|
|
Packit Service |
4b33e2 |
string = ustring
|
|
Packit Service |
4b33e2 |
elif ustring is not None:
|
|
Packit Service |
4b33e2 |
string = str(ustring)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if sys.version_info[0] >= 3:
|
|
Packit Service |
4b33e2 |
return string
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
preferred = locale.getpreferredencoding()
|
|
Packit Service |
4b33e2 |
if _is_unittest():
|
|
Packit Service |
4b33e2 |
preferred = "UTF-8"
|
|
Packit Service |
4b33e2 |
return string.encode(preferred, 'replace')
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def open_without_clobber(name, *args):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Try to open the given file with the given mode; if that filename exists,
|
|
Packit Service |
4b33e2 |
try "name.1", "name.2", etc. until we find an unused filename.
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
fd = None
|
|
Packit Service |
4b33e2 |
count = 1
|
|
Packit Service |
4b33e2 |
orig_name = name
|
|
Packit Service |
4b33e2 |
while fd is None:
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
fd = os.open(name, os.O_CREAT | os.O_EXCL, 0o666)
|
|
Packit Service |
4b33e2 |
except OSError as err:
|
|
Packit Service |
4b33e2 |
if err.errno == os.errno.EEXIST:
|
|
Packit Service |
4b33e2 |
name = "%s.%i" % (orig_name, count)
|
|
Packit Service |
4b33e2 |
count += 1
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
raise IOError(err.errno, err.strerror, err.filename)
|
|
Packit Service |
4b33e2 |
fobj = open(name, *args)
|
|
Packit Service |
4b33e2 |
if fd != fobj.fileno():
|
|
Packit Service |
4b33e2 |
os.close(fd)
|
|
Packit Service |
4b33e2 |
return fobj
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def get_default_url():
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Grab a default URL from bugzillarc [DEFAULT] url=X
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
from bugzilla.base import _open_bugzillarc
|
|
Packit Service |
4b33e2 |
cfg = _open_bugzillarc()
|
|
Packit Service |
4b33e2 |
if cfg:
|
|
Packit Service |
4b33e2 |
cfgurl = cfg.defaults().get("url", None)
|
|
Packit Service |
4b33e2 |
if cfgurl is not None:
|
|
Packit Service |
4b33e2 |
log.debug("bugzillarc: found cli url=%s", cfgurl)
|
|
Packit Service |
4b33e2 |
return cfgurl
|
|
Packit Service |
4b33e2 |
return DEFAULT_BZ
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def setup_logging(debug, verbose):
|
|
Packit Service |
4b33e2 |
handler = StreamHandler(sys.stderr)
|
|
Packit Service |
4b33e2 |
handler.setFormatter(Formatter(
|
|
Packit Service |
4b33e2 |
"[%(asctime)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s",
|
|
Packit Service |
4b33e2 |
"%H:%M:%S"))
|
|
Packit Service |
4b33e2 |
log.addHandler(handler)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if debug:
|
|
Packit Service |
4b33e2 |
log.setLevel(DEBUG)
|
|
Packit Service |
4b33e2 |
elif verbose:
|
|
Packit Service |
4b33e2 |
log.setLevel(INFO)
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
log.setLevel(WARN)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if _is_unittest_debug():
|
|
Packit Service |
4b33e2 |
log.setLevel(DEBUG)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
##################
|
|
Packit Service |
4b33e2 |
# Option parsing #
|
|
Packit Service |
4b33e2 |
##################
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_root_parser():
|
|
Packit Service |
4b33e2 |
epilog = 'Try "bugzilla COMMAND --help" for command-specific help.'
|
|
Packit Service |
4b33e2 |
p = argparse.ArgumentParser(epilog=epilog)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
default_url = get_default_url()
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# General bugzilla connection options
|
|
Packit Service |
4b33e2 |
p.add_argument('--bugzilla', default=default_url,
|
|
Packit Service |
4b33e2 |
help="bugzilla XMLRPC URI. default: %s" % default_url)
|
|
Packit Service |
4b33e2 |
p.add_argument("--nosslverify", dest="sslverify",
|
|
Packit Service |
4b33e2 |
action="store_false", default=True,
|
|
Packit Service |
4b33e2 |
help="Don't error on invalid bugzilla SSL certificate")
|
|
Packit Service |
4b33e2 |
p.add_argument('--cert',
|
|
Packit Service |
4b33e2 |
help="client side certificate file needed by the webserver")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('--login', action="store_true",
|
|
Packit Service |
4b33e2 |
help='Run interactive "login" before performing the '
|
|
Packit Service |
4b33e2 |
'specified command.')
|
|
Packit Service |
4b33e2 |
p.add_argument('--username', help="Log in with this username")
|
|
Packit Service |
4b33e2 |
p.add_argument('--password', help="Log in with this password")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('--ensure-logged-in', action="store_true",
|
|
Packit Service |
4b33e2 |
help="Raise an error if we aren't logged in to bugzilla. "
|
|
Packit Service |
4b33e2 |
"Consider using this if you are depending on "
|
|
Packit Service |
4b33e2 |
"cached credentials, to ensure that when they expire the "
|
|
Packit Service |
4b33e2 |
"tool errors, rather than subtly change output.")
|
|
Packit Service |
4b33e2 |
p.add_argument('--no-cache-credentials',
|
|
Packit Service |
4b33e2 |
action='store_false', default=True, dest='cache_credentials',
|
|
Packit Service |
4b33e2 |
help="Don't save any bugzilla cookies or tokens to disk, and "
|
|
Packit Service |
4b33e2 |
"don't use any pre-existing credentials.")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('--cookiefile', default=None,
|
|
Packit Service |
4b33e2 |
help="cookie file to use for bugzilla authentication")
|
|
Packit Service |
4b33e2 |
p.add_argument('--tokenfile', default=None,
|
|
Packit Service |
4b33e2 |
help="token file to use for bugzilla authentication")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('--verbose', action='store_true',
|
|
Packit Service |
4b33e2 |
help="give more info about what's going on")
|
|
Packit Service |
4b33e2 |
p.add_argument('--debug', action='store_true',
|
|
Packit Service |
4b33e2 |
help="output bunches of debugging info")
|
|
Packit Service |
4b33e2 |
p.add_argument('--version', action='version',
|
|
Packit Service |
4b33e2 |
version=bugzilla.__version__)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Allow user to specify BZClass to initialize. Kinda weird for the
|
|
Packit Service |
4b33e2 |
# CLI, I'd rather people file bugs about this so we can fix our detection.
|
|
Packit Service |
4b33e2 |
# So hide it from the help output but keep it for back compat
|
|
Packit Service |
4b33e2 |
p.add_argument('--bztype', default='auto', help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return p
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _parser_add_output_options(p):
|
|
Packit Service |
4b33e2 |
outg = p.add_argument_group("Output format options")
|
|
Packit Service |
4b33e2 |
outg.add_argument('--full', action='store_const', dest='output',
|
|
Packit Service |
4b33e2 |
const='full', default='normal',
|
|
Packit Service |
4b33e2 |
help="output detailed bug info")
|
|
Packit Service |
4b33e2 |
outg.add_argument('-i', '--ids', action='store_const', dest='output',
|
|
Packit Service |
4b33e2 |
const='ids', help="output only bug IDs")
|
|
Packit Service |
4b33e2 |
outg.add_argument('-e', '--extra', action='store_const',
|
|
Packit Service |
4b33e2 |
dest='output', const='extra',
|
|
Packit Service |
4b33e2 |
help="output additional bug information "
|
|
Packit Service |
4b33e2 |
"(keywords, Whiteboards, etc.)")
|
|
Packit Service |
4b33e2 |
outg.add_argument('--oneline', action='store_const', dest='output',
|
|
Packit Service |
4b33e2 |
const='oneline',
|
|
Packit Service |
4b33e2 |
help="one line summary of the bug (useful for scripts)")
|
|
Packit Service |
4b33e2 |
outg.add_argument('--raw', action='store_const', dest='output',
|
|
Packit Service |
4b33e2 |
const='raw', help="raw output of the bugzilla contents")
|
|
Packit Service |
4b33e2 |
outg.add_argument('--outputformat',
|
|
Packit Service |
4b33e2 |
help="Print output in the form given. "
|
|
Packit Service |
4b33e2 |
"You can use RPM-style tags that match bug "
|
|
Packit Service |
4b33e2 |
"fields, e.g.: '%%{id}: %%{summary}'. See the man page "
|
|
Packit Service |
4b33e2 |
"section 'Output options' for more details.")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _parser_add_bz_fields(rootp, command):
|
|
Packit Service |
4b33e2 |
cmd_new = (command == "new")
|
|
Packit Service |
4b33e2 |
cmd_query = (command == "query")
|
|
Packit Service |
4b33e2 |
cmd_modify = (command == "modify")
|
|
Packit Service |
4b33e2 |
if cmd_new:
|
|
Packit Service |
4b33e2 |
comment_help = "Set initial bug comment/description"
|
|
Packit Service |
4b33e2 |
elif cmd_query:
|
|
Packit Service |
4b33e2 |
comment_help = "Search all bug comments"
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
comment_help = "Add new bug comment"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p = rootp.add_argument_group("Standard bugzilla options")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('-p', '--product', help="Product name")
|
|
Packit Service |
4b33e2 |
p.add_argument('-v', '--version', help="Product version")
|
|
Packit Service |
4b33e2 |
p.add_argument('-c', '--component', help="Component name")
|
|
Packit Service |
4b33e2 |
p.add_argument('-t', '--summary', '--short_desc', help="Bug summary")
|
|
Packit Service |
4b33e2 |
p.add_argument('-l', '--comment', '--long_desc', help=comment_help)
|
|
Packit Service |
4b33e2 |
if not cmd_query:
|
|
Packit Service |
4b33e2 |
p.add_argument("--comment-tag", action="append",
|
|
Packit Service |
4b33e2 |
help="Comment tag for the new comment")
|
|
Packit Service |
4b33e2 |
p.add_argument("--sub-component", action="append",
|
|
Packit Service |
4b33e2 |
help="RHBZ sub component field")
|
|
Packit Service |
4b33e2 |
p.add_argument('-o', '--os', help="Operating system")
|
|
Packit Service |
4b33e2 |
p.add_argument('--arch', help="Arch this bug occurs on")
|
|
Packit Service |
4b33e2 |
p.add_argument('-x', '--severity', help="Bug severity")
|
|
Packit Service |
4b33e2 |
p.add_argument('-z', '--priority', help="Bug priority")
|
|
Packit Service |
4b33e2 |
p.add_argument('--alias', help='Bug alias (name)')
|
|
Packit Service |
4b33e2 |
p.add_argument('-s', '--status', '--bug_status',
|
|
Packit Service |
4b33e2 |
help='Bug status (NEW, ASSIGNED, etc.)')
|
|
Packit Service |
4b33e2 |
p.add_argument('-u', '--url', help="URL field")
|
|
Packit Service |
4b33e2 |
p.add_argument('-m', '--target_milestone', help="Target milestone")
|
|
Packit Service |
4b33e2 |
p.add_argument('--target_release', help="RHBZ Target release")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('--blocked', action="append",
|
|
Packit Service |
4b33e2 |
help="Bug IDs that this bug blocks")
|
|
Packit Service |
4b33e2 |
p.add_argument('--dependson', action="append",
|
|
Packit Service |
4b33e2 |
help="Bug IDs that this bug depends on")
|
|
Packit Service |
4b33e2 |
p.add_argument('--keywords', action="append",
|
|
Packit Service |
4b33e2 |
help="Bug keywords")
|
|
Packit Service |
4b33e2 |
p.add_argument('--groups', action="append",
|
|
Packit Service |
4b33e2 |
help="Which user groups can view this bug")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('--cc', action="append", help="CC list")
|
|
Packit Service |
4b33e2 |
p.add_argument('-a', '--assigned_to', '--assignee', help="Bug assignee")
|
|
Packit Service |
4b33e2 |
p.add_argument('-q', '--qa_contact', help='QA contact')
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not cmd_new:
|
|
Packit Service |
4b33e2 |
p.add_argument('-f', '--flag', action='append',
|
|
Packit Service |
4b33e2 |
help="Bug flags state. Ex:\n"
|
|
Packit Service |
4b33e2 |
" --flag needinfo?\n"
|
|
Packit Service |
4b33e2 |
" --flag dev_ack+ \n"
|
|
Packit Service |
4b33e2 |
" clear with --flag needinfoX")
|
|
Packit Service |
4b33e2 |
p.add_argument("--tags", action="append",
|
|
Packit Service |
4b33e2 |
help="Tags/Personal Tags field.")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument('-w', "--whiteboard", '--status_whiteboard',
|
|
Packit Service |
4b33e2 |
action="append", help='Whiteboard field')
|
|
Packit Service |
4b33e2 |
p.add_argument("--devel_whiteboard", action="append",
|
|
Packit Service |
4b33e2 |
help='RHBZ devel whiteboard field')
|
|
Packit Service |
4b33e2 |
p.add_argument("--internal_whiteboard", action="append",
|
|
Packit Service |
4b33e2 |
help='RHBZ internal whiteboard field')
|
|
Packit Service |
4b33e2 |
p.add_argument("--qa_whiteboard", action="append",
|
|
Packit Service |
4b33e2 |
help='RHBZ QA whiteboard field')
|
|
Packit Service |
4b33e2 |
p.add_argument('-F', '--fixed_in',
|
|
Packit Service |
4b33e2 |
help="RHBZ 'Fixed in version' field")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Put this at the end, so it sticks out more
|
|
Packit Service |
4b33e2 |
p.add_argument('--field',
|
|
Packit Service |
4b33e2 |
metavar="FIELD=VALUE", action="append", dest="fields",
|
|
Packit Service |
4b33e2 |
help="Manually specify a bugzilla XMLRPC field. FIELD is "
|
|
Packit Service |
4b33e2 |
"the raw name used by the bugzilla instance. For example if your "
|
|
Packit Service |
4b33e2 |
"bugzilla instance has a custom field cf_my_field, do:\n"
|
|
Packit Service |
4b33e2 |
" --field cf_my_field=VALUE")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Used by unit tests, not for end user consumption
|
|
Packit Service |
4b33e2 |
p.add_argument('--__test-return-result', action="store_true",
|
|
Packit Service |
4b33e2 |
dest="test_return_result", help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not cmd_modify:
|
|
Packit Service |
4b33e2 |
_parser_add_output_options(rootp)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_action_new_parser(subparsers):
|
|
Packit Service |
4b33e2 |
description = ("Create a new bug report. "
|
|
Packit Service |
4b33e2 |
"--product, --component, --version, --summary, and --comment "
|
|
Packit Service |
4b33e2 |
"must be specified. "
|
|
Packit Service |
4b33e2 |
"Options that take multiple values accept comma separated lists, "
|
|
Packit Service |
4b33e2 |
"including --cc, --blocks, --dependson, --groups, and --keywords.")
|
|
Packit Service |
4b33e2 |
p = subparsers.add_parser("new", description=description)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_parser_add_bz_fields(p, "new")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_action_query_parser(subparsers):
|
|
Packit Service |
4b33e2 |
description = ("List bug reports that match the given criteria. "
|
|
Packit Service |
4b33e2 |
"Certain options can accept a comma separated list to query multiple "
|
|
Packit Service |
4b33e2 |
"values, including --status, --component, --product, --version, --id.")
|
|
Packit Service |
4b33e2 |
epilog = ("Note: querying via explicit command line options will only "
|
|
Packit Service |
4b33e2 |
"get you so far. See the --from-url option for a way to use powerful "
|
|
Packit Service |
4b33e2 |
"Web UI queries from the command line.")
|
|
Packit Service |
4b33e2 |
p = subparsers.add_parser("query",
|
|
Packit Service |
4b33e2 |
description=description, epilog=epilog)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_parser_add_bz_fields(p, "query")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
g = p.add_argument_group("'query' specific options")
|
|
Packit Service |
4b33e2 |
g.add_argument('-b', '--id', '--bug_id',
|
|
Packit Service |
4b33e2 |
help="specify individual bugs by IDs, separated with commas")
|
|
Packit Service |
4b33e2 |
g.add_argument('-r', '--reporter',
|
|
Packit Service |
4b33e2 |
help="Email: search reporter email for given address")
|
|
Packit Service |
4b33e2 |
g.add_argument('--quicksearch',
|
|
Packit Service |
4b33e2 |
help="Search using bugzilla's quicksearch functionality.")
|
|
Packit Service |
4b33e2 |
g.add_argument('--savedsearch',
|
|
Packit Service |
4b33e2 |
help="Name of a bugzilla saved search. If you don't own this "
|
|
Packit Service |
4b33e2 |
"saved search, you must passed --savedsearch_sharer_id.")
|
|
Packit Service |
4b33e2 |
g.add_argument('--savedsearch-sharer-id',
|
|
Packit Service |
4b33e2 |
help="Owner ID of the --savedsearch. You can get this ID from "
|
|
Packit Service |
4b33e2 |
"the URL bugzilla generates when running the saved search "
|
|
Packit Service |
4b33e2 |
"from the web UI.")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Keep this at the end so it sticks out more
|
|
Packit Service |
4b33e2 |
g.add_argument('--from-url', metavar="WEB_QUERY_URL",
|
|
Packit Service |
4b33e2 |
help="Make a working query via bugzilla's 'Advanced search' web UI, "
|
|
Packit Service |
4b33e2 |
"grab the url from your browser (the string with query.cgi or "
|
|
Packit Service |
4b33e2 |
"buglist.cgi in it), and --from-url will run it via the "
|
|
Packit Service |
4b33e2 |
"bugzilla API. Don't forget to quote the string! "
|
|
Packit Service |
4b33e2 |
"This only works for Bugzilla 5 and Red Hat bugzilla")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Deprecated options
|
|
Packit Service |
4b33e2 |
p.add_argument('-E', '--emailtype', help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('--components_file', help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('-U', '--url_type',
|
|
Packit Service |
4b33e2 |
help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('-K', '--keywords_type',
|
|
Packit Service |
4b33e2 |
help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('-W', '--status_whiteboard_type',
|
|
Packit Service |
4b33e2 |
help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('-B', '--booleantype',
|
|
Packit Service |
4b33e2 |
help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('--boolean_query', action="append",
|
|
Packit Service |
4b33e2 |
help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
p.add_argument('--fixed_in_type', help=argparse.SUPPRESS)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_action_info_parser(subparsers):
|
|
Packit Service |
4b33e2 |
description = ("List products or component information about the "
|
|
Packit Service |
4b33e2 |
"bugzilla server.")
|
|
Packit Service |
4b33e2 |
p = subparsers.add_parser("info", description=description)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
x = p.add_mutually_exclusive_group(required=True)
|
|
Packit Service |
4b33e2 |
x.add_argument('-p', '--products', action='store_true',
|
|
Packit Service |
4b33e2 |
help='Get a list of products')
|
|
Packit Service |
4b33e2 |
x.add_argument('-c', '--components', metavar="PRODUCT",
|
|
Packit Service |
4b33e2 |
help='List the components in the given product')
|
|
Packit Service |
4b33e2 |
x.add_argument('-o', '--component_owners', metavar="PRODUCT",
|
|
Packit Service |
4b33e2 |
help='List components (and their owners)')
|
|
Packit Service |
4b33e2 |
x.add_argument('-v', '--versions', metavar="PRODUCT",
|
|
Packit Service |
4b33e2 |
help='List the versions for the given product')
|
|
Packit Service |
4b33e2 |
p.add_argument('--active-components', action="store_true",
|
|
Packit Service |
4b33e2 |
help='Only show active components. Combine with --components*')
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_action_modify_parser(subparsers):
|
|
Packit Service |
4b33e2 |
usage = ("bugzilla modify [options] BUGID [BUGID...]\n"
|
|
Packit Service |
4b33e2 |
"Fields that take multiple values have a special input format.\n"
|
|
Packit Service |
4b33e2 |
"Append: --cc=foo@example.com\n"
|
|
Packit Service |
4b33e2 |
"Overwrite: --cc==foo@example.com\n"
|
|
Packit Service |
4b33e2 |
"Remove: --cc=-foo@example.com\n"
|
|
Packit Service |
4b33e2 |
"Options that accept this format: --cc, --blocked, --dependson,\n"
|
|
Packit Service |
4b33e2 |
" --groups, --tags, whiteboard fields.")
|
|
Packit Service |
4b33e2 |
p = subparsers.add_parser("modify", usage=usage)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_parser_add_bz_fields(p, "modify")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
g = p.add_argument_group("'modify' specific options")
|
|
Packit Service |
4b33e2 |
g.add_argument("ids", nargs="+", help="Bug IDs to modify")
|
|
Packit Service |
4b33e2 |
g.add_argument('-k', '--close', metavar="RESOLUTION",
|
|
Packit Service |
4b33e2 |
help='Close with the given resolution (WONTFIX, NOTABUG, etc.)')
|
|
Packit Service |
4b33e2 |
g.add_argument('-d', '--dupeid', metavar="ORIGINAL",
|
|
Packit Service |
4b33e2 |
help='ID of original bug. Implies --close DUPLICATE')
|
|
Packit Service |
4b33e2 |
g.add_argument('--private', action='store_true', default=False,
|
|
Packit Service |
4b33e2 |
help='Mark new comment as private')
|
|
Packit Service |
4b33e2 |
g.add_argument('--reset-assignee', action="store_true",
|
|
Packit Service |
4b33e2 |
help='Reset assignee to component default')
|
|
Packit Service |
4b33e2 |
g.add_argument('--reset-qa-contact', action="store_true",
|
|
Packit Service |
4b33e2 |
help='Reset QA contact to component default')
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_action_attach_parser(subparsers):
|
|
Packit Service |
4b33e2 |
usage = """
|
|
Packit Service |
4b33e2 |
bugzilla attach --file=FILE --desc=DESC [--type=TYPE] BUGID [BUGID...]
|
|
Packit Service |
4b33e2 |
bugzilla attach --get=ATTACHID --getall=BUGID [...]
|
|
Packit Service |
4b33e2 |
bugzilla attach --type=TYPE BUGID [BUGID...]"""
|
|
Packit Service |
4b33e2 |
description = "Attach files or download attachments."
|
|
Packit Service |
4b33e2 |
p = subparsers.add_parser("attach", description=description, usage=usage)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
p.add_argument("ids", nargs="*", help="BUGID references")
|
|
Packit Service |
4b33e2 |
p.add_argument('-f', '--file', metavar="FILENAME",
|
|
Packit Service |
4b33e2 |
help='File to attach, or filename for data provided on stdin')
|
|
Packit Service |
4b33e2 |
p.add_argument('-d', '--description', '--summary',
|
|
Packit Service |
4b33e2 |
metavar="SUMMARY", dest='desc',
|
|
Packit Service |
4b33e2 |
help="A short summary of the file being attached")
|
|
Packit Service |
4b33e2 |
p.add_argument('-t', '--type', metavar="MIMETYPE",
|
|
Packit Service |
4b33e2 |
help="Mime-type for the file being attached")
|
|
Packit Service |
4b33e2 |
p.add_argument('-g', '--get', metavar="ATTACHID", action="append",
|
|
Packit Service |
4b33e2 |
default=[], help="Download the attachment with the given ID")
|
|
Packit Service |
4b33e2 |
p.add_argument("--getall", "--get-all", metavar="BUGID", action="append",
|
|
Packit Service |
4b33e2 |
default=[], help="Download all attachments on the given bug")
|
|
Packit Service |
4b33e2 |
p.add_argument('-l', '--comment', '--long_desc',
|
|
Packit Service |
4b33e2 |
help="Add comment with attachment")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _setup_action_login_parser(subparsers):
|
|
Packit Service |
4b33e2 |
usage = 'bugzilla login [username [password]]'
|
|
Packit Service |
4b33e2 |
description = "Log into bugzilla and save a login cookie or token."
|
|
Packit Service |
4b33e2 |
p = subparsers.add_parser("login", description=description, usage=usage)
|
|
Packit Service |
4b33e2 |
p.add_argument("pos_username", nargs="?", help="Optional username",
|
|
Packit Service |
4b33e2 |
metavar="username")
|
|
Packit Service |
4b33e2 |
p.add_argument("pos_password", nargs="?", help="Optional password",
|
|
Packit Service |
4b33e2 |
metavar="password")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def setup_parser():
|
|
Packit Service |
4b33e2 |
rootparser = _setup_root_parser()
|
|
Packit Service |
4b33e2 |
subparsers = rootparser.add_subparsers(dest="command")
|
|
Packit Service |
4b33e2 |
subparsers.required = True
|
|
Packit Service |
4b33e2 |
_setup_action_new_parser(subparsers)
|
|
Packit Service |
4b33e2 |
_setup_action_query_parser(subparsers)
|
|
Packit Service |
4b33e2 |
_setup_action_info_parser(subparsers)
|
|
Packit Service |
4b33e2 |
_setup_action_modify_parser(subparsers)
|
|
Packit Service |
4b33e2 |
_setup_action_attach_parser(subparsers)
|
|
Packit Service |
4b33e2 |
_setup_action_login_parser(subparsers)
|
|
Packit Service |
4b33e2 |
return rootparser
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
####################
|
|
Packit Service |
4b33e2 |
# Command routines #
|
|
Packit Service |
4b33e2 |
####################
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _merge_field_opts(query, opt, parser):
|
|
Packit Service |
4b33e2 |
# Add any custom fields if specified
|
|
Packit Service |
4b33e2 |
if opt.fields is None:
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for f in opt.fields:
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
f, v = f.split('=', 1)
|
|
Packit Service |
4b33e2 |
query[f] = v
|
|
Packit Service |
4b33e2 |
except Exception:
|
|
Packit Service |
4b33e2 |
parser.error("Invalid field argument provided: %s" % (f))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _do_query(bz, opt, parser):
|
|
Packit Service |
4b33e2 |
q = {}
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Parse preconstructed queries.
|
|
Packit Service |
4b33e2 |
u = opt.from_url
|
|
Packit Service |
4b33e2 |
if u:
|
|
Packit Service |
4b33e2 |
q = bz.url_to_query(u)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if opt.components_file:
|
|
Packit Service |
4b33e2 |
# Components slurped in from file (one component per line)
|
|
Packit Service |
4b33e2 |
# This can be made more robust
|
|
Packit Service |
4b33e2 |
clist = []
|
|
Packit Service |
4b33e2 |
f = open(opt.components_file, 'r')
|
|
Packit Service |
4b33e2 |
for line in f.readlines():
|
|
Packit Service |
4b33e2 |
line = line.rstrip("\n")
|
|
Packit Service |
4b33e2 |
clist.append(line)
|
|
Packit Service |
4b33e2 |
opt.component = clist
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if opt.status:
|
|
Packit Service |
4b33e2 |
val = opt.status
|
|
Packit Service |
4b33e2 |
stat = val
|
|
Packit Service |
4b33e2 |
if val == 'ALL':
|
|
Packit Service |
4b33e2 |
# leaving this out should return bugs of any status
|
|
Packit Service |
4b33e2 |
stat = None
|
|
Packit Service |
4b33e2 |
elif val == 'DEV':
|
|
Packit Service |
4b33e2 |
# Alias for all development bug statuses
|
|
Packit Service |
4b33e2 |
stat = ['NEW', 'ASSIGNED', 'NEEDINFO', 'ON_DEV',
|
|
Packit Service |
4b33e2 |
'MODIFIED', 'POST', 'REOPENED']
|
|
Packit Service |
4b33e2 |
elif val == 'QE':
|
|
Packit Service |
4b33e2 |
# Alias for all QE relevant bug statuses
|
|
Packit Service |
4b33e2 |
stat = ['ASSIGNED', 'ON_QA', 'FAILS_QA', 'PASSES_QA']
|
|
Packit Service |
4b33e2 |
elif val == 'EOL':
|
|
Packit Service |
4b33e2 |
# Alias for EndOfLife bug statuses
|
|
Packit Service |
4b33e2 |
stat = ['VERIFIED', 'RELEASE_PENDING', 'CLOSED']
|
|
Packit Service |
4b33e2 |
elif val == 'OPEN':
|
|
Packit Service |
4b33e2 |
# non-Closed statuses
|
|
Packit Service |
4b33e2 |
stat = ['NEW', 'ASSIGNED', 'MODIFIED', 'ON_DEV', 'ON_QA',
|
|
Packit Service |
4b33e2 |
'VERIFIED', 'RELEASE_PENDING', 'POST']
|
|
Packit Service |
4b33e2 |
opt.status = stat
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Convert all comma separated list parameters to actual lists,
|
|
Packit Service |
4b33e2 |
# which is what bugzilla wants
|
|
Packit Service |
4b33e2 |
# According to bugzilla docs, any parameter can be a list, but
|
|
Packit Service |
4b33e2 |
# let's only do this for options we explicitly mention can be
|
|
Packit Service |
4b33e2 |
# comma separated.
|
|
Packit Service |
4b33e2 |
for optname in ["severity", "id", "status", "component",
|
|
Packit Service |
4b33e2 |
"priority", "product", "version"]:
|
|
Packit Service |
4b33e2 |
val = getattr(opt, optname, None)
|
|
Packit Service |
4b33e2 |
if not isinstance(val, str):
|
|
Packit Service |
4b33e2 |
continue
|
|
Packit Service |
4b33e2 |
setattr(opt, optname, val.split(","))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
include_fields = None
|
|
Packit Service |
4b33e2 |
if opt.output == 'raw':
|
|
Packit Service |
4b33e2 |
# 'raw' always does a getbug() call anyways, so just ask for ID back
|
|
Packit Service |
4b33e2 |
include_fields = ['id']
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif opt.outputformat:
|
|
Packit Service |
4b33e2 |
include_fields = []
|
|
Packit Service |
4b33e2 |
for fieldname, rest in format_field_re.findall(opt.outputformat):
|
|
Packit Service |
4b33e2 |
if fieldname == "whiteboard" and rest:
|
|
Packit Service |
4b33e2 |
fieldname = rest + "_" + fieldname
|
|
Packit Service |
4b33e2 |
elif fieldname == "flag":
|
|
Packit Service |
4b33e2 |
fieldname = "flags"
|
|
Packit Service |
4b33e2 |
elif fieldname == "cve":
|
|
Packit Service |
4b33e2 |
fieldname = ["keywords", "blocks"]
|
|
Packit Service |
4b33e2 |
elif fieldname == "__unicode__":
|
|
Packit Service |
4b33e2 |
# Needs to be in sync with bug.__unicode__
|
|
Packit Service |
4b33e2 |
fieldname = ["id", "status", "assigned_to", "summary"]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
flist = isinstance(fieldname, list) and fieldname or [fieldname]
|
|
Packit Service |
4b33e2 |
for f in flist:
|
|
Packit Service |
4b33e2 |
if f not in include_fields:
|
|
Packit Service |
4b33e2 |
include_fields.append(f)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if include_fields is not None:
|
|
Packit Service |
4b33e2 |
include_fields.sort()
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
built_query = bz.build_query(
|
|
Packit Service |
4b33e2 |
product=opt.product or None,
|
|
Packit Service |
4b33e2 |
component=opt.component or None,
|
|
Packit Service |
4b33e2 |
sub_component=opt.sub_component or None,
|
|
Packit Service |
4b33e2 |
version=opt.version or None,
|
|
Packit Service |
4b33e2 |
reporter=opt.reporter or None,
|
|
Packit Service |
4b33e2 |
bug_id=opt.id or None,
|
|
Packit Service |
4b33e2 |
short_desc=opt.summary or None,
|
|
Packit Service |
4b33e2 |
long_desc=opt.comment or None,
|
|
Packit Service |
4b33e2 |
cc=opt.cc or None,
|
|
Packit Service |
4b33e2 |
assigned_to=opt.assigned_to or None,
|
|
Packit Service |
4b33e2 |
qa_contact=opt.qa_contact or None,
|
|
Packit Service |
4b33e2 |
status=opt.status or None,
|
|
Packit Service |
4b33e2 |
blocked=opt.blocked or None,
|
|
Packit Service |
4b33e2 |
dependson=opt.dependson or None,
|
|
Packit Service |
4b33e2 |
keywords=opt.keywords or None,
|
|
Packit Service |
4b33e2 |
keywords_type=opt.keywords_type or None,
|
|
Packit Service |
4b33e2 |
url=opt.url or None,
|
|
Packit Service |
4b33e2 |
url_type=opt.url_type or None,
|
|
Packit Service |
4b33e2 |
status_whiteboard=opt.whiteboard or None,
|
|
Packit Service |
4b33e2 |
status_whiteboard_type=opt.status_whiteboard_type or None,
|
|
Packit Service |
4b33e2 |
fixed_in=opt.fixed_in or None,
|
|
Packit Service |
4b33e2 |
fixed_in_type=opt.fixed_in_type or None,
|
|
Packit Service |
4b33e2 |
flag=opt.flag or None,
|
|
Packit Service |
4b33e2 |
alias=opt.alias or None,
|
|
Packit Service |
4b33e2 |
qa_whiteboard=opt.qa_whiteboard or None,
|
|
Packit Service |
4b33e2 |
devel_whiteboard=opt.devel_whiteboard or None,
|
|
Packit Service |
4b33e2 |
boolean_query=opt.boolean_query or None,
|
|
Packit Service |
4b33e2 |
bug_severity=opt.severity or None,
|
|
Packit Service |
4b33e2 |
priority=opt.priority or None,
|
|
Packit Service |
4b33e2 |
target_release=opt.target_release or None,
|
|
Packit Service |
4b33e2 |
target_milestone=opt.target_milestone or None,
|
|
Packit Service |
4b33e2 |
emailtype=opt.emailtype or None,
|
|
Packit Service |
4b33e2 |
booleantype=opt.booleantype or None,
|
|
Packit Service |
4b33e2 |
include_fields=include_fields,
|
|
Packit Service |
4b33e2 |
quicksearch=opt.quicksearch or None,
|
|
Packit Service |
4b33e2 |
savedsearch=opt.savedsearch or None,
|
|
Packit Service |
4b33e2 |
savedsearch_sharer_id=opt.savedsearch_sharer_id or None,
|
|
Packit Service |
4b33e2 |
tags=opt.tags or None)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_merge_field_opts(built_query, opt, parser)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
built_query.update(q)
|
|
Packit Service |
4b33e2 |
q = built_query
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not q:
|
|
Packit Service |
4b33e2 |
parser.error("'query' command requires additional arguments")
|
|
Packit Service |
4b33e2 |
if opt.test_return_result:
|
|
Packit Service |
4b33e2 |
return q
|
|
Packit Service |
4b33e2 |
return bz.query(q)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _do_info(bz, opt):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Handle the 'info' subcommand
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
# All these commands call getproducts internally, so do it up front
|
|
Packit Service |
4b33e2 |
# with minimal include_fields for speed
|
|
Packit Service |
4b33e2 |
def _filter_components(compdetails):
|
|
Packit Service |
4b33e2 |
ret = {}
|
|
Packit Service |
4b33e2 |
for k, v in compdetails.items():
|
|
Packit Service |
4b33e2 |
if v.get("is_active", True):
|
|
Packit Service |
4b33e2 |
ret[k] = v
|
|
Packit Service |
4b33e2 |
return ret
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
productname = (opt.components or opt.component_owners or opt.versions)
|
|
Packit Service |
4b33e2 |
include_fields = ["name", "id"]
|
|
Packit Service |
4b33e2 |
fastcomponents = (opt.components and not opt.active_components)
|
|
Packit Service |
4b33e2 |
if opt.versions:
|
|
Packit Service |
4b33e2 |
include_fields += ["versions"]
|
|
Packit Service |
4b33e2 |
if opt.component_owners:
|
|
Packit Service |
4b33e2 |
include_fields += [
|
|
Packit Service |
4b33e2 |
"components.default_assigned_to",
|
|
Packit Service |
4b33e2 |
"components.name",
|
|
Packit Service |
4b33e2 |
]
|
|
Packit Service |
4b33e2 |
if (opt.active_components and
|
|
Packit Service |
4b33e2 |
any(["components" in i for i in include_fields])):
|
|
Packit Service |
4b33e2 |
include_fields += ["components.is_active"]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
bz.refresh_products(names=productname and [productname] or None,
|
|
Packit Service |
4b33e2 |
include_fields=include_fields)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if opt.products:
|
|
Packit Service |
4b33e2 |
for name in sorted([p["name"] for p in bz.getproducts()]):
|
|
Packit Service |
4b33e2 |
print(name)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif fastcomponents:
|
|
Packit Service |
4b33e2 |
for name in sorted(bz.getcomponents(productname)):
|
|
Packit Service |
4b33e2 |
print(name)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif opt.components:
|
|
Packit Service |
4b33e2 |
details = bz.getcomponentsdetails(productname)
|
|
Packit Service |
4b33e2 |
for name in sorted(_filter_components(details)):
|
|
Packit Service |
4b33e2 |
print(name)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif opt.versions:
|
|
Packit Service |
4b33e2 |
proddict = bz.getproducts()[0]
|
|
Packit Service |
4b33e2 |
for v in proddict['versions']:
|
|
Packit Service |
4b33e2 |
print(to_encoding(v["name"]))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif opt.component_owners:
|
|
Packit Service |
4b33e2 |
details = bz.getcomponentsdetails(productname)
|
|
Packit Service |
4b33e2 |
for c in sorted(_filter_components(details)):
|
|
Packit Service |
4b33e2 |
print(to_encoding(u"%s: %s" % (c,
|
|
Packit Service |
4b33e2 |
details[c]['default_assigned_to'])))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _convert_to_outputformat(output):
|
|
Packit Service |
4b33e2 |
fmt = ""
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if output == "normal":
|
|
Packit Service |
4b33e2 |
fmt = "%{__unicode__}"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif output == "ids":
|
|
Packit Service |
4b33e2 |
fmt = "%{id}"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif output == 'full':
|
|
Packit Service |
4b33e2 |
fmt += "%{__unicode__}\n"
|
|
Packit Service |
4b33e2 |
fmt += "Component: %{component}\n"
|
|
Packit Service |
4b33e2 |
fmt += "CC: %{cc}\n"
|
|
Packit Service |
4b33e2 |
fmt += "Blocked: %{blocks}\n"
|
|
Packit Service |
4b33e2 |
fmt += "Depends: %{depends_on}\n"
|
|
Packit Service |
4b33e2 |
fmt += "%{comments}\n"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif output == 'extra':
|
|
Packit Service |
4b33e2 |
fmt += "%{__unicode__}\n"
|
|
Packit Service |
4b33e2 |
fmt += " +Keywords: %{keywords}\n"
|
|
Packit Service |
4b33e2 |
fmt += " +QA Whiteboard: %{qa_whiteboard}\n"
|
|
Packit Service |
4b33e2 |
fmt += " +Status Whiteboard: %{status_whiteboard}\n"
|
|
Packit Service |
4b33e2 |
fmt += " +Devel Whiteboard: %{devel_whiteboard}\n"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif output == 'oneline':
|
|
Packit Service |
4b33e2 |
fmt += "#%{bug_id} %{status} %{assigned_to} %{component}\t"
|
|
Packit Service |
4b33e2 |
fmt += "[%{target_milestone}] %{flags} %{cve}"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
raise RuntimeError("Unknown output type '%s'" % output)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return fmt
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _format_output(bz, opt, buglist):
|
|
Packit Service |
4b33e2 |
if opt.output == 'raw':
|
|
Packit Service |
4b33e2 |
buglist = bz.getbugs([b.bug_id for b in buglist])
|
|
Packit Service |
4b33e2 |
for b in buglist:
|
|
Packit Service |
4b33e2 |
print("Bugzilla %s: " % b.bug_id)
|
|
Packit Service |
4b33e2 |
for attrname in sorted(b.__dict__):
|
|
Packit Service |
4b33e2 |
print(to_encoding(u"ATTRIBUTE[%s]: %s" %
|
|
Packit Service |
4b33e2 |
(attrname, b.__dict__[attrname])))
|
|
Packit Service |
4b33e2 |
print("\n\n")
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def bug_field(matchobj):
|
|
Packit Service |
4b33e2 |
# whiteboard and flag allow doing
|
|
Packit Service |
4b33e2 |
# %{whiteboard:devel} and %{flag:needinfo}
|
|
Packit Service |
4b33e2 |
# That's what 'rest' matches
|
|
Packit Service |
4b33e2 |
(fieldname, rest) = matchobj.groups()
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if fieldname == "whiteboard" and rest:
|
|
Packit Service |
4b33e2 |
fieldname = rest + "_" + fieldname
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if fieldname == "flag" and rest:
|
|
Packit Service |
4b33e2 |
val = b.get_flag_status(rest)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif fieldname == "flags" or fieldname == "flags_requestee":
|
|
Packit Service |
4b33e2 |
tmpstr = []
|
|
Packit Service |
4b33e2 |
for f in getattr(b, "flags", []):
|
|
Packit Service |
4b33e2 |
requestee = f.get('requestee', "")
|
|
Packit Service |
4b33e2 |
if fieldname == "flags":
|
|
Packit Service |
4b33e2 |
requestee = ""
|
|
Packit Service |
4b33e2 |
if fieldname == "flags_requestee":
|
|
Packit Service |
4b33e2 |
if requestee == "":
|
|
Packit Service |
4b33e2 |
continue
|
|
Packit Service |
4b33e2 |
tmpstr.append("%s" % requestee)
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
tmpstr.append("%s%s%s" %
|
|
Packit Service |
4b33e2 |
(f['name'], f['status'], requestee))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
val = ",".join(tmpstr)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif fieldname == "cve":
|
|
Packit Service |
4b33e2 |
cves = []
|
|
Packit Service |
4b33e2 |
for key in getattr(b, "keywords", []):
|
|
Packit Service |
4b33e2 |
# grab CVE from keywords and blockers
|
|
Packit Service |
4b33e2 |
if key.find("Security") == -1:
|
|
Packit Service |
4b33e2 |
continue
|
|
Packit Service |
4b33e2 |
for bl in b.blocks:
|
|
Packit Service |
4b33e2 |
cvebug = bz.getbug(bl)
|
|
Packit Service |
4b33e2 |
for cb in cvebug.alias:
|
|
Packit Service |
4b33e2 |
if cb.find("CVE") == -1:
|
|
Packit Service |
4b33e2 |
continue
|
|
Packit Service |
4b33e2 |
if cb.strip() not in cves:
|
|
Packit Service |
4b33e2 |
cves.append(cb)
|
|
Packit Service |
4b33e2 |
val = ",".join(cves)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif fieldname == "comments":
|
|
Packit Service |
4b33e2 |
val = ""
|
|
Packit Service |
4b33e2 |
for c in getattr(b, "comments", []):
|
|
Packit Service |
4b33e2 |
val += ("\n* %s - %s:\n%s\n" % (c['time'],
|
|
Packit Service |
4b33e2 |
c.get("creator", c.get("author", "")), c['text']))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif fieldname == "external_bugs":
|
|
Packit Service |
4b33e2 |
val = ""
|
|
Packit Service |
4b33e2 |
for e in getattr(b, "external_bugs", []):
|
|
Packit Service |
4b33e2 |
url = e["type"]["full_url"].replace("%id%", e["ext_bz_bug_id"])
|
|
Packit Service |
4b33e2 |
if not val:
|
|
Packit Service |
4b33e2 |
val += "\n"
|
|
Packit Service |
4b33e2 |
val += "External bug: %s\n" % url
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif fieldname == "__unicode__":
|
|
Packit Service |
4b33e2 |
val = b.__unicode__()
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
val = getattr(b, fieldname, "")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
vallist = isinstance(val, list) and val or [val]
|
|
Packit Service |
4b33e2 |
val = ','.join([to_encoding(v) for v in vallist])
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return val
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for b in buglist:
|
|
Packit Service |
4b33e2 |
print(format_field_re.sub(bug_field, opt.outputformat))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _parse_triset(vallist, checkplus=True, checkminus=True, checkequal=True,
|
|
Packit Service |
4b33e2 |
splitcomma=False):
|
|
Packit Service |
4b33e2 |
add_val = []
|
|
Packit Service |
4b33e2 |
rm_val = []
|
|
Packit Service |
4b33e2 |
set_val = None
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def make_list(v):
|
|
Packit Service |
4b33e2 |
if not v:
|
|
Packit Service |
4b33e2 |
return []
|
|
Packit Service |
4b33e2 |
if splitcomma:
|
|
Packit Service |
4b33e2 |
return v.split(",")
|
|
Packit Service |
4b33e2 |
return [v]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for val in isinstance(vallist, list) and vallist or [vallist]:
|
|
Packit Service |
4b33e2 |
val = val or ""
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if val.startswith("+") and checkplus:
|
|
Packit Service |
4b33e2 |
add_val += make_list(val[1:])
|
|
Packit Service |
4b33e2 |
elif val.startswith("-") and checkminus:
|
|
Packit Service |
4b33e2 |
rm_val += make_list(val[1:])
|
|
Packit Service |
4b33e2 |
elif val.startswith("=") and checkequal:
|
|
Packit Service |
4b33e2 |
# Intentionally overwrite this
|
|
Packit Service |
4b33e2 |
set_val = make_list(val[1:])
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
add_val += make_list(val)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return add_val, rm_val, set_val
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _do_new(bz, opt, parser):
|
|
Packit Service |
4b33e2 |
# Parse options that accept comma separated list
|
|
Packit Service |
4b33e2 |
def parse_multi(val):
|
|
Packit Service |
4b33e2 |
return _parse_triset(val, checkplus=False, checkminus=False,
|
|
Packit Service |
4b33e2 |
checkequal=False, splitcomma=True)[0]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
ret = bz.build_createbug(
|
|
Packit Service |
4b33e2 |
blocks=parse_multi(opt.blocked) or None,
|
|
Packit Service |
4b33e2 |
cc=parse_multi(opt.cc) or None,
|
|
Packit Service |
4b33e2 |
component=opt.component or None,
|
|
Packit Service |
4b33e2 |
depends_on=parse_multi(opt.dependson) or None,
|
|
Packit Service |
4b33e2 |
description=opt.comment or None,
|
|
Packit Service |
4b33e2 |
groups=parse_multi(opt.groups) or None,
|
|
Packit Service |
4b33e2 |
keywords=parse_multi(opt.keywords) or None,
|
|
Packit Service |
4b33e2 |
op_sys=opt.os or None,
|
|
Packit Service |
4b33e2 |
platform=opt.arch or None,
|
|
Packit Service |
4b33e2 |
priority=opt.priority or None,
|
|
Packit Service |
4b33e2 |
product=opt.product or None,
|
|
Packit Service |
4b33e2 |
severity=opt.severity or None,
|
|
Packit Service |
4b33e2 |
summary=opt.summary or None,
|
|
Packit Service |
4b33e2 |
url=opt.url or None,
|
|
Packit Service |
4b33e2 |
version=opt.version or None,
|
|
Packit Service |
4b33e2 |
assigned_to=opt.assigned_to or None,
|
|
Packit Service |
4b33e2 |
qa_contact=opt.qa_contact or None,
|
|
Packit Service |
4b33e2 |
sub_component=opt.sub_component or None,
|
|
Packit Service |
4b33e2 |
alias=opt.alias or None,
|
|
Packit Service |
4b33e2 |
comment_tags=opt.comment_tag or None,
|
|
Packit Service |
4b33e2 |
)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_merge_field_opts(ret, opt, parser)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if opt.test_return_result:
|
|
Packit Service |
4b33e2 |
return ret
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
b = bz.createbug(ret)
|
|
Packit Service |
4b33e2 |
b.refresh()
|
|
Packit Service |
4b33e2 |
return [b]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _do_modify(bz, parser, opt):
|
|
Packit Service |
4b33e2 |
bugid_list = [bugid for a in opt.ids for bugid in a.split(',')]
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
add_wb, rm_wb, set_wb = _parse_triset(opt.whiteboard)
|
|
Packit Service |
4b33e2 |
add_devwb, rm_devwb, set_devwb = _parse_triset(opt.devel_whiteboard)
|
|
Packit Service |
4b33e2 |
add_intwb, rm_intwb, set_intwb = _parse_triset(opt.internal_whiteboard)
|
|
Packit Service |
4b33e2 |
add_qawb, rm_qawb, set_qawb = _parse_triset(opt.qa_whiteboard)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
add_blk, rm_blk, set_blk = _parse_triset(opt.blocked, splitcomma=True)
|
|
Packit Service |
4b33e2 |
add_deps, rm_deps, set_deps = _parse_triset(opt.dependson, splitcomma=True)
|
|
Packit Service |
4b33e2 |
add_key, rm_key, set_key = _parse_triset(opt.keywords)
|
|
Packit Service |
4b33e2 |
add_cc, rm_cc, ignore = _parse_triset(opt.cc,
|
|
Packit Service |
4b33e2 |
checkplus=False,
|
|
Packit Service |
4b33e2 |
checkequal=False)
|
|
Packit Service |
4b33e2 |
add_groups, rm_groups, ignore = _parse_triset(opt.groups,
|
|
Packit Service |
4b33e2 |
checkequal=False,
|
|
Packit Service |
4b33e2 |
splitcomma=True)
|
|
Packit Service |
4b33e2 |
add_tags, rm_tags, ignore = _parse_triset(opt.tags, checkequal=False)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
status = opt.status or None
|
|
Packit Service |
4b33e2 |
if opt.dupeid is not None:
|
|
Packit Service |
4b33e2 |
opt.close = "DUPLICATE"
|
|
Packit Service |
4b33e2 |
if opt.close:
|
|
Packit Service |
4b33e2 |
status = "CLOSED"
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
flags = []
|
|
Packit Service |
4b33e2 |
if opt.flag:
|
|
Packit Service |
4b33e2 |
# Convert "foo+" to tuple ("foo", "+")
|
|
Packit Service |
4b33e2 |
for f in opt.flag:
|
|
Packit Service |
4b33e2 |
flags.append({"name": f[:-1], "status": f[-1]})
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
update = bz.build_update(
|
|
Packit Service |
4b33e2 |
assigned_to=opt.assigned_to or None,
|
|
Packit Service |
4b33e2 |
comment=opt.comment or None,
|
|
Packit Service |
4b33e2 |
comment_private=opt.private or None,
|
|
Packit Service |
4b33e2 |
component=opt.component or None,
|
|
Packit Service |
4b33e2 |
product=opt.product or None,
|
|
Packit Service |
4b33e2 |
blocks_add=add_blk or None,
|
|
Packit Service |
4b33e2 |
blocks_remove=rm_blk or None,
|
|
Packit Service |
4b33e2 |
blocks_set=set_blk,
|
|
Packit Service |
4b33e2 |
url=opt.url or None,
|
|
Packit Service |
4b33e2 |
cc_add=add_cc or None,
|
|
Packit Service |
4b33e2 |
cc_remove=rm_cc or None,
|
|
Packit Service |
4b33e2 |
depends_on_add=add_deps or None,
|
|
Packit Service |
4b33e2 |
depends_on_remove=rm_deps or None,
|
|
Packit Service |
4b33e2 |
depends_on_set=set_deps,
|
|
Packit Service |
4b33e2 |
groups_add=add_groups or None,
|
|
Packit Service |
4b33e2 |
groups_remove=rm_groups or None,
|
|
Packit Service |
4b33e2 |
keywords_add=add_key or None,
|
|
Packit Service |
4b33e2 |
keywords_remove=rm_key or None,
|
|
Packit Service |
4b33e2 |
keywords_set=set_key,
|
|
Packit Service |
4b33e2 |
op_sys=opt.os or None,
|
|
Packit Service |
4b33e2 |
platform=opt.arch or None,
|
|
Packit Service |
4b33e2 |
priority=opt.priority or None,
|
|
Packit Service |
4b33e2 |
qa_contact=opt.qa_contact or None,
|
|
Packit Service |
4b33e2 |
severity=opt.severity or None,
|
|
Packit Service |
4b33e2 |
status=status,
|
|
Packit Service |
4b33e2 |
summary=opt.summary or None,
|
|
Packit Service |
4b33e2 |
version=opt.version or None,
|
|
Packit Service |
4b33e2 |
reset_assigned_to=opt.reset_assignee or None,
|
|
Packit Service |
4b33e2 |
reset_qa_contact=opt.reset_qa_contact or None,
|
|
Packit Service |
4b33e2 |
resolution=opt.close or None,
|
|
Packit Service |
4b33e2 |
target_release=opt.target_release or None,
|
|
Packit Service |
4b33e2 |
target_milestone=opt.target_milestone or None,
|
|
Packit Service |
4b33e2 |
dupe_of=opt.dupeid or None,
|
|
Packit Service |
4b33e2 |
fixed_in=opt.fixed_in or None,
|
|
Packit Service |
4b33e2 |
whiteboard=set_wb and set_wb[0] or None,
|
|
Packit Service |
4b33e2 |
devel_whiteboard=set_devwb and set_devwb[0] or None,
|
|
Packit Service |
4b33e2 |
internal_whiteboard=set_intwb and set_intwb[0] or None,
|
|
Packit Service |
4b33e2 |
qa_whiteboard=set_qawb and set_qawb[0] or None,
|
|
Packit Service |
4b33e2 |
sub_component=opt.sub_component or None,
|
|
Packit Service |
4b33e2 |
alias=opt.alias or None,
|
|
Packit Service |
4b33e2 |
flags=flags or None,
|
|
Packit Service |
4b33e2 |
comment_tags=opt.comment_tag or None,
|
|
Packit Service |
4b33e2 |
)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# We make this a little convoluted to facilitate unit testing
|
|
Packit Service |
4b33e2 |
wbmap = {
|
|
Packit Service |
4b33e2 |
"whiteboard": (add_wb, rm_wb),
|
|
Packit Service |
4b33e2 |
"internal_whiteboard": (add_intwb, rm_intwb),
|
|
Packit Service |
4b33e2 |
"qa_whiteboard": (add_qawb, rm_qawb),
|
|
Packit Service |
4b33e2 |
"devel_whiteboard": (add_devwb, rm_devwb),
|
|
Packit Service |
4b33e2 |
}
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for k, v in wbmap.copy().items():
|
|
Packit Service |
4b33e2 |
if not v[0] and not v[1]:
|
|
Packit Service |
4b33e2 |
del(wbmap[k])
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_merge_field_opts(update, opt, parser)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
log.debug("update bug dict=%s", update)
|
|
Packit Service |
4b33e2 |
log.debug("update whiteboard dict=%s", wbmap)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not any([update, wbmap, add_tags, rm_tags]):
|
|
Packit Service |
4b33e2 |
parser.error("'modify' command requires additional arguments")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if opt.test_return_result:
|
|
Packit Service |
4b33e2 |
return (update, wbmap, add_tags, rm_tags)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if add_tags or rm_tags:
|
|
Packit Service |
4b33e2 |
ret = bz.update_tags(bugid_list,
|
|
Packit Service |
4b33e2 |
tags_add=add_tags, tags_remove=rm_tags)
|
|
Packit Service |
4b33e2 |
log.debug("bz.update_tags returned=%s", ret)
|
|
Packit Service |
4b33e2 |
if update:
|
|
Packit Service |
4b33e2 |
ret = bz.update_bugs(bugid_list, update)
|
|
Packit Service |
4b33e2 |
log.debug("bz.update_bugs returned=%s", ret)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if not wbmap:
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Now for the things we can't blindly batch.
|
|
Packit Service |
4b33e2 |
# Being able to prepend/append to whiteboards, which are just
|
|
Packit Service |
4b33e2 |
# plain string values, is an old rhbz semantic that we try to maintain
|
|
Packit Service |
4b33e2 |
# here. This is a bit weird for traditional bugzilla XMLRPC
|
|
Packit Service |
4b33e2 |
log.debug("Adjusting whiteboard fields one by one")
|
|
Packit Service |
4b33e2 |
for bug in bz.getbugs(bugid_list):
|
|
Packit Service |
4b33e2 |
for wb, (add_list, rm_list) in wbmap.items():
|
|
Packit Service |
4b33e2 |
for tag in add_list:
|
|
Packit Service |
4b33e2 |
newval = getattr(bug, wb) or ""
|
|
Packit Service |
4b33e2 |
if newval:
|
|
Packit Service |
4b33e2 |
newval += " "
|
|
Packit Service |
4b33e2 |
newval += tag
|
|
Packit Service |
4b33e2 |
bz.update_bugs([bug.id],
|
|
Packit Service |
4b33e2 |
bz.build_update(**{wb: newval}))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for tag in rm_list:
|
|
Packit Service |
4b33e2 |
newval = (getattr(bug, wb) or "").split()
|
|
Packit Service |
4b33e2 |
for t in newval[:]:
|
|
Packit Service |
4b33e2 |
if t == tag:
|
|
Packit Service |
4b33e2 |
newval.remove(t)
|
|
Packit Service |
4b33e2 |
bz.update_bugs([bug.id],
|
|
Packit Service |
4b33e2 |
bz.build_update(**{wb: " ".join(newval)}))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _do_get_attach(bz, opt):
|
|
Packit Service |
4b33e2 |
for bug in bz.getbugs(opt.getall):
|
|
Packit Service |
4b33e2 |
opt.get += bug.get_attachment_ids()
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
for attid in set(opt.get):
|
|
Packit Service |
4b33e2 |
att = bz.openattachment(attid)
|
|
Packit Service |
4b33e2 |
outfile = open_without_clobber(att.name, "wb")
|
|
Packit Service |
4b33e2 |
data = att.read(4096)
|
|
Packit Service |
4b33e2 |
while data:
|
|
Packit Service |
4b33e2 |
outfile.write(data)
|
|
Packit Service |
4b33e2 |
data = att.read(4096)
|
|
Packit Service |
4b33e2 |
print("Wrote %s" % outfile.name)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
return
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _do_set_attach(bz, opt, parser):
|
|
Packit Service |
4b33e2 |
if not opt.ids:
|
|
Packit Service |
4b33e2 |
parser.error("Bug ID must be specified for setting attachments")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if sys.stdin.isatty():
|
|
Packit Service |
4b33e2 |
if not opt.file:
|
|
Packit Service |
4b33e2 |
parser.error("--file must be specified")
|
|
Packit Service |
4b33e2 |
fileobj = open(opt.file, "rb")
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
# piped input on stdin
|
|
Packit Service |
4b33e2 |
if not opt.desc:
|
|
Packit Service |
4b33e2 |
parser.error("--description must be specified if passing "
|
|
Packit Service |
4b33e2 |
"file on stdin")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
fileobj = tempfile.NamedTemporaryFile(prefix="bugzilla-attach.")
|
|
Packit Service |
4b33e2 |
data = sys.stdin.read(4096)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
while data:
|
|
Packit Service |
4b33e2 |
fileobj.write(data.encode(locale.getpreferredencoding()))
|
|
Packit Service |
4b33e2 |
data = sys.stdin.read(4096)
|
|
Packit Service |
4b33e2 |
fileobj.seek(0)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
kwargs = {}
|
|
Packit Service |
4b33e2 |
if opt.file:
|
|
Packit Service |
4b33e2 |
kwargs["filename"] = os.path.basename(opt.file)
|
|
Packit Service |
4b33e2 |
if opt.type:
|
|
Packit Service |
4b33e2 |
kwargs["contenttype"] = opt.type
|
|
Packit Service |
4b33e2 |
if opt.type in ["text/x-patch"]:
|
|
Packit Service |
4b33e2 |
kwargs["ispatch"] = True
|
|
Packit Service |
4b33e2 |
if opt.comment:
|
|
Packit Service |
4b33e2 |
kwargs["comment"] = opt.comment
|
|
Packit Service |
4b33e2 |
desc = opt.desc or os.path.basename(fileobj.name)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Upload attachments
|
|
Packit Service |
4b33e2 |
for bugid in opt.ids:
|
|
Packit Service |
4b33e2 |
attid = bz.attachfile(bugid, fileobj, desc, **kwargs)
|
|
Packit Service |
4b33e2 |
print("Created attachment %i on bug %s" % (attid, bugid))
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
#################
|
|
Packit Service |
4b33e2 |
# Main handling #
|
|
Packit Service |
4b33e2 |
#################
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _make_bz_instance(opt):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Build the Bugzilla instance we will use
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
if opt.bztype != 'auto':
|
|
Packit Service |
4b33e2 |
log.info("Explicit --bztype is no longer supported, ignoring")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
cookiefile = None
|
|
Packit Service |
4b33e2 |
tokenfile = None
|
|
Packit Service |
4b33e2 |
if opt.cache_credentials:
|
|
Packit Service |
4b33e2 |
cookiefile = opt.cookiefile or -1
|
|
Packit Service |
4b33e2 |
tokenfile = opt.tokenfile or -1
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
bz = bugzilla.Bugzilla(
|
|
Packit Service |
4b33e2 |
url=opt.bugzilla,
|
|
Packit Service |
4b33e2 |
cookiefile=cookiefile,
|
|
Packit Service |
4b33e2 |
tokenfile=tokenfile,
|
|
Packit Service |
4b33e2 |
sslverify=opt.sslverify,
|
|
Packit Service |
4b33e2 |
cert=opt.cert)
|
|
Packit Service |
4b33e2 |
return bz
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _handle_login(opt, action, bz):
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
Handle all login related bits
|
|
Packit Service |
4b33e2 |
"""
|
|
Packit Service |
4b33e2 |
is_login_command = (action == 'login')
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
do_interactive_login = (is_login_command or
|
|
Packit Service |
4b33e2 |
opt.login or opt.username or opt.password)
|
|
Packit Service |
4b33e2 |
username = getattr(opt, "pos_username", None) or opt.username
|
|
Packit Service |
4b33e2 |
password = getattr(opt, "pos_password", None) or opt.password
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
if do_interactive_login:
|
|
Packit Service |
4b33e2 |
if bz.url:
|
|
Packit Service |
4b33e2 |
print("Logging into %s" % urlparse(bz.url)[1])
|
|
Packit Service |
4b33e2 |
bz.interactive_login(username, password)
|
|
Packit Service |
4b33e2 |
except bugzilla.BugzillaError as e:
|
|
Packit Service |
4b33e2 |
print(str(e))
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if opt.ensure_logged_in and not bz.logged_in:
|
|
Packit Service |
4b33e2 |
print("--ensure-logged-in passed but you aren't logged in to %s" %
|
|
Packit Service |
4b33e2 |
bz.url)
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if is_login_command:
|
|
Packit Service |
4b33e2 |
msg = "Login successful."
|
|
Packit Service |
4b33e2 |
if bz.cookiefile or bz.tokenfile:
|
|
Packit Service |
4b33e2 |
msg = "Login successful, token cache updated."
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
print(msg)
|
|
Packit Service |
4b33e2 |
sys.exit(0)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def _main(unittest_bz_instance):
|
|
Packit Service |
4b33e2 |
parser = setup_parser()
|
|
Packit Service |
4b33e2 |
opt = parser.parse_args()
|
|
Packit Service |
4b33e2 |
action = opt.command
|
|
Packit Service |
4b33e2 |
setup_logging(opt.debug, opt.verbose)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
log.debug("Launched with command line: %s", " ".join(sys.argv))
|
|
Packit Service |
4b33e2 |
log.debug("Bugzilla module: %s", bugzilla)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Connect to bugzilla
|
|
Packit Service |
4b33e2 |
log.info('Connecting to %s', opt.bugzilla)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if unittest_bz_instance:
|
|
Packit Service |
4b33e2 |
bz = unittest_bz_instance
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
bz = _make_bz_instance(opt)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# Handle login options
|
|
Packit Service |
4b33e2 |
_handle_login(opt, action, bz)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
###########################
|
|
Packit Service |
4b33e2 |
# Run the actual commands #
|
|
Packit Service |
4b33e2 |
###########################
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
if hasattr(opt, "outputformat"):
|
|
Packit Service |
4b33e2 |
if not opt.outputformat and opt.output not in ['raw', None]:
|
|
Packit Service |
4b33e2 |
opt.outputformat = _convert_to_outputformat(opt.output)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
buglist = []
|
|
Packit Service |
4b33e2 |
if action == 'info':
|
|
Packit Service |
4b33e2 |
if not (opt.products or
|
|
Packit Service |
4b33e2 |
opt.components or
|
|
Packit Service |
4b33e2 |
opt.component_owners or
|
|
Packit Service |
4b33e2 |
opt.versions):
|
|
Packit Service |
4b33e2 |
parser.error("'info' command requires additional arguments")
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
_do_info(bz, opt)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif action == 'query':
|
|
Packit Service |
4b33e2 |
buglist = _do_query(bz, opt, parser)
|
|
Packit Service |
4b33e2 |
if opt.test_return_result:
|
|
Packit Service |
4b33e2 |
return buglist
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif action == 'new':
|
|
Packit Service |
4b33e2 |
buglist = _do_new(bz, opt, parser)
|
|
Packit Service |
4b33e2 |
if opt.test_return_result:
|
|
Packit Service |
4b33e2 |
return buglist
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif action == 'attach':
|
|
Packit Service |
4b33e2 |
if opt.get or opt.getall:
|
|
Packit Service |
4b33e2 |
if opt.ids:
|
|
Packit Service |
4b33e2 |
parser.error("Bug IDs '%s' not used for "
|
|
Packit Service |
4b33e2 |
"getting attachments" % opt.ids)
|
|
Packit Service |
4b33e2 |
_do_get_attach(bz, opt)
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
_do_set_attach(bz, opt, parser)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
elif action == 'modify':
|
|
Packit Service |
4b33e2 |
modout = _do_modify(bz, parser, opt)
|
|
Packit Service |
4b33e2 |
if opt.test_return_result:
|
|
Packit Service |
4b33e2 |
return modout
|
|
Packit Service |
4b33e2 |
else:
|
|
Packit Service |
4b33e2 |
raise RuntimeError("Unexpected action '%s'" % action)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
# If we're doing new/query/modify, output our results
|
|
Packit Service |
4b33e2 |
if action in ['new', 'query']:
|
|
Packit Service |
4b33e2 |
_format_output(bz, opt, buglist)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def main(unittest_bz_instance=None):
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
return _main(unittest_bz_instance)
|
|
Packit Service |
4b33e2 |
except (Exception, KeyboardInterrupt):
|
|
Packit Service |
4b33e2 |
log.debug("", exc_info=True)
|
|
Packit Service |
4b33e2 |
raise
|
|
Packit Service |
4b33e2 |
except (Fault, bugzilla.BugzillaError) as e:
|
|
Packit Service |
4b33e2 |
print("\nServer error: %s" % str(e))
|
|
Packit Service |
4b33e2 |
sys.exit(3)
|
|
Packit Service |
4b33e2 |
except requests.exceptions.SSLError as e:
|
|
Packit Service |
4b33e2 |
# Give SSL recommendations
|
|
Packit Service |
4b33e2 |
print("SSL error: %s" % e)
|
|
Packit Service |
4b33e2 |
print("\nIf you trust the remote server, you can work "
|
|
Packit Service |
4b33e2 |
"around this error with:\n"
|
|
Packit Service |
4b33e2 |
" bugzilla --nosslverify ...")
|
|
Packit Service |
4b33e2 |
sys.exit(4)
|
|
Packit Service |
4b33e2 |
except (socket.error,
|
|
Packit Service |
4b33e2 |
requests.exceptions.HTTPError,
|
|
Packit Service |
4b33e2 |
requests.exceptions.ConnectionError,
|
|
Packit Service |
4b33e2 |
ProtocolError) as e:
|
|
Packit Service |
4b33e2 |
print("\nConnection lost/failed: %s" % str(e))
|
|
Packit Service |
4b33e2 |
sys.exit(2)
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
|
|
Packit Service |
4b33e2 |
def cli():
|
|
Packit Service |
4b33e2 |
try:
|
|
Packit Service |
4b33e2 |
main()
|
|
Packit Service |
4b33e2 |
except KeyboardInterrupt:
|
|
Packit Service |
4b33e2 |
log.debug("", exc_info=True)
|
|
Packit Service |
4b33e2 |
print("\nExited at user request.")
|
|
Packit Service |
4b33e2 |
sys.exit(1)
|