Updates to API report tooling

This patch updates our api-report tooling as follows:
- Bugfix to support None as a valid public API attribute value.
- Rather than tracking collections with scalars, the tool now just
tracks the type of the collection (e.g. dict, list, etc.). There's no
reason for this tool to dig into collections and track their values
for API (tho it could do more with additional effort/code).
- Better handling/output for API signature changes. Previously
some of the output describing a changed API was a bit confusing.
This patch tries to address that issue by adding additional handling
for the scenario.

Sample output from current report [1] vs output with this patch [2].

[1] http://paste.openstack.org/show/587662/
[2] http://paste.openstack.org/show/587663/

Change-Id: Ic380633477c9939773198463a21ef887d575aa21
This commit is contained in:
Boden R
2016-11-02 10:05:56 -06:00
parent 763fe5ed23
commit 75ae597a8c
2 changed files with 33 additions and 11 deletions

View File

@@ -79,10 +79,10 @@ if [[ ${TAG_RELEASE} == '' ]]; then
fi fi
${PYIR_PATH} generate --blacklist '.*\/tests\/.*','.*\._(\w+)' ${PACKAGE} > "${TMPDIR}/${PACKAGE}.master.json.txt" ${PYIR_PATH} generate --blacklist '.*\/tests\/.*','.*\._(\w*)' ${PACKAGE} > "${TMPDIR}/${PACKAGE}.master.json.txt"
install_project install_project
${PYIR_PATH} generate --blacklist '.*\/tests\/.*','.*\._(\w+)' ${TMPDIR}/${PROJECT}/${PACKAGE} > "${TMPDIR}/${PACKAGE}.${TAG_RELEASE}.json.txt" ${PYIR_PATH} generate --blacklist '.*\/tests\/.*','.*\._(\w*)' ${TMPDIR}/${PROJECT}/${PACKAGE} > "${TMPDIR}/${PACKAGE}.${TAG_RELEASE}.json.txt"
echo "===========================================================" echo "==========================================================="

View File

@@ -331,13 +331,15 @@ def ordered(obj):
def json_primitive(val): def json_primitive(val):
if (str(val).count(_MOCK_CLASS_NAME) or if isinstance(val, (six.string_types, six.text_type,
six.integer_types, bool)):
return str(val)
elif str(val).startswith('<') or type(val) in [dict, list, set, tuple]:
return str(type(val))
elif (str(val).count(_MOCK_CLASS_NAME) or
str(val).count(_MOCK_IMPORT_CLASS_NAME)): str(val).count(_MOCK_IMPORT_CLASS_NAME)):
return UNKNOWN_VAL return UNKNOWN_VAL
primitive = jsonutils.to_primitive(val) return val
if str(primitive).startswith('<'):
return UNKNOWN_VAL
return primitive
def is_mock_import(obj): def is_mock_import(obj):
@@ -1079,10 +1081,8 @@ class APISignature(object):
return "%s(%s)" % (signature_dict['qualified_name'], arg_str.strip()) return "%s(%s)" % (signature_dict['qualified_name'], arg_str.strip())
def _build_variable_signature(self, signature_dict): def _build_variable_signature(self, signature_dict):
val = (UNKNOWN_VAL return "%s = %s" % (signature_dict['qualified_name'],
if signature_dict['member_value'] is None signature_dict['member_value'])
else signature_dict['member_value'])
return "%s = %s" % (signature_dict['qualified_name'], val)
def _build_class_signature(self, signature_dict): def _build_class_signature(self, signature_dict):
return signature_dict['qualified_name'] return signature_dict['qualified_name']
@@ -1305,6 +1305,11 @@ class APIReport(object):
if ordered(self.api[k]) != if ordered(self.api[k]) !=
ordered(other_api.api[k])] ordered(other_api.api[k])]
for k in common_key_changes:
if (not blacklist_filter(self.api[k]['member_value']) and not
blacklist_filter(other_api.api[k]['member_value'])):
common_key_changes.remove(k)
def _build_report(new_api): def _build_report(new_api):
apis = APIReport() apis = APIReport()
apis._api = new_api apis._api = new_api
@@ -1467,6 +1472,23 @@ class DiffReportCommand(AbstractCommand):
new_sigs = api_diff['new_changed'].get_filtered_signatures() new_sigs = api_diff['new_changed'].get_filtered_signatures()
old_sigs = api_diff['old_changed'].get_filtered_signatures() old_sigs = api_diff['old_changed'].get_filtered_signatures()
if len(new_sigs) != len(old_sigs):
new_sigs = []
old_sigs = []
new_changed = api_diff['new_changed'].api
old_changed = api_diff['old_changed'].api
for n, new_spec in new_changed.items():
display_old = blacklist_filter(old_changed[n]['member_value'])
display_new = blacklist_filter(new_spec['member_value'])
if display_old and display_new:
new_sigs.append(APISignature.get_signature(new_spec))
old_sigs.append(APISignature.get_signature(old_changed[n]))
elif not display_old:
new_sigs.append(APISignature.get_signature(new_spec))
old_sigs.append(n)
else:
new_sigs.append('UNKNOWN')
old_sigs.append(n)
self._print_row("Changed API Signatures", self._print_row("Changed API Signatures",
["%s [is now] %s" % ["%s [is now] %s" %
(old_sigs[i], new_sigs[i]) (old_sigs[i], new_sigs[i])