diff --git a/dashboard/helpers.py b/dashboard/helpers.py index 7a7e6b78a..959eba6bb 100644 --- a/dashboard/helpers.py +++ b/dashboard/helpers.py @@ -52,6 +52,13 @@ def _extend_record_common_fields(record): _extend_author_fields(coauthor) +def _extend_by_parent_info(record, parent): + parent = parent.copy() + _extend_record_common_fields(parent) + for k, v in six.iteritems(parent): + record['parent_' + k] = v + + def extend_record(record): record = record.copy() _extend_record_common_fields(record) @@ -69,14 +76,11 @@ def extend_record(record): if not parent: return None - parent = parent.copy() - _extend_record_common_fields(parent) - for k, v in six.iteritems(parent): - record['parent_%s' % k] = v - - record['review_number'] = parent.get('review_number') - record['subject'] = parent['subject'] - record['url'] = parent['url'] + _extend_by_parent_info(record, parent) + elif record['record_type'] == 'patch': + parent = vault.get_memory_storage().get_record_by_primary_key( + record['review_id']) + _extend_by_parent_info(record, parent) elif record['record_type'] == 'email': record['email_link'] = record.get('email_link') or '' record['blueprint_links'] = [] diff --git a/dashboard/templates/_macros/activity_log.html b/dashboard/templates/_macros/activity_log.html index b9dac5ee7..435595cfb 100644 --- a/dashboard/templates/_macros/activity_log.html +++ b/dashboard/templates/_macros/activity_log.html @@ -91,14 +91,17 @@ show_record_type=True, show_user_gravatar=True, gravatar_size=32, show_all=True)
+${lines_added} - ${lines_deleted}
{%elif record_type == "mark" %} -
Review “${subject}”
-
Submitted by: {%html parent_author_link %} ({%html parent_company_link %}) (#${review_number})
-
Change Id: ${review_id}
+
Review “${parent_subject}”
+
Submitted by: {%html parent_author_link %} ({%html parent_company_link %}) (#${parent_review_number})
+
Change Id: ${review_id}
${description}: ${value}
{%elif record_type == "review" %} -
Patch “${subject}”
+
New change request “${subject}”
Current Status: ${status}
Change Id: ${id}
+ {%elif record_type == "patch" %} +
Patch #${number} “${parent_subject}”
+
Change Id: ${review_id}
{%elif record_type == "email" %}
{%if email_link != "" %} diff --git a/stackalytics/processor/record_processor.py b/stackalytics/processor/record_processor.py index 265846228..ac61ebfd5 100644 --- a/stackalytics/processor/record_processor.py +++ b/stackalytics/processor/record_processor.py @@ -256,13 +256,11 @@ class RecordProcessor(object): yield new_record - def _spawn_review(self, record): + def _make_review_record(self, record): # copy everything except patchsets and flatten user data review = dict([(k, v) for k, v in six.iteritems(record) if k not in ['patchSets', 'owner', 'createdOn']]) owner = record['owner'] - if 'email' not in owner or 'username' not in owner: - return # ignore review['primary_key'] = review['id'] review['launchpad_id'] = owner['username'] @@ -286,56 +284,74 @@ class RecordProcessor(object): review['value'] = 0 self._update_record_and_user(review) + return review - yield review + def _make_patch_record(self, review, patch): + patch_record = dict() + patch_record['record_type'] = 'patch' + patch_record['primary_key'] = utils.get_patch_id( + review['id'], patch['number']) + patch_record['number'] = patch['number'] + patch_record['date'] = patch['createdOn'] + uploader = patch['uploader'] + patch_record['launchpad_id'] = uploader['username'] + patch_record['author_name'] = uploader['name'] + patch_record['author_email'] = uploader['email'].lower() + patch_record['module'] = review['module'] + patch_record['branch'] = review['branch'] + patch_record['review_id'] = review['id'] - def _spawn_marks(self, record): - review_id = record['id'] - module = record['module'] - branch = record['branch'] + self._update_record_and_user(patch_record) + return patch_record - for patch in record.get('patchSets', []): - if 'approvals' not in patch: - continue # not reviewed by anyone - for approval in patch['approvals']: - if approval['type'] not in ('CRVW', 'APRV'): - continue # keep only Code-Review and Approved + def _make_mark_record(self, review, patch, approval): + # copy everything and flatten user data + mark = dict([(k, v) for k, v in six.iteritems(approval) + if k not in ['by', 'grantedOn', 'value']]) + reviewer = approval['by'] - # copy everything and flatten user data - mark = dict([(k, v) for k, v in six.iteritems(approval) - if k not in ['by', 'grantedOn', 'value']]) - reviewer = approval['by'] + mark['record_type'] = 'mark' + mark['value'] = int(approval['value']) + mark['date'] = approval['grantedOn'] + mark['primary_key'] = (review['id'] + str(mark['date']) + mark['type']) + mark['launchpad_id'] = reviewer['username'] + mark['author_name'] = reviewer['name'] + mark['author_email'] = reviewer['email'].lower() + mark['module'] = review['module'] + mark['branch'] = review['branch'] + mark['review_id'] = review['id'] + mark['patch'] = int(patch['number']) - if 'email' not in reviewer or 'username' not in reviewer: - continue # ignore - - mark['record_type'] = 'mark' - mark['value'] = int(approval['value']) - mark['date'] = approval['grantedOn'] - mark['primary_key'] = (record['id'] + - str(mark['date']) + - mark['type']) - mark['launchpad_id'] = reviewer['username'] - mark['author_name'] = reviewer['name'] - mark['author_email'] = reviewer['email'].lower() - mark['module'] = module - mark['branch'] = branch - mark['review_id'] = review_id - mark['patch'] = int(patch['number']) - - self._update_record_and_user(mark) - - yield mark + self._update_record_and_user(mark) + return mark def _process_review(self, record): """ - Process a review. Review spawns into records of two types: + Process a review. Review spawns into records of three types: * review - records that a user created review request + * patch - records that a user submitted another patch set * mark - records that a user set approval mark to given review """ - for gen in [self._spawn_review, self._spawn_marks]: - for r in gen(record): - yield r + owner = record['owner'] + if 'email' not in owner or 'username' not in owner: + return # ignore + + yield self._make_review_record(record) + + for patch in record.get('patchSets', []): + yield self._make_patch_record(record, patch) + + if 'approvals' not in patch: + continue # not reviewed by anyone + + for approval in patch['approvals']: + if approval['type'] not in ('CRVW', 'APRV'): + continue # keep only Code-Review and Approved + if ('email' not in approval['by'] or + 'username' not in approval['by']): + continue # ignore + + yield self._make_mark_record(record, patch, approval) def _guess_module(self, record): subject = record['subject'].lower() diff --git a/stackalytics/processor/utils.py b/stackalytics/processor/utils.py index c1c3eed78..9d86a81ed 100644 --- a/stackalytics/processor/utils.py +++ b/stackalytics/processor/utils.py @@ -165,6 +165,10 @@ def get_blueprint_id(module, name): return module + ':' + name +def get_patch_id(review_id, patch_number): + return review_id + ':' + patch_number + + def add_index(sequence, start=1, item_filter=lambda x: True): n = start for item in sequence: diff --git a/tests/unit/test_record_processor.py b/tests/unit/test_record_processor.py index 019c68d59..40fe00432 100644 --- a/tests/unit/test_record_processor.py +++ b/tests/unit/test_record_processor.py @@ -776,7 +776,7 @@ class TestRecordProcessor(testtools.TestCase): 'emails': ['john_doe@ibm.com'], 'core': [('nova', 'master')], 'companies': [{'company_name': 'IBM', 'end_date': 0}]} - user_2 = {'seq': 2, 'user_id': 'homer', + user_2 = {'seq': 3, 'user_id': 'homer', 'launchpad_id': 'homer', 'user_name': 'Homer Simpson', 'emails': ['hsimpson@gmail.com'], 'core': [],