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
|
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
|
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())
|
self.assertEqual(secret, f.read())
|
||||||
os.unlink(infile.name)
|
os.unlink(infile.name)
|
||||||
os.unlink(outfile.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)
|
req = self.session.get(url)
|
||||||
self._check_request_status(req)
|
self._check_request_status(req)
|
||||||
return req.text
|
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_dequeue_subparser(subparsers)
|
||||||
self.add_promote_subparser(subparsers)
|
self.add_promote_subparser(subparsers)
|
||||||
self.add_encrypt_subparser(subparsers)
|
self.add_encrypt_subparser(subparsers)
|
||||||
|
self.add_builds_list_subparser(subparsers)
|
||||||
|
|
||||||
return subparsers
|
return subparsers
|
||||||
|
|
||||||
def parseArguments(self, args=None):
|
def parseArguments(self, args=None):
|
||||||
@ -530,6 +532,113 @@ class ZuulClient():
|
|||||||
os.unlink(pubkey_file.name)
|
os.unlink(pubkey_file.name)
|
||||||
return return_code
|
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():
|
def main():
|
||||||
ZuulClient().main()
|
ZuulClient().main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user