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:
parent
19f9eaf0b3
commit
b0c0791e73
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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%}
|
||||
|
@ -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>
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user