Track abandon actions as reviews

Record of type 'mark' is created when reviewer abandons someone else's
change requests. The stats on such marks is included into review stats

Change-Id: I44955c72326c95bbf421ea47b177972e06aa6ca2
Closes-Bug: #1498769
This commit is contained in:
Ilya Shakhat 2015-10-12 17:52:00 +03:00
parent 19f9eaf0b3
commit b0c0791e73
8 changed files with 50 additions and 18 deletions

View File

@ -247,6 +247,9 @@ def mark_filter(result, record, param_id, context):
if record_type == 'Code-Review':
result_by_param['metric'] += 1
value = record.value
elif record_type == 'Abandon':
result_by_param['metric'] += 1
value = 'x'
elif record.type == 'Workflow':
if record.value == 1:
value = 'A'
@ -265,7 +268,7 @@ def mark_finalize(record):
positive = 0
numeric = 0
mark_distribution = []
for key in [-2, -1, 1, 2, 'A']:
for key in [-2, -1, 1, 2, 'A', 'x']:
if key in record:
if key in [1, 2]:
positive += record[key]

View File

@ -182,7 +182,7 @@ def get_activity(records, start_record, page_size, query_message=None):
def get_contribution_summary(records):
marks = dict((m, 0) for m in [-2, -1, 0, 1, 2, 'A', 'WIP'])
marks = dict((m, 0) for m in [-2, -1, 0, 1, 2, 'A', 'WIP', 'x', 's'])
commit_count = 0
loc = 0
drafted_blueprint_count = 0
@ -208,6 +208,10 @@ def get_contribution_summary(records):
value = 'WIP'
elif record.type == 'Code-Review':
value = record.value
elif record.type == 'Abandon':
value = 'x'
elif record.type[:5] == 'Self-':
value = 's'
marks[value] += 1
elif record_type == 'email':
email_count += 1

View File

@ -106,11 +106,13 @@ show_record_type=True, show_user_gravatar=True, gravatar_size=32, show_all=True)
<div>Change Id: <a href="${parent_url}" target="_blank">${review_id}</a></div>
<div style="color: {%if value > 0 %} green {%else%} blue {%/if%}">
{%if (type == "Workflow" && value == 1) %}
Approved
Approve
{%elif (type == "Self-Workflow" && value == 1) %}
Self-Approved
Self-Approve
{%elif (type == "Workflow" && value == -1) %}
Work in progress
{%elif (type == "Abandon" || type == "Self-Abandon") %}
${type}
{%else%}
${type}: <span class="review_mark">${value}</span>
{%/if%}

View File

@ -29,9 +29,14 @@
<script id="contribution_template" type="text/x-jquery-tmpl">
{% raw %}
<div>Total commits: <b>${commit_count}</b></div>
<div>Total LOC: <b>${loc}</b></div>
<div>Review stat (-2, -1, +1, +2, A): <b>${marks["-2"]}, ${marks["-1"]}, ${marks["1"]}, ${marks["2"]}, ${marks["A"]}</b></div>
<div>Commits: <b>${commit_count}</b></div>
<div>LOCs: <b>${loc}</b></div>
<div>Do not merge (-2): <b>${marks["-2"]}</b>
<div>Patch needs further work (-1): <b>${marks["-1"]}</b>
<div>Looks good (+1): <b>${marks["1"]}</b>
<div>Looks good for core (+2): <b>${marks["2"]}</b>
<div>Approve: <b>${marks["A"]}</b>
<div>Abandon: <b>${marks["x"]}</b>
<div>Change Requests: <b>${change_request_count}</b>
{%if abandoned_change_requests_count > 0 %}
<span>(${abandoned_change_requests_count} of them abandoned)</span>

View File

@ -101,7 +101,7 @@
<th>#</th>
<th>{% if show_ci %}Driver{% else %}Contributor{% endif %}</th>
{% if show_review_ratio %}
<th>-2|-1|+1|+2|A (+ ratio)</th>
<th>-2|-1|+1|+2|A|x (+ ratio)</th>
{% endif %}
<th>{{ metric_label }}</th>
{% if show_ci %}

View File

@ -23,7 +23,7 @@
});
$(document).ready(function () {
var table_column_names = ["index", "link", "metric", "-2", "-1", "1", "2", "A", "positive_ratio", "disagreements", "disagreement_ratio",
var table_column_names = ["index", "link", "metric", "-2", "-1", "1", "2", "A", "x", "positive_ratio", "disagreements", "disagreement_ratio",
"review_ratio", "commit", "email"];
var table_id = "review_stats_table";
@ -95,7 +95,7 @@
"aaData": tableData,
"aoColumns": tableColumns,
"aoColumnDefs": [
{ "sClass": "center", "aTargets": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] },
{ "sClass": "center", "aTargets": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] },
{ "sType": "ratio", "aTargets": [8, 10]}
]
});
@ -144,11 +144,12 @@
<th>#</th>
<th>Engineer</th>
<th>Reviews</th>
<th>-2</th>
<th>-1</th>
<th>+1</th>
<th>+2</th>
<th>A</th>
<th title="Do not merge (-2)">-2</th>
<th title="Patch needs further work (-1)">-1</th>
<th title="Looks good (+1)">+1</th>
<th title="Looks good for core (+2)">+2</th>
<th title="Approve">A</th>
<th title="Abandon">x</th>
<th>+ %</th>
<th>Disagreements</th>
<th>Ratio</th>

View File

@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import itertools
from oslo_config import cfg
from oslo_log import log as logging
import psutil
@ -134,8 +136,12 @@ def _process_repo(repo, runtime_storage_inst, record_processor_inst,
last_retrieval_time = runtime_storage_inst.get_by_key(rcs_key)
current_retrieval_time = int(time.time())
review_iterator = rcs_inst.log(repo, branch, last_retrieval_time,
grab_comments=('ci' in repo))
review_iterator = itertools.chain(
rcs_inst.log(repo, branch, last_retrieval_time, status='open'),
rcs_inst.log(repo, branch, last_retrieval_time, status='merged'),
rcs_inst.log(repo, branch, last_retrieval_time, status='abandoned',
grab_comments=True),
)
review_iterator_typed = _record_typer(review_iterator, 'review')
processed_review_iterator = record_processor_inst.process(

View File

@ -428,6 +428,17 @@ class RecordProcessor(object):
yield self._make_mark_record(record, patch, approval)
# check for abandon action
if record.get('status') == 'ABANDONED':
for comment in reversed(record.get('comments') or []):
if comment['message'] == 'Abandoned':
action = dict(type='Abandon', value=0)
action['by'] = comment['reviewer']
action['grantedOn'] = comment['timestamp']
yield self._make_mark_record(
record, record['patchSets'][-1], action)
def _guess_module(self, record):
subject = record['subject'].lower()
pos = len(subject)
@ -818,7 +829,7 @@ class RecordProcessor(object):
patch_id = utils.get_patch_id(record['review_id'], record['patch'])
if record['user_id'] == patch_id_to_user_id.get(patch_id):
if record['type'].find('Self-') < 0:
if record['type'][:5] == 'Self-':
record['type'] = 'Self-%s' % record['type']
yield record