Skip to content

Commit 292ebeb

Browse files
committed
cli: Add query --extrafield, --includefield, --excludefield
Allow users to pass these extra/include/exclude values straight through to the remote server. For most of the output format options these don't add anything, but for --json and --raw which do a getbug() call, these can be useful for tweaking the output, like reducing the total returned data, or requesting the server return a non-standard field. Signed-off-by: Cole Robinson <[email protected]>
1 parent 3f81d2d commit 292ebeb

7 files changed

Lines changed: 341 additions & 1 deletion

File tree

bugzilla/_cli.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,21 @@ def _parser_add_output_options(p):
163163
help="one line summary of the bug (useful for scripts)")
164164
outg.add_argument('--json', action='store_const', dest='output',
165165
const='json', help="output contents in json format")
166+
outg.add_argument("--includefield", action="append",
167+
help="Pass the field name to bugzilla include_fields list. "
168+
"Only the fields passed to include_fields are returned "
169+
"by the bugzilla server. "
170+
"This can be specified multiple times.")
171+
outg.add_argument("--extrafield", action="append",
172+
help="Pass the field name to bugzilla extra_fields list. "
173+
"When used with --json this can be used to request "
174+
"bugzilla to return values for non-default fields. "
175+
"This can be specified multiple times.")
176+
outg.add_argument("--excludefield", action="append",
177+
help="Pass the field name to bugzilla exclude_fields list. "
178+
"When used with --json this can be used to request "
179+
"bugzilla to not return values for a field. "
180+
"This can be specified multiple times.")
166181
outg.add_argument('--raw', action='store_const', dest='output',
167182
const='raw', help="raw output of the bugzilla contents. This "
168183
"format is unstable and difficult to parse. Use --json instead.")
@@ -750,7 +765,21 @@ def _bug_field_repl_cb(bz, b, matchobj):
750765

751766
def _format_output(bz, opt, buglist):
752767
if opt.output in ['raw', 'json']:
753-
buglist = bz.getbugs([b.bug_id for b in buglist])
768+
include_fields = None
769+
exclude_fields = None
770+
extra_fields = None
771+
772+
if opt.includefield:
773+
include_fields = opt.includefield
774+
if opt.excludefield:
775+
exclude_fields = opt.excludefield
776+
if opt.extrafield:
777+
extra_fields = opt.extrafield
778+
779+
buglist = bz.getbugs([b.bug_id for b in buglist],
780+
include_fields=include_fields,
781+
exclude_fields=exclude_fields,
782+
extra_fields=extra_fields)
754783
if opt.output == 'json':
755784
_format_output_json(buglist)
756785
if opt.output == 'raw':

man/bugzilla.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,27 @@ one line summary of the bug (useful for scripts)
272272

273273
output bug contents in JSON format
274274

275+
- ``--includefield``
276+
277+
Pass the field name to bugzilla include_fields list.
278+
Only the fields passed to include_fields are returned
279+
by the bugzilla server.
280+
This can be specified multiple times.
281+
282+
- ``--extrafield``
283+
284+
Pass the field name to bugzilla extra_fields list.
285+
When used with --json this can be used to request
286+
bugzilla to return values for non-default fields.
287+
This can be specified multiple times.
288+
289+
- ``--excludefield``
290+
291+
Pass the field name to bugzilla exclude_fields list.
292+
When used with --json this can be used to request
293+
bugzilla to not return values for a field.
294+
This can be specified multiple times.
295+
275296
- ``--raw``
276297

