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:
parent
e6eb64af82
commit
ac05b179ca
@ -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
|
||||
|
@ -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')
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 += " ✬ <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>
|
||||
|
@ -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')
|
||||
|
Loading…
x
Reference in New Issue
Block a user