Skip to content

Commit d4d288c

Browse files
committed
bugzilla: Remove custom boolean query format entirely
Warn if the old boolean properties appear to be used, but pass them on to bugzilla and let it fail
1 parent b98162f commit d4d288c

5 files changed

Lines changed: 83 additions & 225 deletions

File tree

bin/bugzilla

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -302,27 +302,26 @@ def _setup_action_query_parser(subparsers):
302302

303303
# Boolean Charts
304304
bgrp = p.add_argument_group("Boolean options")
305-
bgrp.add_argument('-B', '--booleantype', default="substring",
306-
help="specify searching option for booleans, ie. substring, "
307-
"notsubstring, exact, ... [Default: substring]")
305+
bgrp.add_argument('-B', '--booleantype',
306+
help=argparse.SUPPRESS)
308307
bgrp.add_argument('--boolean_query', action="append",
309308
help=argparse.SUPPRESS)
310-
bgrp.add_argument('--blocked', action="append",
309+
bgrp.add_argument('--blocked',
311310
help="Search for bugs that block this bug ID")
312-
bgrp.add_argument('--dependson', action="append",
311+
bgrp.add_argument('--dependson',
313312
help="Search for bugs that depend on this bug ID")
314-
bgrp.add_argument('--flag', action='append',
313+
bgrp.add_argument('--flag',
315314
help="Search for bugs that have certain "
316315
"flag states present. Ex --flags=dev_ack+")
317-
bgrp.add_argument('--qa_whiteboard', action="append",
316+
bgrp.add_argument('--qa_whiteboard',
318317
help="search for bugs that have certain QA "
319318
"Whiteboard text present")
320-
bgrp.add_argument('--devel_whiteboard', action="append",
319+
bgrp.add_argument('--devel_whiteboard',
321320
help="search for bugs that have certain "
322321
"Devel Whiteboard text present")
323-
bgrp.add_argument('--alias', action="append",
322+
bgrp.add_argument('--alias',
324323
help="search for bugs that have the provided alias")
325-
bgrp.add_argument('--fixed_in', action="append",
324+
bgrp.add_argument('--fixed_in',
326325
help="search Status Whiteboard field for specified words")
327326

328327
_parser_add_output_options(p)
@@ -609,7 +608,7 @@ def _do_query(bz, opt, parser):
609608
priority=getattr(opt, "priority", None),
610609
target_milestone=getattr(opt, "target_milestone", None),
611610
emailtype=opt.emailtype or None,
612-
booleantype=opt.booleantype,
611+
booleantype=opt.booleantype or None,
613612
include_fields=include_fields,
614613
quicksearch=getattr(opt, "quicksearch", None),
615614
savedsearch=getattr(opt, "savedsearch", None),

bugzilla/base.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,24 +1050,11 @@ def build_query(self,
10501050
10511051
Then pass the output to Bugzilla.query()
10521052
"""
1053-
if boolean_query:
1053+
if boolean_query or booleantype:
10541054
raise RuntimeError("boolean_query format is no longer supported. "
10551055
"If you need complicated URL queries, look into "
10561056
"query --from-url/url_to_query().")
10571057

1058-
for key, val in [
1059-
('fixed_in', fixed_in),
1060-
('blocked', blocked),
1061-
('dependson', dependson),
1062-
('flag', flag),
1063-
('qa_whiteboard', qa_whiteboard),
1064-
('devel_whiteboard', devel_whiteboard),
1065-
('alias', alias),
1066-
]:
1067-
if val is not None:
1068-
raise RuntimeError("'%s' search not supported by this "
1069-
"bugzilla's XMLRPC interface" % key)
1070-
10711058
query = {
10721059
"product": self._listify(product),
10731060
"component": self._listify(component),
@@ -1089,6 +1076,18 @@ def build_query(self,
10891076
"quicksearch": quicksearch,
10901077
"savedsearch": savedsearch,
10911078
"sharer_id": savedsearch_sharer_id,
1079+
1080+
# RH extensions that we have to maintain here for back compat,
1081+
# but all future custom fields should be specified via
1082+
# cli --field option, or via extending the query dict() manually.
1083+
# No more supporting custom fields in this API
1084+
"cf_fixed_in": fixed_in,
1085+
"blocked": blocked,
1086+
"dependson": dependson,
1087+
"flagtypes.name": flag,
1088+
"cf_qa_whiteboard": qa_whiteboard,
1089+
"cf_devel_whiteboard": devel_whiteboard,
1090+
"alias": alias,
10921091
"sub_components": self._listify(sub_component),
10931092
}
10941093

bugzilla/rhbugzilla.py

Lines changed: 32 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -304,142 +304,42 @@ def post_translation(self, query, bug):
304304
values += vallist
305305
bug['sub_component'] = " ".join(values)
306306

307-
def build_external_tracker_boolean_query(
308-
self, ext_type_description=None, ext_type_url=None,
309-
ext_bz_bug_id=None, ext_status=None):
310-
"""
311-
Helper method to build a boolean query to find bugs that contain an
312-
external tracker.
313-
314-
All parameters that are None will be ignored when building the query.
315-
316-
ext_type_description: The external tracker description as used by
317-
Bugzilla.
318-
ext_type_url: The external tracker url as used by Bugzilla.
319-
ext_bz_bug_id: The external bug id (ie: the bug number in the
320-
external tracker).
321-
ext_status: The status of the external bug.
322-
"""
323-
parts = []
307+
def build_external_tracker_boolean_query(self, *args, **kwargs):
308+
ignore1 = args
309+
ignore2 = kwargs
310+
raise RuntimeError("Building external boolean queries is "
311+
"no longer supported. Please build a URL query "
312+
"via the bugzilla web UI and pass it to 'query --from-url' "
313+
"or url_to_query()")
324314

325-
if ext_type_description is not None:
326-
parts.append(
327-
'external_bugzilla.description-equals-{0:s}'.format(
328-
ext_type_description))
329-
330-
if ext_type_url is not None:
331-
parts.append(
332-
'external_bugzilla.url-equals-{0:s}'.format(ext_type_url))
333-
334-
if ext_bz_bug_id is not None:
335-
id_str = str(ext_bz_bug_id)
336-
parts.append(
337-
'ext_bz_bug_map.ext_bz_bug_id-equals-{0:s}'.format(id_str))
338-
339-
if ext_status is not None:
340-
parts.append(
341-
'ext_bz_bug_map.ext_status-equals-{0:s}'.format(ext_status))
342-
343-
return ' & '.join(parts)
344315

345316
def build_query(self, **kwargs):
346-
query = {}
347-
348-
def _add_key(paramname, keyname, listify=False):
349-
val = kwargs.pop(paramname, None)
350-
if val is None:
351-
return
352-
if listify:
353-
val = self._listify(val)
354-
query[keyname] = val
355-
356-
def bool_smart_split(boolval):
357-
# This parses the CLI command syntax, but we only want to
358-
# do space splitting if the space is actually part of a
359-
# boolean operator
360-
boolchars = ["|", "&", "!"]
361-
add = ""
362-
retlist = []
363-
364-
for word in boolval.split(" "):
365-
if word.strip() in boolchars:
366-
word = word.strip()
367-
if add:
368-
retlist.append(add)
369-
add = ""
370-
retlist.append(word)
371-
else:
372-
if add:
373-
add += " "
374-
add += word
375-
376-
if add:
377-
retlist.append(add)
378-
return retlist
379-
380-
def add_boolean(kwkey, key, bool_id):
381-
value = self._listify(kwargs.pop(kwkey, None))
382-
if value is None:
383-
return bool_id
384-
385-
query["query_format"] = "advanced"
386-
for boolval in value:
387-
and_count = 0
388-
or_count = 0
389-
390-
def make_bool_str(prefix):
391-
# pylint: disable=cell-var-from-loop
392-
return "%s%i-%i-%i" % (prefix, bool_id,
393-
and_count, or_count)
394-
395-
for par in bool_smart_split(boolval):
396-
field = None
397-
fval = par
398-
typ = kwargs.get("booleantype", "substring")
399-
400-
if par == "&":
401-
and_count += 1
402-
elif par == "|":
403-
or_count += 1
404-
elif par == "!":
405-
query['negate%i' % bool_id] = 1
406-
elif not key:
407-
if par.find('-') == -1:
408-
raise RuntimeError('Malformed boolean query: %s' %
409-
value)
410-
411-
args = par.split('-', 2)
412-
field = args[0]
413-
typ = args[1]
414-
fval = None
415-
if len(args) == 3:
416-
fval = args[2]
417-
else:
418-
field = key
419-
420-
query[make_bool_str("field")] = field
421-
if fval:
422-
query[make_bool_str("value")] = fval
423-
query[make_bool_str("type")] = typ
424-
425-
bool_id += 1
426-
return bool_id
427-
428-
# Use fancy email specification for RH bugzilla. It isn't
429-
# strictly required, but is more powerful, and it is what
430-
# bin/bugzilla historically generated. This requires
431-
# query_format='advanced' which is an RHBZ only XMLRPC extension
432-
433-
chart_id = 0
434-
chart_id = add_boolean("fixed_in", "cf_fixed_in", chart_id)
435-
chart_id = add_boolean("blocked", "blocked", chart_id)
436-
chart_id = add_boolean("dependson", "dependson", chart_id)
437-
chart_id = add_boolean("flag", "flagtypes.name", chart_id)
438-
chart_id = add_boolean("qa_whiteboard", "cf_qa_whiteboard", chart_id)
439-
chart_id = add_boolean("devel_whiteboard", "cf_devel_whiteboard",
440-
chart_id)
441-
chart_id = add_boolean("alias", "alias", chart_id)
317+
# We previously accepted a text format to approximate boolean
318+
# queries, and only for RHBugzilla. Upstream bz has --from-url
319+
# support now, so point people to that instead so we don't have
320+
# to document and maintain this logic anymore
321+
def _warn_bool(kwkey):
322+
vallist = self._listify(kwargs.get(kwkey, None))
323+
for value in vallist or []:
324+
for s in value.split(" "):
325+
if s not in ["|", "&", "!"]:
326+
continue
327+
log.warn("%s value '%s' appears to use the now "
328+
"unsupported boolean formatting, your query may "
329+
"be incorrect. If you need complicated URL queries, "
330+
"look into bugzilla --from-url/url_to_query().",
331+
kwkey, value)
332+
return
333+
334+
_warn_bool("fixed_in")
335+
_warn_bool("blocked")
336+
_warn_bool("dependson")
337+
_warn_bool("flag")
338+
_warn_bool("qa_whiteboard")
339+
_warn_bool("devel_whiteboard")
340+
_warn_bool("alias")
442341

342+
query = {}
443343
query.update(self._process_include_fields(None, None,
444344
kwargs.pop('extra_fields', None)))
445345

tests/query.py

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,6 @@ def testKeywords(self):
9191
"--url http://example.com --url_type foo",
9292
self._keywords_out)
9393

94-
def testBooleans(self):
95-
self.clicomm("--blocked 123456 "
96-
"--devel_whiteboard 'foobar | baz' "
97-
"--qa_whiteboard '! baz foo' "
98-
"--flag 'needinfo & devel_ack'",
99-
self._booleans_out)
100-
10194
def testBooleanChart(self):
10295
self.clicomm("--boolean_query 'keywords-substring-Partner & "
10396
"keywords-notsubstring-OtherQA' "
@@ -151,7 +144,6 @@ def testSubComponent(self):
151144
_components_file_out = {'component': ["foo", "bar", "baz"]}
152145
_keywords_out = {'keywords': 'Triaged', 'bug_file_loc':
153146
'http://example.com', 'bug_file_loc_type': 'foo'}
154-
_booleans_out = None
155147
_longdesc_out = {'longdesc': 'foobar', 'longdesc_type': 'allwordssubstr',
156148
'query_format': 'advanced'}
157149
_quicksearch_out = {'quicksearch': 'foo bar baz'}
@@ -224,18 +216,7 @@ class RHBZTest(BZ4Test):
224216
_output_format_out = BZ34Test.output_format_out.copy()
225217
_output_format_out["include_fields"] = ['product', 'summary',
226218
'platform', 'status', 'id', 'blocks', 'whiteboard']
227-
_booleans_out = {'value2-0-0': 'baz foo', 'value0-0-0': '123456',
228-
'type3-0-1': 'substring', 'value1-1-0': 'devel_ack', 'type0-0-0':
229-
'substring', 'type2-0-0': 'substring', 'field3-0-1':
230-
'cf_devel_whiteboard', 'field3-0-0': 'cf_devel_whiteboard',
231-
'field1-0-0': 'flagtypes.name', 'value3-0-0': 'foobar',
232-
'value3-0-1': 'baz', 'value1-0-0': 'needinfo', 'type1-1-0':
233-
'substring', 'type1-0-0': 'substring', 'field1-1-0':
234-
'flagtypes.name', 'negate2': 1, 'field2-0-0':
235-
'cf_qa_whiteboard', 'type3-0-0': 'substring', 'field0-0-0':
236-
'blocked', 'include_fields': BZ4Test._default_includes,
237-
'query_format': 'advanced'}
238-
219+
_booleans_out = {}
239220

240221
def testTranslation(self):
241222
def translate(_in):
@@ -270,6 +251,28 @@ def testInvalidBoolean(self):
270251
self.assertRaises(RuntimeError, self.bz.build_query,
271252
boolean_query="foobar")
272253

254+
def testBooleans(self):
255+
out = {
256+
'blocked': '123456',
257+
'cf_devel_whiteboard': 'foobar | baz',
258+
'cf_qa_whiteboard': '! baz foo',
259+
'flagtypes.name': 'needinfo & devel_ack',
260+
'include_fields': ['assigned_to', 'id', 'status', 'summary']
261+
}
262+
263+
import bugzilla
264+
import logging
265+
log = logging.getLogger(bugzilla.__name__)
266+
handlers = log.handlers
267+
try:
268+
log.handlers = []
269+
self.clicomm("--blocked 123456 "
270+
"--devel_whiteboard 'foobar | baz' "
271+
"--qa_whiteboard '! baz foo' "
272+
"--flag 'needinfo & devel_ack'", out)
273+
finally:
274+
log.handlers = handlers
275+
273276

274277
class TestURLToQuery(BZ34Test):
275278
def _check(self, url, query):

0 commit comments

Comments
 (0)