rrs: Add Maintainer statistics page.

Maintainer statistics page gives information by Milestone and
Maintainers assigned recipes, status of recipes (up-to-date,
not-update, unknown) and percertange of work done.

Signed-off-by: Aníbal Limón <anibal.limon@linux.intel.com>
This commit is contained in:
Aníbal Limón 2015-01-29 18:13:28 -06:00 committed by Paul Eggleton
parent 6dfc369f29
commit dc38557582
4 changed files with 205 additions and 8 deletions

View File

@ -1,7 +1,7 @@
from django.conf.urls import patterns, include, url from django.conf.urls import patterns, include, url
from rrs.models import Milestone from rrs.models import Milestone
from rrs.views import RecipeListView, RecipeDetailView from rrs.views import RecipeListView, RecipeDetailView, MaintainerListView
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', redirect_to, {'url' : reverse_lazy('recipes', args=(Milestone.get_current().name,))}, url(r'^$', redirect_to, {'url' : reverse_lazy('recipes', args=(Milestone.get_current().name,))},
@ -14,4 +14,8 @@ urlpatterns = patterns('',
RecipeDetailView.as_view( RecipeDetailView.as_view(
template_name='rrs/recipedetail.html'), template_name='rrs/recipedetail.html'),
name='recipedetail'), name='recipedetail'),
url(r'^maintainers/(?P<milestone_name>.*)/$',
MaintainerListView.as_view(
template_name='rrs/maintainers.html'),
name="maintainers"),
) )

View File

@ -26,7 +26,7 @@ def _get_layer_branch_url(branch, layer_name):
return ("http://layers.openembedded.org/layerindex/branch/%s/layer/%s/"\ return ("http://layers.openembedded.org/layerindex/branch/%s/layer/%s/"\
% (branch, layer_name)) % (branch, layer_name))
def _get_milestone_statistics(milestone): def _get_milestone_statistics(milestone, maintainer_name=None):
milestone_statistics = {} milestone_statistics = {}
recipe_upstream_history = RecipeUpstreamHistory.get_last_by_date_range( recipe_upstream_history = RecipeUpstreamHistory.get_last_by_date_range(
@ -35,22 +35,51 @@ def _get_milestone_statistics(milestone):
) )
if recipe_upstream_history is None: if recipe_upstream_history is None:
milestone_statistics['all'] = '0'
milestone_statistics['up_to_date'] = '0' milestone_statistics['up_to_date'] = '0'
milestone_statistics['not_updated'] = '0' milestone_statistics['not_updated'] = '0'
milestone_statistics['unknown'] = '0' milestone_statistics['unknown'] = '0'
milestone_statistics['percentage'] = '0.0' milestone_statistics['percentage'] = '0.0'
else: elif maintainer_name is None:
recipes_all = RecipeUpstream.objects.filter(history = recipe_count = RecipeUpstream.objects.filter(history =
recipe_upstream_history).count() recipe_upstream_history).count()
milestone_statistics['all'] = recipe_count
milestone_statistics['up_to_date'] = RecipeUpstream.objects.filter( milestone_statistics['up_to_date'] = RecipeUpstream.objects.filter(
history = recipe_upstream_history, status = 'Y').count() history = recipe_upstream_history, status = 'Y').count()
milestone_statistics['not_updated'] = RecipeUpstream.objects.filter( milestone_statistics['not_updated'] = RecipeUpstream.objects.filter(
history = recipe_upstream_history, status = 'N').count() history = recipe_upstream_history, status = 'N').count()
milestone_statistics['unknown'] = recipes_all - \ milestone_statistics['unknown'] = milestone_statistics['all'] - \
(milestone_statistics['up_to_date'] + milestone_statistics['not_updated']) (milestone_statistics['up_to_date'] + milestone_statistics['not_updated'])
milestone_statistics['percentage'] = "%.2f" % \ milestone_statistics['percentage'] = "%.2f" % \
((float(milestone_statistics['up_to_date']) / float(recipes_all)) * 100) ((float(milestone_statistics['up_to_date']) /
float(milestone_statistics['all'])) * 100)
else:
recipe_maintainer_history = RecipeMaintainerHistory.get_by_end_date(
milestone.end_date)
recipes_all = []
for rm in RecipeMaintainer.objects.filter(history = recipe_maintainer_history,
maintainer__name = maintainer_name):
ru = RecipeUpstream.objects.filter(recipe = rm.recipe, history =
recipe_upstream_history)[0]
recipes_all.append(ru)
milestone_statistics['all'] = len(recipes_all)
milestone_statistics['up_to_date'] = 0
milestone_statistics['not_updated'] = 0
milestone_statistics['unknown'] = 0
for ru in recipes_all:
if ru.status == 'Y':
milestone_statistics['up_to_date'] += 1
elif ru.status == 'N':
milestone_statistics['not_updated'] += 1
else:
milestone_statistics['unknown'] += 1
milestone_statistics['percentage'] = "%.2f" % \
((float(milestone_statistics['up_to_date']) /
float(milestone_statistics['all'])) * 100)
return milestone_statistics return milestone_statistics
@ -266,3 +295,64 @@ class RecipeDetailView(DetailView):
context['recipe_distros'] = RecipeDistro.get_distros_by_recipe(recipe) context['recipe_distros'] = RecipeDistro.get_distros_by_recipe(recipe)
return context return context
class MaintainerList():
name = None
recipes_all = 0
recipes_up_to_date = '0'
recipes_not_updated = '0'
recipes_unknown = '0'
percentage_done = '0.00'
def __init__(self, name):
self.name = name
class MaintainerListView(ListView):
context_object_name = 'maintainer_list'
def get_queryset(self):
maintainer_list = []
self.maintainer_count = 0
self.milestone_name = self.kwargs['milestone_name']
milestone = get_object_or_404(Milestone, name=self.milestone_name)
self.milestone_statistics = _get_milestone_statistics(milestone)
recipe_maintainer_history = RecipeMaintainerHistory.get_by_end_date(
milestone.end_date)
if recipe_maintainer_history:
for rm in RecipeMaintainer.objects.filter(history =
recipe_maintainer_history).values(
'maintainer__name').distinct().order_by('maintainer__name'):
maintainer_list.append(MaintainerList(rm['maintainer__name']))
self.maintainer_count = len(maintainer_list)
for ml in maintainer_list:
milestone_statistics = _get_milestone_statistics(milestone, ml.name)
ml.recipes_all = milestone_statistics['all']
ml.recipes_up_to_date = milestone_statistics['up_to_date']
ml.recipes_not_updated = milestone_statistics['not_updated']
ml.recipes_unknown = milestone_statistics['unknown']
ml.percentage_done = milestone_statistics['percentage']
return maintainer_list
def get_context_data(self, **kwargs):
context = super(MaintainerListView, self).get_context_data(**kwargs)
context['this_url_name'] = resolve(self.request.path_info).url_name
context['milestone_name'] = self.milestone_name
context['all_milestones'] = Milestone.objects.filter().order_by('-id')
context['recipes_percentage'] = self.milestone_statistics['percentage']
context['recipes_up_to_date'] = self.milestone_statistics['up_to_date']
context['recipes_not_updated'] = self.milestone_statistics['not_updated']
context['recipes_unknown'] = self.milestone_statistics['unknown']
context['maintainer_count'] = self.maintainer_count
return context

