[ui] Add count of messages to commit configdocs CLI

The list of validations returned from commit configdocs
can be long and sometimes lose sight of errors. This change adds
a summary count of the severity level of messages returned at the
bottom of the output so as to clue the user into what might be closer
to the top.

Change-Id: I2a8921b22977b8ceab0afb1341b195c12dc49c67
This commit is contained in:
Bryan Strassner 2018-04-13 18:02:27 -05:00 committed by Scott Hussey
parent 89840303b1
commit a51e30f0a2
3 changed files with 94 additions and 11 deletions

View File

@ -61,12 +61,21 @@ def cli_format_status_handler(response, is_error=False):
resp_j = response.json()
resp = formatted.format(resp_j.get('message', 'Not specified'),
resp_j.get('reason', 'Not specified'))
# lvl_counts must have a matching number of values as the
# _LEVEL_KEYS below + 1 for sentinel.
lvl_counts = [0, 0, 0, 0]
if resp_j.get('details'):
mlist = resp_j['details'].get('messageList', [])
for message in sorted(mlist,
key=lambda m: _lvl_key(
m.get('level'),
m.get('error', False))):
# Decorate messages with level number and sortkey
for message in mlist:
message['lnum'], message['sortkey'] = _lvl_key(
message.get('level'),
message.get('error', False)
)
# Sort and formulate the messages
for message in sorted(mlist, key=lambda m: m['sortkey']):
lnum = message['lnum']
lvl_counts[lnum] = lvl_counts[lnum] + 1
if message.get('kind') == 'ValidationMessage':
resp = resp + _format_validation_message(message)
else:
@ -76,6 +85,11 @@ def cli_format_status_handler(response, is_error=False):
_INDENT,
message['source']
)
# Append a count summary
resp = resp + ("\n\n#### Errors: {},"
" Warnings: {},"
" Infos: {},"
" Other: {} ####".format(*lvl_counts))
return resp
else:
return ''
@ -92,14 +106,18 @@ _LEVEL_KEYS = {
1: ['warn', 'warning'],
2: ['info', 'debug'],
}
_SENTINEL_LEVEL = "999"
_SENTINEL_SORT_KEY = "3none"
_SENTINEL_LEVEL = 3
def _lvl_key(level_name, error):
"""Generate a level key value
"""Generate a level key value and sort key
Returns a value to support sort order based on lvls dict.
The result is that like-level items are sorted together.
The level number provides sameness for levels that are named differently
but are the same level for our purposes. The sort key retains the original
provided level so that like named items still sort together.
"""
if level_name is None:
if (error):
@ -111,8 +129,8 @@ def _lvl_key(level_name, error):
for key, val_list in _LEVEL_KEYS.items():
if level_name in val_list:
return '{}{}'.format(key, level_name)
return _SENTINEL_LEVEL
return key, '{}{}'.format(key, level_name)
return _SENTINEL_LEVEL, _SENTINEL_SORT_KEY
def _format_validation_message(message):

View File

@ -60,7 +60,6 @@ def test_cli_format_error_handler_no_messages():
resp = MagicMock()
resp.json = MagicMock(return_value=json.loads(resp_val))
output = format_utils.cli_format_error_handler(resp)
print(output)
assert "Error: Unauthenticated" in output
assert "Reason: Credentials are not established" in output
@ -208,7 +207,74 @@ Reason: Validation
Document: schema/schema/v1 - someyaml
Source: format-o-matic
- Info: Basic info
Source: Armadadock"""
Source: Armadadock
#### Errors: 4, Warnings: 0, Infos: 2, Other: 0 ####"""
resp = MagicMock()
resp.json = MagicMock(return_value=json.loads(resp_val))
output = format_utils.cli_format_status_handler(resp, is_error=True)
assert output == expected
def test_cli_format_status_handler_messages_empty():
"""Tests the generic handler for shipyard status response if passed
a response with no message in the detail to ensure the empty case works.
"""
resp_val = """
{
"apiVersion": "v1.0",
"status": "Failure",
"metadata": {},
"message": "Component Validation Failed",
"code": 400,
"details": {
"errorCount": 0,
"messageList": []
},
"kind": "Status",
"reason": "Validation"
}
"""
expected = """Error: Component Validation Failed
Reason: Validation
#### Errors: 0, Warnings: 0, Infos: 0, Other: 0 ####"""
resp = MagicMock()
resp.json = MagicMock(return_value=json.loads(resp_val))
output = format_utils.cli_format_status_handler(resp, is_error=True)
assert output == expected
def test_cli_format_status_handler_messages_invalid_levels():
"""Tests the generic handler for shipyard status response if passed
a response with no message in the detail to ensure the empty case works.
"""
resp_val = """
{
"apiVersion": "v1.0",
"status": "Failure",
"metadata": {},
"message": "Component Validation Failed",
"code": 400,
"details": {
"errorCount": 0,
"messageList": [
{ "message": "It is broken",
"level": "Broken",
"kind": "ValidationMessage"
}
]
},
"kind": "Status",
"reason": "Validation"
}
"""
expected = """Error: Component Validation Failed
Reason: Validation
- Broken: None
Message: It is broken
#### Errors: 0, Warnings: 0, Infos: 0, Other: 1 ####"""
resp = MagicMock()
resp.json = MagicMock(return_value=json.loads(resp_val))
output = format_utils.cli_format_status_handler(resp, is_error=True)

View File

@ -39,7 +39,6 @@ def test_add_role():
def test_add_roles():
'''test add_roles'''
ctx = ShipyardRequestContext()
print(ctx.roles)
test_roles = ['Waiter', 'Host', 'Chef']
ctx.add_roles(test_roles)
assert ['Chef', 'Host', 'Waiter', 'anyone'] == sorted(ctx.roles)