Extend review report with more contribution data

Added columns on number of posted patches, number of commits and sent emails.
Added summary for contribution statistics

Part of blueprint extend-russell-report

Change-Id: Ie496ee51ab3bfebb5df9b9980c5f9fd5e3a93068
This commit is contained in:
Ilya Shakhat 2013-12-18 16:10:16 +04:00
parent e6eb64af82
commit ac05b179ca
5 changed files with 84 additions and 31 deletions

View File

@ -183,15 +183,20 @@ def aggregate_filter():
mark_distribution.append('0')
new_record[key] = 0
positive_ratio = ' (%.1f%%)' % (
(positive * 100.0) / record['metric'])
new_record['mark_ratio'] = (
'|'.join(mark_distribution) + positive_ratio)
new_record['positive_ratio'] = positive_ratio
new_record['disagreements'] = record.get('disagreements', 0)
new_record['disagreement_ratio'] = '%.1f%%' % (
(record.get('disagreements', 0) * 100.0) / record['metric']
)
if record['metric']:
positive_ratio = '%.1f%%' % (
(positive * 100.0) / record['metric'])
new_record['disagreement_ratio'] = '%.1f%%' % (
(record.get('disagreements', 0) * 100.0) /
record['metric'])
else:
positive_ratio = helpers.INFINITY_HTML
new_record['disagreement_ratio'] = helpers.INFINITY_HTML
new_record['mark_ratio'] = ('|'.join(mark_distribution) +
' (' + positive_ratio + ')')
new_record['positive_ratio'] = positive_ratio
return new_record
metric_param = (flask.request.args.get('metric') or

View File

@ -24,6 +24,8 @@ from dashboard import vault
from stackalytics.processor import utils
INFINITY_HTML = '∞'
gravatar = gravatar_ext.Gravatar(None, size=64, rating='g', default='wavatar')

View File

@ -266,7 +266,7 @@ function make_uri(uri, options) {
$.extend(ops, options);
}
var str = $.map(ops,function (val, index) {
return index + "=" + val;
return index + "=" + encodeURIComponent(val).toLowerCase();
}).join("&");
return (str == "") ? uri : uri + "?" + str;

View File

@ -1,13 +1,14 @@
{% extends "reports/base_report.html" %}
{% block title %}
Reviews for the last {{ days }} days in {{ module }}
Contribution into {{ module }} for the last {{ days }} days
{% endblock %}
{% block scripts %}
<script type="text/javascript">
$(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", "positive_ratio", "disagreements", "disagreement_ratio",
"review_ratio", "commit", "email"];
var table_id = "review_stats_table";
$.ajax({
@ -28,15 +29,20 @@ Reviews for the last {{ days }} days in {{ module }}
var summary = {
'marks': 0,
'core_marks': 0,
'reviewers': tableData.length,
'core_reviewers': 0
'reviewers': 0,
'core_reviewers': 0,
'commits': 0,
'reviews': 0,
'patch_count': 0,
'emails': 0
};
for (i = 0; i < tableData.length; i++) {
if (tableData[i].id) {
var options = {user_id: tableData[i].id, metric: "marks"};
var link = make_uri("/", options);
tableData[i].link = "<a href=\"" + link + "\">" + tableData[i].name + " (" + tableData[i].id + ")</a>"
var user_link = make_uri("/", {user_id: tableData[i].id, metric: "marks"});
var company_link = make_uri("/", {company: tableData[i].company, metric: "marks"});
tableData[i].link = "<a href=\"" + user_link + "\">" + tableData[i].name + "</a>" +
" <a href=\"" + company_link + "\">" + "(" + tableData[i].company + ")</a>"
} else {
tableData[i].link = tableData[i].name
}
@ -48,7 +54,15 @@ Reviews for the last {{ days }} days in {{ module }}
} else if (tableData[i].core) {
tableData[i].link += "&nbsp;&#x272C; <small><i>" + tableData[i].core + "</i></small>";
}
if (tableData[i].metric > 0) {
summary.reviewers ++;
}
tableData[i].review_ratio = tableData[i].review + " / " + tableData[i].patch_count;
summary.marks += tableData[i].metric;
summary.commits += tableData[i].commit;
summary.reviews += tableData[i].review;
summary.patch_count += tableData[i].patch_count;
summary.emails += tableData[i].email;
}
if (table_id) {
@ -64,7 +78,7 @@ Reviews for the last {{ days }} days in {{ module }}
"aaData": tableData,
"aoColumns": tableColumns,
"aoColumnDefs": [
{ "sClass": "center", "aTargets": [2, 3, 4, 5, 6, 7, 8, 9, 10] }
{ "sClass": "center", "aTargets": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] }
]
});
}
@ -94,12 +108,17 @@ Reviews for the last {{ days }} days in {{ module }}
<div>Total reviewers: <b>${reviewers}</b> (${(marks / reviewers / {{ days }}).toFixed(1) } per reviewer per day)</div>
<div>Total reviews by core team: <b>${core_marks}</b> (${(core_marks / {{ days }}).toFixed(1) } per day)</div>
<div>Core team size: <b>${core_reviewers}</b> (${(core_marks / core_reviewers / {{ days }}).toFixed(1) } per core per day)</div>
<h2>Contribution Summary</h2>
<div>On review: <b>${reviews}</b> (${(reviews / {{ days }}).toFixed(1) } per day)</div>
<div>Patch sets: <b>${patch_count}</b> (${(patch_count / {{ days }}).toFixed(1) } per day)</div>
<div>Commits: <b>${commits}</b> (${(commits / {{ days }}).toFixed(1) } per day)</div>
<div>Emails: <b>${emails}</b> (${(emails / {{ days }}).toFixed(1) } per day)</div>
</script>
{% endblock %}
{% block content %}
<h1>Reviews for the last {{ days }} days in {{ module }}</h1>
<h1>Contribution into {{ module }} for the last {{ days }} days</h1>
<table id="review_stats_table">
<thead>
@ -112,9 +131,12 @@ Reviews for the last {{ days }} days in {{ module }}
<th>+1</th>
<th>+2</th>
<th>A</th>
<th>(+/- %)</th>
<th>+/-</th>
<th>Disagreements</th>
<th>Ratio</th>
<th>On review / patch sets</th>
<th>Commits</th>
<th>Emails</th>
</tr>
</thead>
<tbody>

