Add builds subcommand
Allow a user to search builds according to filtering criteria. Change-Id: Ibde3730d00f623df7ff6716a034af88de89f4835
This commit is contained in:
parent
da8e50862e
commit
dcef301d79
@ -55,6 +55,15 @@ Example::
|
||||
|
||||
zuul-client autohold-list --tenant openstack
|
||||
|
||||
Builds
|
||||
^^^^^^
|
||||
.. program-output:: zuul-client builds --help
|
||||
|
||||
Examples::
|
||||
|
||||
zuul-client --use-conf sfio builds --tenant mytenant --result NODE_FAILURE
|
||||
zuul-client --use-conf opendev builds --tenant zuul --project zuul/zuul-client --limit 10
|
||||
|
||||
Dequeue
|
||||
^^^^^^^
|
||||
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add the **builds** subcommand to zuul-client, allowing users to search through
|
||||
builds using filters.
|
@ -468,3 +468,32 @@ class TestCmd(BaseTestCase):
|
||||
self.assertEqual(secret, f.read())
|
||||
os.unlink(infile.name)
|
||||
os.unlink(outfile.name)
|
||||
|
||||
def test_builds(self):
|
||||
"""Test builds subcommand"""
|
||||
ZC = ZuulClient()
|
||||
with self.assertRaisesRegex(Exception,
|
||||
'--voting and --non-voting are '
|
||||
'mutually exclusive'):
|
||||
exit_code = ZC._main(
|
||||
['--zuul-url', 'https://fake.zuul',
|
||||
'builds', '--tenant', 'tenant1', '--voting', '--non-voting'])
|
||||
with patch('requests.Session') as mock_sesh:
|
||||
session = mock_sesh.return_value
|
||||
session.post = MagicMock(
|
||||
return_value=FakeRequestResponse(200, {}))
|
||||
exit_code = ZC._main(
|
||||
['--zuul-url', 'https://fake.zuul', 'builds',
|
||||
'--pipeline', 'gate',
|
||||
'--tenant', 'tenant1',
|
||||
'--change', '1234', '--job', 'job1', '--held'])
|
||||
session.get.assert_called_with(
|
||||
'https://fake.zuul/api/tenant/tenant1/builds',
|
||||
params={'pipeline': 'gate',
|
||||
'change': '1234',
|
||||
'job_name': 'job1',
|
||||
'held': True,
|
||||
'skip': 0,
|
||||
'limit': 50}
|
||||
)
|
||||
self.assertEqual(0, exit_code)
|
||||
|
@ -226,3 +226,24 @@ class ZuulRESTClient(object):
|
||||
req = self.session.get(url)
|
||||
self._check_request_status(req)
|
||||
return req.text
|
||||
|
||||
def builds(self, tenant, **kwargs):
|
||||
# check kwargs
|
||||
allowed_args = {'project', 'pipeline', 'change', 'branch', 'patchset',
|
||||
'ref', 'newrev', 'uuid', 'job_name', 'voting',
|
||||
'node_name', 'result', 'final', 'held',
|
||||
'limit', 'skip'}
|
||||
if not set(kwargs.keys()).issubset(allowed_args):
|
||||
raise Exception(
|
||||
'Allowed arguments are %s' % ', '.join(allowed_args))
|
||||
params = kwargs
|
||||
if 'limit' not in params:
|
||||
params['limit'] = 50
|
||||
if 'skip' not in params:
|
||||
params['skip'] = 0
|
||||
url = urllib.parse.urljoin(
|
||||
self.base_url,
|
||||
'tenant/%s/builds' % tenant)
|
||||
req = self.session.get(url, params=kwargs)
|
||||
self._check_request_status(req)
|
||||
return req.json()
|
||||
|
@ -87,6 +87,8 @@ class ZuulClient():
|
||||
self.add_dequeue_subparser(subparsers)
|
||||
self.add_promote_subparser(subparsers)
|
||||
self.add_encrypt_subparser(subparsers)
|
||||
self.add_builds_list_subparser(subparsers)
|
||||
|
||||
return subparsers
|
||||
|
||||
def parseArguments(self, args=None):
|
||||
@ -530,6 +532,113 @@ class ZuulClient():
|
||||
os.unlink(pubkey_file.name)
|
||||
return return_code
|
||||
|
||||
def add_builds_list_subparser(self, subparsers):
|
||||
cmd_builds = subparsers.add_parser(
|
||||
'builds', help='List builds matching search criteria')
|
||||
cmd_builds.add_argument(
|
||||
'--tenant', help='tenant name', required=True)
|
||||
cmd_builds.add_argument(
|
||||
'--project', help='project name')
|
||||
cmd_builds.add_argument(
|
||||
'--pipeline', help='pipeline name')
|
||||
cmd_builds.add_argument(
|
||||
'--change', help='change reference')
|
||||
cmd_builds.add_argument(
|
||||
'--branch', help='branch name')
|
||||
cmd_builds.add_argument(
|
||||
'--patchset', help='patchset number')
|
||||
cmd_builds.add_argument(
|
||||
'--ref', help='ref name')
|
||||
cmd_builds.add_argument(
|
||||
'--newrev', help='the applied revision')
|
||||
cmd_builds.add_argument(
|
||||
'--job', help='job name')
|
||||
cmd_builds.add_argument(
|
||||
'--voting', help='show voting builds only',
|
||||
action='store_true', default=False)
|
||||
cmd_builds.add_argument(
|
||||
'--non-voting', help='show non-voting builds only',
|
||||
action='store_true', default=False)
|
||||
cmd_builds.add_argument(
|
||||
'--node', help='node name')
|
||||
cmd_builds.add_argument(
|
||||
'--result', help='build result')
|
||||
cmd_builds.add_argument(
|
||||
'--final', help='show final builds only',
|
||||
action='store_true', default=False)
|
||||
cmd_builds.add_argument(
|
||||
'--held', help='show held builds only',
|
||||
action='store_true', default=False)
|
||||
cmd_builds.add_argument(
|
||||
'--limit', help='maximum amount of results to return',
|
||||
default=50, type=int)
|
||||
cmd_builds.add_argument(
|
||||
'--skip', help='how many results to skip',
|
||||
default=0, type=int)
|
||||
cmd_builds.set_defaults(func=self.builds)
|
||||
|
||||
def builds(self):
|
||||
if self.args.voting and self.args.non_voting:
|
||||
raise Exception('--voting and --non-voting are mutually exclusive')
|
||||
self.log.info('Showing the last {} matches.'.format(self.args.limit))
|
||||
filters = {'limit': self.args.limit,
|
||||
'skip': self.args.skip}
|
||||
if self.args.project:
|
||||
filters['project'] = self.args.project
|
||||
if self.args.pipeline:
|
||||
filters['pipeline'] = self.args.pipeline
|
||||
if self.args.change:
|
||||
filters['change'] = self.args.change
|
||||
if self.args.branch:
|
||||
filters['branch'] = self.args.branch
|
||||
if self.args.patchset:
|
||||
filters['patchset'] = self.args.patchset
|
||||
if self.args.ref:
|
||||
filters['ref'] = self.args.ref
|
||||
if self.args.newrev:
|
||||
filters['newrev'] = self.args.newrev
|
||||
if self.args.job:
|
||||
filters['job_name'] = self.args.job
|
||||
if self.args.voting:
|
||||
filters['voting'] = True
|
||||
if self.args.non_voting:
|
||||
filters['voting'] = False
|
||||
if self.args.node:
|
||||
filters['node'] = self.args.node
|
||||
if self.args.result:
|
||||
filters['result'] = self.args.result
|
||||
if self.args.final:
|
||||
filters['final'] = True
|
||||
if self.args.held:
|
||||
filters['held'] = True
|
||||
client = self.get_client()
|
||||
builds = client.builds(tenant=self.args.tenant, **filters)
|
||||
table = prettytable.PrettyTable(
|
||||
field_names=[
|
||||
'ID', 'Job', 'Project', 'Branch', 'Pipeline', 'Change or Ref',
|
||||
'Duration (s)', 'Start time', 'Result', 'Event ID'
|
||||
]
|
||||
)
|
||||
for build in builds:
|
||||
if build['change'] and build['patchset']:
|
||||
change = str(build['change']) + ',' + str(build['patchset'])
|
||||
else:
|
||||
change = build['ref']
|
||||
table.add_row([
|
||||
build.get('uuid') or 'N/A',
|
||||
build['job_name'],
|
||||
build['project'],
|
||||
build['branch'],
|
||||
build['pipeline'],
|
||||
change,
|
||||
build['duration'],
|
||||
build['start_time'],
|
||||
build['result'],
|
||||
build.get('event_id') or 'N/A'
|
||||
])
|
||||
print(table)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
ZuulClient().main()
|
||||
|
Loading…
Reference in New Issue
Block a user