Implemented summary report on reviews per engineer
Partially implements blueprint review-stats Change-Id: I011d81a10ad63746a9246a62379c0f6b4c814812
This commit is contained in:
parent
6779de9dc2
commit
7fcf69efdf
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h4>Marks</h4>
|
<h3>Reviews</h3>
|
||||||
{% for mark in [-2, -1, 0, 1, 2] %}
|
{% for mark in [-2, -1, 0, 1, 2] %}
|
||||||
<div>{{ mark }}: {{ marks[mark] }}</div>
|
<div>{{ mark }}: {{ marks[mark] }}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -114,6 +114,7 @@
|
|||||||
var aggregate = 0;
|
var aggregate = 0;
|
||||||
var index = 1;
|
var index = 1;
|
||||||
var i;
|
var i;
|
||||||
|
var hasComment = false;
|
||||||
|
|
||||||
for (i = 0; i < data.length; i++) {
|
for (i = 0; i < data.length; i++) {
|
||||||
if (i < limit - 1) {
|
if (i < limit - 1) {
|
||||||
@ -133,7 +134,12 @@
|
|||||||
} else {
|
} else {
|
||||||
var link = data[i].name
|
var link = data[i].name
|
||||||
}
|
}
|
||||||
tableData.push({"index": index_label, "link": link, "metric": data[i].metric});
|
var rec = {"index": index_label, "link": link, "metric": data[i].metric};
|
||||||
|
if (data[i].comment) {
|
||||||
|
rec["comment"] = data[i].comment;
|
||||||
|
hasComment = true;
|
||||||
|
}
|
||||||
|
tableData.push(rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == limit) {
|
if (i == limit) {
|
||||||
@ -142,6 +148,15 @@
|
|||||||
chartData.push(["others", aggregate]);
|
chartData.push(["others", aggregate]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tableColumns = [
|
||||||
|
{ "mData": "index" },
|
||||||
|
{ "mData": "link" },
|
||||||
|
{ "mData": "metric" }
|
||||||
|
];
|
||||||
|
if (hasComment) {
|
||||||
|
tableColumns.push({ "mData": "comment"})
|
||||||
|
}
|
||||||
|
|
||||||
$("#" + table_id).dataTable({
|
$("#" + table_id).dataTable({
|
||||||
"aLengthMenu": [
|
"aLengthMenu": [
|
||||||
[25, 50, -1],
|
[25, 50, -1],
|
||||||
@ -153,11 +168,7 @@
|
|||||||
"sPaginationType": "full_numbers",
|
"sPaginationType": "full_numbers",
|
||||||
"iDisplayLength": 25,
|
"iDisplayLength": 25,
|
||||||
"aaData": tableData,
|
"aaData": tableData,
|
||||||
"aoColumns": [
|
"aoColumns": tableColumns
|
||||||
{ "mData": "index" },
|
|
||||||
{ "mData": "link" },
|
|
||||||
{ "mData": "metric" }
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var plot = $.jqplot(chart_id, [chartData], {
|
var plot = $.jqplot(chart_id, [chartData], {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
chartAndTableRenderer("/data/companies", "left_list", "left_chart", "/companies/", {module: "{{ module }}" });
|
chartAndTableRenderer("/data/companies", "left_list", "left_chart", "/companies/", {module: "{{ module }}" });
|
||||||
|
chartAndTableRenderer("/data/engineers", "right_list", "right_chart", "/engineers/", {module: "{{ module }}" });
|
||||||
timelineRenderer({module: "{{ module }}" })
|
timelineRenderer({module: "{{ module }}" })
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -34,37 +35,24 @@
|
|||||||
|
|
||||||
{% block right_frame %}
|
{% block right_frame %}
|
||||||
|
|
||||||
<h2>Recent activity</h2>
|
<h2>Contribution by engineers</h2>
|
||||||
|
|
||||||
{% for rec in commits %}
|
<div id="right_chart" style="width: 100%; height: 350px;"></div>
|
||||||
<div style="padding-bottom: 1em;">
|
|
||||||
<div style='float: left; '>
|
|
||||||
<img src="{{ rec.author_email|gravatar(size=32) }}">
|
|
||||||
</div>
|
|
||||||
<div style="margin-left: 4em;">
|
|
||||||
<div>
|
|
||||||
{% if rec.launchpad_id %}
|
|
||||||
{{ rec.author_name|link('/engineers/' + rec.launchpad_id)|safe }}
|
|
||||||
{% else %}
|
|
||||||
{{ rec.author_name }}
|
|
||||||
{% endif %}
|
|
||||||
{% if rec.company_name %}
|
|
||||||
(
|
|
||||||
{{ rec.company_name|link('/companies/' + rec.company_name)|safe }}
|
|
||||||
)
|
|
||||||
{% endif %}
|
|
||||||
<em>{{ rec.date|datetimeformat }}</em>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if rec.correction_comment %}
|
<table id="right_list" class="display">
|
||||||
<div style='font-weight: bold; color: red; padding-left: 2em;'>Commit corrected: {{ rec.correction_comment }}</div>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Engineer</th>
|
||||||
|
<th>{{ metric_label }}</th>
|
||||||
|
{% if metric == 'marks' %}
|
||||||
|
<th>-2|-1|+1|+2 (+/- ratio)</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div><b>{{ rec.subject }}</b></div>
|
</tr>
|
||||||
<div style="white-space: pre-wrap;">{{ rec|commit_message|safe }}</div>
|
</thead>
|
||||||
<div><span style="color: green">+ {{ rec.lines_added }}</span>
|
<tbody>
|
||||||
<span style="color: red">- {{ rec.lines_deleted }}</span></div>
|
</tbody>
|
||||||
</div>
|
</table>
|
||||||
</div>
|
<div class="spacer"></div>
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -44,8 +44,7 @@ DEFAULTS = {
|
|||||||
METRIC_LABELS = {
|
METRIC_LABELS = {
|
||||||
'loc': 'Lines of code',
|
'loc': 'Lines of code',
|
||||||
'commits': 'Commits',
|
'commits': 'Commits',
|
||||||
'reviews': 'Reviews',
|
'marks': 'Reviews',
|
||||||
'marks': 'Marks',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_RECORDS_LIMIT = 10
|
DEFAULT_RECORDS_LIMIT = 10
|
||||||
@ -277,17 +276,59 @@ def aggregate_filter():
|
|||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def aggregate_filter_decorated_function(*args, **kwargs):
|
def aggregate_filter_decorated_function(*args, **kwargs):
|
||||||
|
|
||||||
|
def commit_filter(result, record, param_id):
|
||||||
|
result[record[param_id]]['metric'] += 1
|
||||||
|
|
||||||
|
def loc_filter(result, record, param_id):
|
||||||
|
result[record[param_id]]['metric'] += record['loc']
|
||||||
|
|
||||||
|
def mark_filter(result, record, param_id):
|
||||||
|
value = record['value']
|
||||||
|
result_by_param = result[record[param_id]]
|
||||||
|
result_by_param['metric'] += 1
|
||||||
|
|
||||||
|
if value in result_by_param:
|
||||||
|
result_by_param[value] += 1
|
||||||
|
else:
|
||||||
|
result_by_param[value] = 1
|
||||||
|
|
||||||
|
def mark_finalize(record):
|
||||||
|
new_record = {}
|
||||||
|
for key in ['id', 'metric', 'name']:
|
||||||
|
new_record[key] = record[key]
|
||||||
|
|
||||||
|
positive = 0
|
||||||
|
mark_distribution = []
|
||||||
|
for key in ['-2', '-1', '1', '2']:
|
||||||
|
if key in record:
|
||||||
|
if key in ['1', '2']:
|
||||||
|
positive += record[key]
|
||||||
|
mark_distribution.append(str(record[key]))
|
||||||
|
else:
|
||||||
|
mark_distribution.append('0')
|
||||||
|
|
||||||
|
new_record['comment'] = (
|
||||||
|
'|'.join(mark_distribution) +
|
||||||
|
' (%.1f%%)' % ((positive * 100.0) / record['metric']))
|
||||||
|
return new_record
|
||||||
|
|
||||||
metric_param = (flask.request.args.get('metric') or
|
metric_param = (flask.request.args.get('metric') or
|
||||||
get_default('metric'))
|
get_default('metric'))
|
||||||
metric = metric_param.lower()
|
metric = metric_param.lower()
|
||||||
if metric in ['commits', 'reviews', 'marks']:
|
aggregate_filter = None
|
||||||
metric_filter = lambda r: 1
|
|
||||||
|
if metric == 'commits':
|
||||||
|
metric_filter = commit_filter
|
||||||
elif metric == 'loc':
|
elif metric == 'loc':
|
||||||
metric_filter = lambda r: r['loc']
|
metric_filter = loc_filter
|
||||||
|
elif metric == 'marks':
|
||||||
|
metric_filter = mark_filter
|
||||||
|
aggregate_filter = mark_finalize
|
||||||
else:
|
else:
|
||||||
raise Exception('Invalid metric %s' % metric)
|
raise Exception('Invalid metric %s' % metric)
|
||||||
|
|
||||||
kwargs['metric_filter'] = metric_filter
|
kwargs['metric_filter'] = metric_filter
|
||||||
|
kwargs['finalize_handler'] = aggregate_filter
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
return aggregate_filter_decorated_function
|
return aggregate_filter_decorated_function
|
||||||
@ -471,16 +512,18 @@ def engineer_details(user_id, records):
|
|||||||
# AJAX Handlers ---------
|
# AJAX Handlers ---------
|
||||||
|
|
||||||
def _get_aggregated_stats(records, metric_filter, keys, param_id,
|
def _get_aggregated_stats(records, metric_filter, keys, param_id,
|
||||||
param_title=None):
|
param_title=None, finalize_handler=None):
|
||||||
param_title = param_title or param_id
|
param_title = param_title or param_id
|
||||||
result = dict((c, 0) for c in keys)
|
result = dict((c, {'metric': 0, 'id': c}) for c in keys)
|
||||||
titles = {}
|
|
||||||
for record in records:
|
for record in records:
|
||||||
result[record[param_id]] += metric_filter(record)
|
metric_filter(result, record, param_id)
|
||||||
titles[record[param_id]] = record[param_title]
|
result[record[param_id]]['name'] = record[param_title]
|
||||||
|
|
||||||
response = [{'id': r, 'metric': result[r], 'name': titles[r]}
|
if not finalize_handler:
|
||||||
for r in result if result[r]]
|
finalize_handler = lambda x: x
|
||||||
|
|
||||||
|
response = [finalize_handler(result[r]) for r in result
|
||||||
|
if result[r]['metric']]
|
||||||
response.sort(key=lambda x: x['metric'], reverse=True)
|
response.sort(key=lambda x: x['metric'], reverse=True)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@ -489,7 +532,7 @@ def _get_aggregated_stats(records, metric_filter, keys, param_id,
|
|||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
@aggregate_filter()
|
@aggregate_filter()
|
||||||
def get_companies(records, metric_filter):
|
def get_companies(records, metric_filter, finalize_handler):
|
||||||
response = _get_aggregated_stats(records, metric_filter,
|
response = _get_aggregated_stats(records, metric_filter,
|
||||||
get_memory_storage().get_companies(),
|
get_memory_storage().get_companies(),
|
||||||
'company_name')
|
'company_name')
|
||||||
@ -500,7 +543,7 @@ def get_companies(records, metric_filter):
|
|||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
@aggregate_filter()
|
@aggregate_filter()
|
||||||
def get_modules(records, metric_filter):
|
def get_modules(records, metric_filter, finalize_handler):
|
||||||
response = _get_aggregated_stats(records, metric_filter,
|
response = _get_aggregated_stats(records, metric_filter,
|
||||||
get_memory_storage().get_modules(),
|
get_memory_storage().get_modules(),
|
||||||
'module')
|
'module')
|
||||||
@ -511,10 +554,11 @@ def get_modules(records, metric_filter):
|
|||||||
@exception_handler()
|
@exception_handler()
|
||||||
@record_filter()
|
@record_filter()
|
||||||
@aggregate_filter()
|
@aggregate_filter()
|
||||||
def get_engineers(records, metric_filter):
|
def get_engineers(records, metric_filter, finalize_handler):
|
||||||
response = _get_aggregated_stats(records, metric_filter,
|
response = _get_aggregated_stats(records, metric_filter,
|
||||||
get_memory_storage().get_user_ids(),
|
get_memory_storage().get_user_ids(),
|
||||||
'user_id', 'author_name')
|
'user_id', 'author_name',
|
||||||
|
finalize_handler=finalize_handler)
|
||||||
return json.dumps(response)
|
return json.dumps(response)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user