View File

@ -78,8 +78,7 @@ def page_not_found(e):
# AJAX Handlers ---------
def _get_aggregated_stats(records, metric_filter, keys, param_id,
param_title=None, finalize_handler=None,
postprocessing=None):
param_title=None, finalize_handler=None):
param_title = param_title or param_id
result = dict((c, {'metric': 0, 'id': c}) for c in keys)
for record in records:
@ -87,12 +86,11 @@ def _get_aggregated_stats(records, metric_filter, keys, param_id,
result[record[param_id]]['name'] = record[param_title]
if not finalize_handler:
finalize_handler = lambda x: x
response = [finalize_handler(result[r]) for r in result
if result[r]['metric']]
response = [r for r in result.values() if r['metric']]
else:
response = result.values()
response.sort(key=lambda x: x['metric'], reverse=True)
response = [item for item in map(postprocessing, response) if item]
response = [item for item in map(finalize_handler, response) if item]
utils.add_index(response, item_filter=lambda x: x['id'] != '*independent')
return response
@ -122,7 +120,7 @@ def get_modules(records, metric_filter, finalize_handler):
@app.route('/api/1.0/stats/engineers')
@decorators.jsonify('stats')
@decorators.exception_handler()
@decorators.record_filter()
@decorators.record_filter(ignore='metric')
@decorators.aggregate_filter()
def get_engineers(records, metric_filter, finalize_handler):
@ -130,8 +128,20 @@ def get_engineers(records, metric_filter, finalize_handler):
modules_names = parameters.get_parameter({}, 'module', 'modules')
modules = vault.resolve_modules(modules_names)
def filter_core_users(record):
def postprocessing(record):
if finalize_handler:
record = finalize_handler(record)
user = vault.get_user_from_runtime_storage(record['id'])
record['company'] = user['companies'][-1]['company_name']
record['review'] = record.get('review', 0)
record['commit'] = record.get('commit', 0)
record['email'] = record.get('email', 0)
record['patch_count'] = record.get('patch_count', 0)
if not (record['metric'] or record['review'] or record['commit'] or
record['email'] or record['patch_count']):
return
is_core = False
for (module, branch) in user['core']:
if module in modules:
@ -147,11 +157,25 @@ def get_engineers(records, metric_filter, finalize_handler):
record['core'] = is_core
return record
return _get_aggregated_stats(records, metric_filter,
def record_processing(result, record, param_id):
record_type = record['record_type']
result_row = result[record[param_id]]
if record_type == 'mark':
metric_filter(result, record, param_id)
elif record_type == 'commit':
result_row['commit'] = result_row.get('commit', 0) + 1
elif record_type == 'email':
result_row['email'] = result_row.get('email', 0) + 1
elif record_type == 'review':
result_row['review'] = result_row.get('review', 0) + 1
result_row['patch_count'] = (result_row.get('patch_count', 0) +
record['patch_count'])
return _get_aggregated_stats(records, record_processing,
vault.get_memory_storage().get_user_ids(),
'user_id', 'author_name',
finalize_handler=finalize_handler,
postprocessing=filter_core_users)
finalize_handler=postprocessing)
@app.route('/api/1.0/stats/distinct_engineers')