277298
raw output of the bugzilla contents. This format is unstable and
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
{
2+
"bugs": [
3+
{
4+
"actual_time": 0.0,
5+
"alias": [],
6+
"assigned_to": "[email protected]",
7+
"assigned_to_detail": {
8+
"email": "[email protected]",
9+
"id": 206817,
10+
"name": "[email protected]",
11+
"real_name": "LVM and device-mapper development team"
12+
},
13+
"blocks": [
14+
123456
15+
],
16+
"cc": [
17+
18+
19+
],
20+
"cc_detail": [
21+
{
22+
"email": "[email protected]",
23+
"id": 123456,
24+
"name": "[email protected]",
25+
"real_name": "Example user"
26+
},
27+
{
28+
"email": "[email protected]",
29+
"id": 123457,
30+
"name": "[email protected]",
31+
"real_name": "Example2 user"
32+
}
33+
],
34+
"cf_build_id": "",
35+
"cf_conditional_nak": [],
36+
"cf_cust_facing": "---",
37+
"cf_doc_type": "Bug Fix",
38+
"cf_environment": "",
39+
"cf_last_closed": "2016-03-03T22:15:07",
40+
"cf_partner": [],
41+
"cf_pgm_internal": "",
42+
"cf_pm_score": "0",
43+
"cf_qe_conditional_nak": [],
44+
"cf_release_notes": "",
45+
"cf_target_upstream_version": "",
46+
"cf_verified": [],
47+
"classification": "Red Hat",
48+
"comments": [
49+
{
50+
"bug_id": 1165434,
51+
"count": 0,
52+
"creation_time": "2014-11-19T00:26:50",
53+
"creator": "[email protected]",
54+
"creator_id": 276776,
55+
"id": 7685441,
56+
"is_private": false,
57+
"tags": [],
58+
"text": "Description of problem:\nVersion-Release number of selected component (if applicable):\nkernel-2.6.18-308.el5\ndevice-mapper-multipath-0.4.7-48.el5\ndevice-mapper-1.02.67-2.el5\ndevice-mapper-1.02.67-2.el5\ndevice-mapper-event-1.02.67-2.el5\n",
59+
"time": "2014-11-19T00:26:50"
60+
},
61+
{
62+
"bug_id": 1165434,
63+
"count": 1,
64+
"creation_time": "2014-11-19T00:47:57",
65+
"creator": "[email protected]",
66+
"creator_id": 276776,
67+
"id": 7685467,
68+
"is_private": false,
69+
"tags": [],
70+
"text": "We can see that there is a dmeventd task that has sent data over a socket and is waiting for the peer to respond:\n\ncrash> bt\nany interaction with the filesystem until it has issued the suspend command to convert the mirror device to a linear device.",
71+
"time": "2014-11-19T00:47:57"
72+
},
73+
{
74+
"bug_id": 1165434,
75+
"count": 2,
76+
"creation_time": "2014-11-19T01:53:53",
77+
"creator": "[email protected]",
78+
"creator_id": 156796,
79+
"id": 7685595,
80+
"is_private": false,
81+
"tags": [],
82+
"text": "Test text",
83+
"time": "2014-11-19T01:53:53"
84+
}
85+
],
86+
"depends_on": [
87+
112233
88+
],
89+
"devel_whiteboard": "somedeveltag,someothertag",
90+
"docs_contact": "",
91+
"estimated_time": 0.0,
92+
"external_bugs": [
93+
{
94+
"bug_id": 989253,
95+
"ext_bz_bug_id": "703421",
96+
"ext_bz_id": 3,
97+
"ext_description": "None",
98+
"ext_priority": "None",
99+
"ext_status": "None",
100+
"id": 115528,
101+
"type": {
102+
"can_get": true,
103+
"can_send": false,
104+
"description": "GNOME Bugzilla",
105+
"full_url": "https://bugzilla.gnome.org/show_bug.cgi?id=%id%",
106+
"id": 3,
107+
"must_send": false,
108+
"send_once": false,
109+
"type": "Bugzilla",
110+
"url": "https://bugzilla.gnome.org"
111+
}
112+
},
113+
{
114+
"bug_id": 989253,
115+
"ext_bz_bug_id": "1203576",
116+
"ext_bz_id": 29,
117+
"ext_description": "None",
118+
"ext_priority": "None",
119+
"ext_status": "None",
120+
"id": 115527,
121+
"type": {
122+
"can_get": false,
123+
"can_send": false,
124+
"description": "Launchpad",
125+
"full_url": "https://bugs.launchpad.net/bugs/%id%",
126+
"id": 29,
127+
"must_send": false,
128+
"send_once": false,
129+
"type": "None",
130+
"url": "https://bugs.launchpad.net/bugs"
131+
}
132+
}
133+
],
134+
"fixed_in": "",
135+
"flags": [
136+
{
137+
"creation_date": "2019-11-15T21:57:21Z",
138+
"id": 4302313,
139+
"is_active": 1,
140+
"modification_date": "2019-11-15T21:57:21Z",
141+
"name": "qe_test_coverage",
142+
"setter": "[email protected]",
143+
"status": "?",
144+
"type_id": 318
145+
},
146+
{
147+
"creation_date": "2018-12-25T16:47:43Z",
148+
"id": 3883137,
149+
"is_active": 1,
150+
"modification_date": "2018-12-25T16:47:43Z",
151+
"name": "release",
152+
"setter": "[email protected]",
153+
"status": "?",
154+
"type_id": 1197
155+
},
156+
{
157+
"creation_date": "2018-12-25T16:47:38Z",
158+
"id": 3883134,
159+
"is_active": 1,
160+
"modification_date": "2018-12-25T16:47:38Z",
161+
"name": "pm_ack",
162+
"setter": "[email protected]",
163+
"status": "?",
164+
"type_id": 11
165+
},
166+
{
167+
"creation_date": "2018-12-25T16:47:38Z",
168+
"id": 3883135,
169+
"is_active": 1,
170+
"modification_date": "2018-12-25T16:47:38Z",
171+
"name": "devel_ack",
172+
"setter": "[email protected]",
173+
"status": "?",
174+
"type_id": 10
175+
},
176+
{
177+
"creation_date": "2018-12-25T16:47:38Z",
178+
"id": 3883136,
179+
"is_active": 1,
180+
"modification_date": "2019-04-28T02:07:03Z",
181+
"name": "qa_ack",
182+
"setter": "[email protected]",
183+
"status": "+",
184+
"type_id": 9
185+
},
186+
{
187+
"creation_date": "2019-03-29T06:50:01Z",
188+
"id": 3999302,
189+
"is_active": 1,
190+
"modification_date": "2019-03-29T06:50:01Z",
191+
"name": "needinfo",
192+
"requestee": "[email protected]",
193+
"setter": "[email protected]",
194+
"status": "?",
195+
"type_id": 1164
196+
}
197+
],
198+
"groups": [
199+
"somegroup"
200+
],
201+
"id": 1165434,
202+
"internal_whiteboard": "someinternal TAG",
203+
"is_cc_accessible": true,
204+
"is_confirmed": true,
205+
"is_creator_accessible": true,
206+
"is_open": false,
207+
"keywords": [
208+
"key1",
209+
"keyword2",
210+
"Security"
211+
],
212+
"last_change_time": "2018-12-09T19:12:12",
213+
"op_sys": "Linux",
214+
"platform": "All",
215+
"priority": "medium",
216+
"product": "Red Hat Enterprise Linux 5",
217+
"qa_contact": "[email protected]",
218+
"qa_contact_detail": {
219+
"email": "[email protected]",
220+
"id": 164197,
221+
"name": "[email protected]",
222+
"real_name": "Cluster QE"
223+
},
224+
"qa_whiteboard": "foo bar baz",
225+
"remaining_time": 0.0,
226+
"resolution": "WONTFIX",
227+
"see_also": [],
228+
"severity": "medium",
229+
"status": "CLOSED",
230+
"sub_component": "dmeventd (RHEL5)",
231+
"sub_components": {
232+
"lvm2": [
233+
"dmeventd (RHEL5)"
234+
]
235+
},
236+
"summary": "LVM mirrored root can deadlock dmeventd if a mirror leg is lost",
237+
"tags": [],
238+
"target_milestone": "rc",
239+
"target_release": [
240+
"---"
241+
],
242+
"url": "",
243+
"version": "5.8",
244+
"versions": [
245+
"5.8"
246+
],
247+
"whiteboard": "genericwhiteboard"
248+
}
249+
]
250+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
([1165434],
2+
[],
3+
{'exclude_fields': ['excludeme'],
4+
'extra_fields': ['extrame1',
5+
'extrame2',
6+
'comments',
7+
'description',
8+
'external_bugs',
9+
'flags',
10+
'sub_components',
11+
'tags'],
12+
'include_fields': ['foo', 'bar', 'id'],
13+
'permissive': 1})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{'id': ['1165434'], 'include_fields': ['id']}

tests/test_cli_query.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,18 @@ def test_query(run_cli):
132132
tests.utils.diff_compare(tests.utils.sanitize_json(out),
133133
"data/clioutput/test_query8.txt")
134134
assert json.loads(out)
135+
136+
# Test --json output
137+
cmd = ("bugzilla query --json --id 1165434 "
138+
"--includefield foo --includefield bar "
139+
"--excludefield excludeme "
140+
"--extrafield extrame1 --extrafield extrame2 ")
141+
fakebz = tests.mockbackend.make_bz(rhbz=True,
142+
bug_search_args="data/mockargs/test_query9.txt",
143+
bug_search_return={"bugs": [{"id": 1165434}]},
144+
bug_get_args="data/mockargs/test_getbug_query9.txt",
145+
bug_get_return="data/mockreturn/test_getbug_rhel.txt")
146+
out = run_cli(cmd, fakebz)
147+
tests.utils.diff_compare(tests.utils.sanitize_json(out),
148+
"data/clioutput/test_query9.txt")
149+
assert json.loads(out)

tests/test_ro_functional.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,17 @@ def testQueryFixedIn(run_cli, backends):
229229
assert "#629311 CLOSED" in out
230230

231231

232+
def testQueryExtrafieldPool(run_cli, backends):
233+
# rhbz has an agile 'pool' extension but doesn't return the field
234+
# by default. Check that '-extrafield pool' returns it for --json output
235+
bz = _open_bz(REDHAT_URL, **backends)
236+
237+
out1 = run_cli("bugzilla query --id 1717616 --json", bz)
238+
out2 = run_cli("bugzilla query --id 1717616 --json --extrafield pool", bz)
239+
assert "current_sprint_id" not in out1
240+
assert "current_sprint_id" in out2
241+
242+
232243
def testComponentsDetails(backends):
233244
"""
234245
Fresh call to getcomponentsdetails should properly refresh

0 commit comments

Comments
 (0)