View File

@ -56,18 +56,22 @@
<ul class="nav nav-pills"> <ul class="nav nav-pills">
{% if this_url_name == 'recipes' %} {% if this_url_name == 'recipes' %}
<li class="active"> <li class="active">
<a href="#">
{% else %} {% else %}
<li> <li>
<a href="{% url 'recipes' milestone_name %}{{ extra_url_param }}">
{% endif %} {% endif %}
<a href="{% url this_url_name milestone_name %}{{ extra_url_param }}">Recipes status</a> Recipes status</a>
</li> </li>
{% if this_url_name == 'maintainers' %} {% if this_url_name == 'maintainers' %}
<li class="active"> <li class="active">
<a href="#">
{% else %} {% else %}
<li> <li>
<a href="{% url 'maintainers' milestone_name %}">
{% endif %} {% endif %}
<a href="#">Maintainer statistics</a> Maintainer statistics</a>
</li> </li>
</ul> </ul>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,99 @@
{% extends "rrs/base_toplevel.html" %}
{% load i18n %}
{% load staticfiles %}
{% load url from future %}
{% comment %}
rrs-web - maintainers page template
Copyright (C) 2015 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
{% block navs %}
{% endblock %}
{% block content_inner %}
<div class="navbar navbar-table-controls">
<div class="navbar-inner table-controls">
<ul class="nav">
<li class="dropdown">
<span class="badge" style="margin-top:11px;">{{ maintainer_count }} maintainers</span>
</li>
</ul>
<form class="navbar-form pull-right">
<input type="text" class="input-xxlarge pull-right" placeholder="Search maintainers" id="filter">
</form>
</div>
</div>
{% if maintainer_count == 0 %}
<div class="alert"> No maintainers found</div>
{% else %}
<table class="table table-bordered table-hover statisticstable">
<thead>
<tr>
<th>Maintainer</th>
<th class="muted">Assigned recipes</th>
<th class="muted">Up-to-date</th>
<th>Not updated</th>
<th class="muted">Unknown</th>
<th>% done</th>
<th class="current-wk">wk1</th>
<th class="muted">wk2</th>
<th class="muted">wk3</th>
<th class="muted">wk4</th>
</tr>
</thead>
<tbody>
{% for ml in maintainer_list %}
<tr>
<td>
<a href="{% url 'recipes' milestone_name %}?maintainer_name={{ ml.name|urlencode }}">
{{ ml.name }}
</a>
</td>
<td>{{ ml.recipes_all }}</td>
<td>
<a href="{% url 'recipes' milestone_name %}?upstream_status={{ "Up-to-date"|urlencode }}&maintainer_name={{ ml.name|urlencode }}">
{{ ml.recipes_up_to_date }}
</a>
</td>
<td>
<a href="{% url 'recipes' milestone_name %}?upstream_status={{ "Not updated"|urlencode }}&maintainer_name={{ ml.name|urlencode }}">
{{ ml.recipes_not_updated }}
</a>
</td>
<td>
<a href="{% url 'recipes' milestone_name %}?upstream_status={{ "Unknown"|urlencode }}&maintainer_name={{ ml.name|urlencode }}">
{{ ml.recipes_unknown }}
</a>
</td>
<td>{{ ml.percentage_done }}</td>
<td class="current-wk"></td>
<td></td>
<td></td>
<td></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endblock %}
{% block scripts %}
{% if maintainer_count > 0 %}
<script src="{% static "js/uitablefilter.js" %}"></script>
<script>
$(document).ready(function() {
$("#filter").keyup(function() {
var table = $('.statisticstable');
$.uiTableFilter(table, this.value);
});
});
</script>
{% endif %}
{% endblock %}