layerindex-web/rrs/views.py
Paul Eggleton e071ebab29 rrs: add flag to MaintenancePlan to specify layer-wide maintainers
Most layers do not track maintenance on a per-recipe basis, and for
those layers we will hide some of the per-recipe maintainer features
and on the recipe detail show the layer maintainer(s) as the
maintainer(s) of the recipe.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
2018-05-04 23:57:53 +12:00

940 lines
39 KiB
Python

import urllib
import csv
from django.http import HttpResponse
from datetime import date, datetime
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.views.generic import TemplateView, ListView, DetailView, RedirectView
from django.core.urlresolvers import resolve, reverse, reverse_lazy
from django.db import connection
from layerindex.models import Recipe, StaticBuildDep, Patch
from rrs.models import Release, Milestone, Maintainer, RecipeMaintainerHistory, \
RecipeMaintainer, RecipeUpstreamHistory, RecipeUpstream, \
RecipeDistro, RecipeUpgrade, MaintenancePlan
class FrontPageRedirect(RedirectView):
permanent = False
def get_redirect_url(self):
maintplan = MaintenancePlan.objects.first()
if not maintplan:
raise Exception('No maintenance plans defined')
release = Release.get_current(maintplan)
if not release:
raise Exception('No releases defined for maintenance plan %s' % maintplan.name)
milestone = Milestone.get_current(release)
if not milestone:
raise Exception('No milestones defined for release %s' % release.name)
return reverse('rrs_recipes', args=(maintplan.name, release.name, milestone.name))
class MaintenancePlanRedirect(RedirectView):
permanent = False
def get_redirect_url(self, maintplan_name):
maintplan = get_object_or_404(MaintenancePlan, name=maintplan_name)
release = Release.get_current(maintplan)
if not release:
raise Exception('No releases defined for maintenance plan %s' % maintplan.name)
milestone = Milestone.get_current(release)
if not milestone:
raise Exception('No milestones defined for release %s' % release.name)
return reverse('rrs_recipes', args=(maintplan.name, release.name, milestone.name))
def _check_url_params(upstream_status, maintainer_name):
get_object_or_404(Maintainer, name=maintainer_name)
found = 0
for us in RecipeUpstream.RECIPE_UPSTREAM_STATUS_CHOICES_DICT.keys():
if us == 'D': # Downgrade is displayed as Unknown
continue
if RecipeUpstream.RECIPE_UPSTREAM_STATUS_CHOICES_DICT[us] == upstream_status:
found = 1
break
if found == 0:
raise Http404
def _get_layer_branch_url(branch, layer_name):
return reverse_lazy('layer_item', args=(branch, layer_name))
class Raw():
""" Raw SQL call to improve performance
Table abbrevations:
re: Recipe
ma: Maintainer
reup: Recipe Upstream
reupg: Recipe Ugrade
rema: Recipe Maintainer
remahi: Recipe Maintainer History
"""
@staticmethod
def get_re_by_mantainer_and_date(maintainer, date_id):
""" Get Recipes based on Maintainer and Recipe Maintainer History """
recipes = []
cur = connection.cursor()
cur.execute("""SELECT DISTINCT rema.recipe_id
FROM rrs_recipemaintainer AS rema
INNER JOIN rrs_maintainer AS ma
ON rema.maintainer_id = ma.id
WHERE rema.history_id = %s
AND ma.name = %s;
""", [date_id, maintainer])
for re in cur.fetchall():
recipes.append(re[0])
return recipes
@staticmethod
def get_ma_by_recipes_and_date(recipes_id, date_id=None):
""" Get Maintainer based on Recipes and Recipe Upstream History """
stats = []
recipes = str(recipes_id).strip('[]')
if date_id:
qry = """SELECT rema.recipe_id, ma.name
FROM rrs_recipemaintainer AS rema
INNER JOIN rrs_maintainer AS ma
ON rema.maintainer_id = ma.id"""
qry += "\nWHERE rema.history_id = '%s'" % str(date_id)
qry += "\nAND rema.recipe_id IN (%s);" % recipes
cur = connection.cursor()
cur.execute(qry)
stats = Raw.dictfetchall(cur)
return stats
@staticmethod
def get_reup_statistics(maintplan, date, date_id):
""" Special case to get recipes statistics removing gcc-source duplicates """
recipes = []
updated = 0
not_updated = 0
cant = 0
unknown = 0
for maintplanlayer in maintplan.maintenanceplanlayerbranch_set.all():
layerbranch = maintplanlayer.layerbranch
layerbranch_recipes = Raw.get_reupg_by_date(layerbranch.id, date)
for re in layerbranch_recipes:
recipes.append(re["id"])
if date_id and recipes:
recipes = str(recipes).strip('[]')
qry = """SELECT id, status, no_update_reason
FROM rrs_recipeupstream"""
qry += "\nWHERE history_id = '%s'" % str(date_id.id)
qry += "\nAND recipe_id IN (%s);" % recipes
cur = connection.cursor()
cur.execute(qry)
for re in Raw.dictfetchall(cur):
if re["status"] == "Y":
updated += 1
elif re["status"] == "N" and re["no_update_reason"] == "":
not_updated += 1
elif re["status"] == "N":
cant += 1
# We count downgrade as unknown
else:
unknown += 1
return (updated, not_updated, cant, unknown)
@staticmethod
def get_reup_by_recipes_and_date(recipes_id, date_id=None):
""" Get Recipe Upstream based on Recipes and Recipe Upstream History """
stats = []
recipes = str(recipes_id).strip('[]')
if date_id:
qry = """SELECT recipe_id, status, no_update_reason, version
FROM rrs_recipeupstream"""
qry += "\nWHERE history_id = '%s'" % str(date_id)
qry += "\nAND recipe_id IN (%s);" % recipes
cur = connection.cursor()
cur.execute(qry)
stats = Raw.dictfetchall(cur)
return stats
@staticmethod
def get_reup_by_last_updated(layerbranch_id, date):
""" Get last time the Recipes were upgraded """
cur = connection.cursor()
cur.execute("""SELECT recipe_id, MAX(commit_date) AS date
FROM rrs_recipeupgrade
INNER JOIN layerindex_recipe AS re
ON rrs_recipeupgrade.recipe_id = re.id
WHERE commit_date <= %s
AND re.layerbranch_id = %s
GROUP BY recipe_id;
""", [date, layerbranch_id])
return Raw.dictfetchall(cur)
@staticmethod
def get_reup_by_date(date_id):
""" Get Recipes not up to date based on Recipe Upstream History """
cur = connection.cursor()
cur.execute("""SELECT DISTINCT recipe_id
FROM rrs_recipeupstream
WHERE status = 'N'
AND history_id = %s
""", [date_id])
return [i[0] for i in cur.fetchall()]
@staticmethod
def get_reupg_by_date(layerbranch_id, date):
""" Get info for Recipes for the milestone """
cur = connection.cursor()
cur.execute("""SELECT re.id, re.pn, re.summary, te.version, rownum FROM (
SELECT recipe_id, version, commit_date, ROW_NUMBER() OVER(
PARTITION BY recipe_id
ORDER BY commit_date DESC
) AS rownum
FROM rrs_recipeupgrade
WHERE commit_date <= %s) AS te
INNER JOIN layerindex_recipe AS re
ON te.recipe_id = re.id
WHERE rownum = 1
AND re.layerbranch_id = %s
ORDER BY re.pn;
""", [date, layerbranch_id])
return Raw.dictfetchall(cur)
@staticmethod
def get_reupg_by_dates_and_recipes(start_date, end_date, recipes_id):
""" Get Recipe Upgrade for the milestone based on Recipes """
recipes = str(recipes_id).strip('[]')
cur = connection.cursor()
qry = """SELECT DISTINCT recipe_id
FROM rrs_recipeupgrade"""
qry += "\nWHERE commit_date >= '%s'" % str(start_date)
qry += "\nAND commit_date <= '%s'" % str(end_date)
qry += "\nAND recipe_id IN (%s);" % recipes
cur.execute(qry)
return Raw.dictfetchall(cur)
@staticmethod
def get_remahi_by_end_date(layerbranch_id, date):
""" Get the latest Recipe Maintainer History for the milestone """
cur = connection.cursor()
cur.execute("""SELECT id
FROM rrs_recipemaintainerhistory
WHERE date <= %s
AND layerbranch_id = %s
ORDER BY date DESC
LIMIT 1;
""", [str(date), layerbranch_id])
ret = cur.fetchone()
if not ret:
cur.execute("""SELECT id
FROM rrs_recipemaintainerhistory
WHERE layerbranch_id = %s
ORDER BY date
LIMIT 1;
""", [layerbranch_id])
ret = cur.fetchone()
return ret
@staticmethod
def dictfetchall(cursor):
"Returns all rows from a cursor as a dict"
desc = cursor.description
return [
dict(zip([col[0] for col in desc], row))
for row in cursor.fetchall()
]
def _get_milestone_statistics(milestone, maintainer_name=None):
milestone_statistics = {}
milestone_statistics['all'] = 0
milestone_statistics['up_to_date'] = 0
milestone_statistics['not_updated'] = 0
milestone_statistics['cant_be_updated'] = 0
milestone_statistics['unknown'] = 0
if maintainer_name is None:
milestone_statistics['all_upgraded'] = 0
milestone_statistics['all_not_upgraded'] = 0
for maintplanlayer in milestone.release.plan.maintenanceplanlayerbranch_set.all():
layerbranch = maintplanlayer.layerbranch
recipe_upstream_history = RecipeUpstreamHistory.get_last_by_date_range(
layerbranch,
milestone.start_date,
milestone.end_date
)
recipe_upstream_history_first = \
RecipeUpstreamHistory.get_first_by_date_range(
layerbranch,
milestone.start_date,
milestone.end_date,
)
if maintainer_name is None:
t_updated, t_not_updated, t_cant, t_unknown = \
Raw.get_reup_statistics(milestone.release.plan, milestone.end_date, recipe_upstream_history)
milestone_statistics['all'] += \
t_updated + t_not_updated + t_cant + t_unknown
milestone_statistics['up_to_date'] = +t_updated
milestone_statistics['not_updated'] = +t_not_updated
milestone_statistics['cant_be_updated'] += t_cant
milestone_statistics['unknown'] += t_unknown
if recipe_upstream_history_first:
recipes_not_upgraded = \
Raw.get_reup_by_date(recipe_upstream_history_first.id)
if recipes_not_upgraded:
recipes_upgraded = \
Raw.get_reupg_by_dates_and_recipes(
milestone.start_date, milestone.end_date, recipes_not_upgraded)
milestone_statistics['all_upgraded'] += len(recipes_upgraded)
milestone_statistics['all_not_upgraded'] += len(recipes_not_upgraded)
else:
recipe_maintainer_history = Raw.get_remahi_by_end_date(
layerbranch.id, milestone.end_date)
recipe_maintainer_all = Raw.get_re_by_mantainer_and_date(
maintainer_name, recipe_maintainer_history[0])
milestone_statistics['all'] += len(recipe_maintainer_all)
if recipe_upstream_history:
recipe_upstream_all = Raw.get_reup_by_recipes_and_date(
recipe_maintainer_all, recipe_upstream_history.id)
else:
recipe_upstream_all = Raw.get_reup_by_recipes_and_date(
recipe_maintainer_all)
for ru in recipe_upstream_all:
if ru['status'] == 'Y':
milestone_statistics['up_to_date'] += 1
elif ru['status'] == 'N':
if ru['no_update_reason'] == '':
milestone_statistics['not_updated'] += 1
else:
milestone_statistics['cant_be_updated'] += 1
else:
milestone_statistics['unknown'] += 1
milestone_statistics['percentage'] = '0'
if maintainer_name is None:
if milestone_statistics['all'] > 0:
milestone_statistics['percentage_up_to_date'] = "%.0f" % \
(float(milestone_statistics['up_to_date']) * 100.0 \
/float(milestone_statistics['all']))
milestone_statistics['percentage_not_updated'] = "%.0f" % \
(float(milestone_statistics['not_updated']) * 100.0 \
/float(milestone_statistics['all']))
milestone_statistics['percentage_cant_be_updated'] = "%.0f" % \
(float(milestone_statistics['cant_be_updated']) * 100.0 \
/float(milestone_statistics['all']))
milestone_statistics['percentage_unknown'] = "%.0f" % \
(float(milestone_statistics['unknown']) * 100.0
/float(milestone_statistics['all']))
if milestone_statistics['all_not_upgraded'] > 0:
milestone_statistics['percentage'] = "%.0f" % \
((float(milestone_statistics['all_upgraded']) * 100.0)
/float(milestone_statistics['all_not_upgraded']))
else:
milestone_statistics['percentage_up_to_date'] = "0"
milestone_statistics['percentage_not_updated'] = "0"
milestone_statistics['percentage_cant_be_updated'] = "0"
milestone_statistics['percentage_unknown'] = "0"
else:
if milestone_statistics['all'] > 0:
milestone_statistics['percentage'] = "%.0f" % \
((float(milestone_statistics['up_to_date']) /
float(milestone_statistics['all'])) * 100)
return milestone_statistics
class RecipeList():
pk = None
name = None
version = None
summary = None
upstream_status = None
upstream_version = None
outdated = None
maintainer_name = None
no_update_reason = None
def __init__(self, pk, name, summary):
self.pk = pk
self.name = name
self.summary = summary
def _get_recipe_list(milestone):
recipe_list = []
recipes_ids = []
recipe_upstream_dict_all = {}
recipe_last_updated_dict_all = {}
maintainers_dict_all = {}
current_date = date.today()
for maintplanlayer in milestone.release.plan.maintenanceplanlayerbranch_set.all():
layerbranch = maintplanlayer.layerbranch
recipe_maintainer_history = Raw.get_remahi_by_end_date(layerbranch.id,
milestone.end_date)
recipe_upstream_history = RecipeUpstreamHistory.get_last_by_date_range(
layerbranch,
milestone.start_date,
milestone.end_date
)
recipes = Raw.get_reupg_by_date(layerbranch.id, milestone.end_date)
for i,re in enumerate(recipes):
if 'pv' in re:
recipes[i]['version'] = re['pv']
recipes_ids.append(re['id'])
if recipes:
recipe_last_updated = Raw.get_reup_by_last_updated(
layerbranch.id, milestone.end_date)
for rela in recipe_last_updated:
recipe_last_updated_dict_all[rela['recipe_id']] = rela
if recipe_upstream_history:
recipe_upstream_all = Raw.get_reup_by_recipes_and_date(
recipes_ids, recipe_upstream_history.id)
for reup in recipe_upstream_all:
recipe_upstream_dict_all[reup['recipe_id']] = reup
if recipe_maintainer_history:
maintainers_all = Raw.get_ma_by_recipes_and_date(
recipes_ids, recipe_maintainer_history[0])
for ma in maintainers_all:
maintainers_dict_all[ma['recipe_id']] = ma['name']
for recipe in recipes:
upstream_version = ''
upstream_status = ''
no_update_reason = ''
outdated = ''
if recipe_upstream_history:
recipe_upstream = recipe_upstream_dict_all.get(recipe['id'])
if not recipe_upstream:
recipe_add = Recipe.objects.filter(id = recipe['id'])[0]
recipe_upstream_add = RecipeUpstream()
recipe_upstream_add.history = recipe_upstream_history
recipe_upstream_add.recipe = recipe_add
recipe_upstream_add.version = ''
recipe_upstream_add.type = 'M' # Manual
recipe_upstream_add.status = 'U' # Unknown
recipe_upstream_add.no_update_reason = ''
recipe_upstream_add.date = recipe_upstream_history.end_date
recipe_upstream_add.save()
recipe_upstream = {'version': '', 'status': 'U', 'type': 'M',
'no_update_reason': ''}
if recipe_upstream['status'] == 'N' and recipe_upstream['no_update_reason']:
recipe_upstream['status'] = 'C'
upstream_status = \
RecipeUpstream.RECIPE_UPSTREAM_STATUS_CHOICES_DICT[
recipe_upstream['status']]
if upstream_status == 'Downgrade':
upstream_status = 'Unknown' # Downgrade is displayed as Unknown
upstream_version = recipe_upstream['version']
no_update_reason = recipe_upstream['no_update_reason']
#Get how long the recipe hasn't been updated
recipe_last_updated = \
recipe_last_updated_dict_all.get(recipe['id'])
if recipe_last_updated:
recipe_date = recipe_last_updated['date']
outdated = recipe_date.date().isoformat()
else:
outdated = ""
maintainer_name = maintainers_dict_all.get(recipe['id'], '')
recipe_list_item = RecipeList(recipe['id'], recipe['pn'], recipe['summary'])
recipe_list_item.version = recipe['version']
recipe_list_item.upstream_status = upstream_status
recipe_list_item.upstream_version = upstream_version
recipe_list_item.outdated = outdated
patches = Patch.objects.filter(recipe__id=recipe['id'])
recipe_list_item.patches_total = patches.count()
recipe_list_item.patches_pending = patches.filter(status='P').count()
recipe_list_item.maintainer_name = maintainer_name
recipe_list_item.no_update_reason = no_update_reason
recipe_list.append(recipe_list_item)
return recipe_list
class RecipeListView(ListView):
context_object_name = 'recipe_list'
def get_queryset(self):
self.maintplan_name = self.kwargs['maintplan_name']
maintplan = get_object_or_404(MaintenancePlan, name=self.maintplan_name)
self.release_name = self.kwargs['release_name']
release = get_object_or_404(Release, plan=maintplan, name=self.release_name)
self.milestone_name = self.kwargs['milestone_name']
milestone = get_object_or_404(Milestone, release = release, name=self.milestone_name)
if 'upstream_status' in self.request.GET.keys():
self.upstream_status = self.request.GET['upstream_status']
else:
self.upstream_status = 'All'
if 'maintainer_name' in self.request.GET.keys():
self.maintainer_name = self.request.GET['maintainer_name']
else:
self.maintainer_name = 'All'
if 'search' in self.request.GET.keys():
self.search = self.request.GET['search']
# only allow one type of filter search or upstream_status/maintainer
self.upstream_status = 'All'
self.maintainer_name = 'All'
else:
self.search = ''
_check_url_params(self.upstream_status, self.maintainer_name)
self.milestone_statistics = _get_milestone_statistics(milestone)
self.recipe_maintainer_history = {}
for maintplanlayer in maintplan.maintenanceplanlayerbranch_set.all():
layerbranch = maintplanlayer.layerbranch
self.recipe_maintainer_history[layerbranch.id] = RecipeMaintainerHistory.get_by_end_date(layerbranch,
milestone.end_date)
recipe_list = _get_recipe_list(milestone)
self.recipe_list_count = len(recipe_list)
return recipe_list
def get_context_data(self, **kwargs):
context = super(RecipeListView, self).get_context_data(**kwargs)
context['this_url_name'] = resolve(self.request.path_info).url_name
context['all_maintplans'] = MaintenancePlan.objects.all()
context['maintplan_name'] = self.maintplan_name
maintplan = get_object_or_404(MaintenancePlan, name=self.maintplan_name)
context['maintplan'] = maintplan
context['release_name'] = self.release_name
context['all_releases'] = Release.objects.filter(plan=maintplan).order_by('-end_date')
context['milestone_name'] = self.milestone_name
context['all_milestones'] = Milestone.get_by_release_name(maintplan, self.release_name)
context['recipes_percentage'] = self.milestone_statistics['percentage']
context['recipes_all_upgraded'] = self.milestone_statistics['all_upgraded']
context['recipes_all_not_upgraded'] = self.milestone_statistics['all_not_upgraded']
context['recipes_up_to_date'] = self.milestone_statistics['up_to_date']
context['recipes_not_updated'] = self.milestone_statistics['not_updated']
context['recipes_cant_be_updated'] = self.milestone_statistics['cant_be_updated']
context['recipes_unknown'] = self.milestone_statistics['unknown']
context['recipes_percentage_up_to_date'] = \
self.milestone_statistics['percentage_up_to_date']
context['recipes_percentage_not_updated'] = \
self.milestone_statistics['percentage_not_updated']
context['recipes_percentage_cant_be_updated'] = \
self.milestone_statistics['percentage_cant_be_updated']
context['recipes_percentage_unknown'] = \
self.milestone_statistics['percentage_unknown']
context['recipe_list_count'] = self.recipe_list_count
context['upstream_status'] = self.upstream_status
ruch = RecipeUpstream.RECIPE_UPSTREAM_STATUS_CHOICES_DICT
context['upstream_status_set_choices'] = [ruch['A']]
context['upstream_status_choices'] = [ruch['N'], ruch['C'], ruch['Y'], ruch['U']]
context['maintainer_name'] = self.maintainer_name
context['set_maintainers'] = ['All', 'No maintainer']
all_maintainers = []
for layerbranch_id, rmh in self.recipe_maintainer_history.items():
for rm in RecipeMaintainer.objects.filter(history=rmh).values(
'maintainer__name').distinct().order_by('maintainer__name'):
if rm['maintainer__name'] in context['set_maintainers']:
continue
all_maintainers.append(rm['maintainer__name'])
context['all_maintainers'] = all_maintainers
context['search'] = self.search
return context
def recipes_report(request, maintplan_name, release_name, milestone_name):
maintplan = get_object_or_404(MaintenancePlan, name=maintplan_name)
release = get_object_or_404(Release, plan=maintplan, name=release_name)
milestone = get_object_or_404(Milestone, release = release, name=milestone_name)
recipe_list = _get_recipe_list(milestone)
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="%s_%s.csv"' % (
release_name , milestone_name)
writer = csv.writer(response)
writer.writerow(['Upstream status', 'Name', 'Version',
'Upstream version', 'Maintainer', 'Summary'])
for r in recipe_list:
writer.writerow([r.upstream_status, r.name, r.version,
r.upstream_version, r.maintainer_name.encode('utf-8'), r.summary])
return response
class RecipeUpgradeDetail():
title = None
version = None
maintplan_name = None
release_name = None
milestone_name = None
date = None
maintainer_name = None
is_recipe_maintainer = None
commit = None
commit_url = None
def __init__(self, title, version, maintplan_name, release_name, milestone_name, date,
maintainer_name, is_recipe_maintainer, commit, commit_url):
self.title = title
self.version = version
self.maintplan_name = maintplan_name
self.release_name = release_name
self.milestone_name = milestone_name
self.date = date
self.maintainer_name = maintainer_name
self.is_recipe_maintainer = is_recipe_maintainer
self.commit = commit
self.commit_url = commit_url
def _get_recipe_upgrade_detail(maintplan, recipe_upgrade):
release_name = ''
milestone_name = ''
recipe_maintainer_history = None
release = Release.get_by_date(maintplan, recipe_upgrade.commit_date)
if release:
release_name = release.name
milestone = Milestone.get_by_release_and_date(release,
recipe_upgrade.commit_date)
if milestone:
milestone_name = milestone.name
recipe_maintainer_history = RecipeMaintainerHistory.get_by_end_date(
recipe_upgrade.recipe.layerbranch,
milestone.end_date)
is_recipe_maintainer = False
maintainer_name = ''
if not recipe_upgrade.maintainer is None:
maintainer_name = recipe_upgrade.maintainer.name
if not recipe_maintainer_history is None and \
RecipeMaintainer.objects.filter(maintainer__name
= maintainer_name, history = recipe_maintainer_history) \
.count() > 0:
is_recipe_maintainer = True
commit_date = recipe_upgrade.commit_date.date().isoformat()
commit = recipe_upgrade.sha1[:10]
commit_url = recipe_upgrade.recipe.layerbranch.commit_url(recipe_upgrade.sha1)
rud = RecipeUpgradeDetail(recipe_upgrade.title, recipe_upgrade.version, \
maintplan.name, release_name, milestone_name, commit_date, maintainer_name, \
is_recipe_maintainer, commit, commit_url)
return rud
class RecipeDetailView(DetailView):
model = Recipe
def get_queryset(self):
self.maintplan_name = self.kwargs['maintplan_name']
return super(RecipeDetailView, self).get_queryset()
def get_context_data(self, **kwargs):
context = super(RecipeDetailView, self).get_context_data(**kwargs)
recipe = self.get_object()
if not recipe:
raise django.http.Http404
maintplan = get_object_or_404(MaintenancePlan, name=self.maintplan_name)
context['maintplan_name'] = maintplan.name
context['maintplan'] = maintplan
release = Release.get_current(maintplan)
context['release_name'] = release.name
milestone = Milestone.get_current(release)
context['milestone_name'] = milestone.name
context['upstream_status'] = ''
context['upstream_version'] = ''
context['upstream_no_update_reason'] = ''
recipe_upstream_history = RecipeUpstreamHistory.get_last_by_date_range(
recipe.layerbranch,
milestone.start_date,
milestone.end_date
)
if recipe_upstream_history:
recipe_upstream = RecipeUpstream.get_by_recipe_and_history(
recipe, recipe_upstream_history)
if recipe_upstream:
if recipe_upstream.status == 'N' and recipe_upstream.no_update_reason:
recipe_upstream.status = 'C'
elif recipe_upstream.status == 'D':
recipe_upstream.status = 'U'
context['upstream_status'] = \
RecipeUpstream.RECIPE_UPSTREAM_STATUS_CHOICES_DICT[recipe_upstream.status]
context['upstream_version'] = recipe_upstream.version
context['upstream_no_update_reason'] = recipe_upstream.no_update_reason
self.recipe_maintainer_history = RecipeMaintainerHistory.get_last(recipe.layerbranch)
recipe_maintainer = RecipeMaintainer.objects.filter(recipe = recipe,
history = self.recipe_maintainer_history)
if recipe_maintainer:
maintainer = recipe_maintainer[0].maintainer
context['maintainer_name'] = maintainer.name
else:
context['maintainer_name'] = 'No maintainer'
context['recipe_upgrade_details'] = []
for ru in RecipeUpgrade.objects.filter(recipe =
recipe).order_by('-commit_date'):
context['recipe_upgrade_details'].append(_get_recipe_upgrade_detail(maintplan, ru))
context['recipe_upgrade_detail_count'] = len(context['recipe_upgrade_details'])
context['recipe_layer_branch_url'] = _get_layer_branch_url(
recipe.layerbranch.branch.name, recipe.layerbranch.layer.name)
context['recipe_provides'] = []
for p in recipe.provides.split():
context['recipe_provides'].append(p)
context['recipe_depends'] = StaticBuildDep.objects.filter(recipes__id=recipe.id).values_list('name', flat=True)
context['recipe_distros'] = RecipeDistro.get_distros_by_recipe(recipe)
return context
class MaintainerList():
name = None
recipes_all = 0
recipes_up_to_date = '0'
recipes_not_updated = '0'
recipes_cant_be_updated = '0'
recipes_unknown = '0'
percentage_done = '0.00'
interval_statistics = None
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.maintplan_name = self.kwargs['maintplan_name']
maintplan = get_object_or_404(MaintenancePlan, name=self.maintplan_name)
self.release_name = self.kwargs['release_name']
release = get_object_or_404(Release, plan=maintplan, name=self.release_name)
self.milestone_name = self.kwargs['milestone_name']
milestone = get_object_or_404(Milestone, release = release,
name=self.milestone_name)
if "All" in milestone.name:
intervals = milestone.get_milestone_intervals(release)
interval_type = 'Milestone'
else:
intervals = milestone.get_week_intervals()
interval_type = 'Week'
self.milestone_statistics = _get_milestone_statistics(milestone)
self.maintainer_count = 0
for maintplanlayer in maintplan.maintenanceplanlayerbranch_set.all():
layerbranch = maintplanlayer.layerbranch
recipe_maintainer_history = RecipeMaintainerHistory.get_by_end_date(
layerbranch, 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)
self.intervals = sorted(intervals.keys())
current_date = date.today()
for ml in maintainer_list:
milestone_statistics = _get_milestone_statistics(milestone, ml.name)
ml.recipes_all = milestone_statistics['all']
ml.recipes_up_to_date = ('' if milestone_statistics['up_to_date'] == 0
else milestone_statistics['up_to_date'])
ml.recipes_not_updated = ('' if milestone_statistics['not_updated'] == 0
else milestone_statistics['not_updated'])
ml.recipes_cant_be_updated = ('' if milestone_statistics['cant_be_updated'] == 0
else milestone_statistics['cant_be_updated'])
ml.recipes_unknown = ('' if milestone_statistics['unknown'] == 0
else milestone_statistics['unknown'])
ml.percentage_done = milestone_statistics['percentage'] + '%'
ml.interval_statistics = []
self.current_interval = -1
for idx, i in enumerate(sorted(intervals.keys())):
start_date = intervals[i]['start_date']
end_date = intervals[i]['end_date']
if current_date >= start_date and current_date <= end_date:
self.current_interval = idx
number = RecipeUpgrade.objects.filter(maintainer__name = ml.name,
commit_date__gte = start_date,
commit_date__lte = end_date).count()
ml.interval_statistics.append('' if number == 0 else number)
# To add Wk prefix after get statics to avoid sorting problems
if interval_type == 'Week':
self.intervals = ['Wk' + str(i) for i in self.intervals]
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['all_maintplans'] = MaintenancePlan.objects.all()
context['maintplan_name'] = self.maintplan_name
maintplan = get_object_or_404(MaintenancePlan, name=self.maintplan_name)
context['release_name'] = self.release_name
context['all_releases'] = Release.objects.filter(plan=maintplan).order_by('-end_date')
context['milestone_name'] = self.milestone_name
context['all_milestones'] = Milestone.get_by_release_name(maintplan, self.release_name)
context['recipes_percentage'] = self.milestone_statistics['percentage']
context['recipes_all_upgraded'] = self.milestone_statistics['all_upgraded']
context['recipes_all_not_upgraded'] = self.milestone_statistics['all_not_upgraded']
context['recipes_up_to_date'] = self.milestone_statistics['up_to_date']
context['recipes_not_updated'] = self.milestone_statistics['not_updated']
context['recipes_cant_be_updated'] = self.milestone_statistics['cant_be_updated']
context['recipes_unknown'] = self.milestone_statistics['unknown']
context['recipes_percentage_up_to_date'] = \
self.milestone_statistics['percentage_up_to_date']
context['recipes_percentage_not_updated'] = \
self.milestone_statistics['percentage_not_updated']
context['recipes_percentage_cant_be_updated'] = \
self.milestone_statistics['percentage_cant_be_updated']
context['recipes_percentage_unknown'] = \
self.milestone_statistics['percentage_unknown']
context['maintainer_count'] = self.maintainer_count
context['intervals'] = self.intervals
context['interval_range'] = range(len(self.intervals))
if hasattr(self, 'current_interval'):
context['current_interval'] = self.current_interval
return context
class MaintenanceStatsView(TemplateView):
def get_context_data(self, **kwargs):
context = super(MaintenanceStatsView, self).get_context_data(**kwargs)
context['this_url_name'] = resolve(self.request.path_info).url_name
self.maintplan_name = self.kwargs['maintplan_name']
maintplan = get_object_or_404(MaintenancePlan, name=self.maintplan_name)
self.release_name = self.kwargs['release_name']
release = get_object_or_404(Release, plan=maintplan, name=self.release_name)
self.milestone_name = self.kwargs['milestone_name']
milestone = get_object_or_404(Milestone, release = release, name=self.milestone_name)
self.milestone_statistics = _get_milestone_statistics(milestone)
context['recipes_percentage'] = self.milestone_statistics['percentage']
context['recipes_all_upgraded'] = self.milestone_statistics['all_upgraded']
context['recipes_all_not_upgraded'] = self.milestone_statistics['all_not_upgraded']
context['recipes_up_to_date'] = self.milestone_statistics['up_to_date']
context['recipes_not_updated'] = self.milestone_statistics['not_updated']
context['recipes_cant_be_updated'] = self.milestone_statistics['cant_be_updated']
context['recipes_unknown'] = self.milestone_statistics['unknown']
context['recipes_percentage_up_to_date'] = \
self.milestone_statistics['percentage_up_to_date']
context['recipes_percentage_not_updated'] = \
self.milestone_statistics['percentage_not_updated']
context['recipes_percentage_cant_be_updated'] = \
self.milestone_statistics['percentage_cant_be_updated']
context['recipes_percentage_unknown'] = \
self.milestone_statistics['percentage_unknown']
# *** Upstream status chart ***
statuses = []
status_counts = {}
statuses.append('Up-to-date')
status_counts['Up-to-date'] = self.milestone_statistics['up_to_date']
statuses.append('Not updated')
status_counts['Not updated'] = self.milestone_statistics['not_updated']
statuses.append('Can\'t be updated')
status_counts['Can\'t be updated'] = self.milestone_statistics['cant_be_updated']
statuses.append('Unknown')
status_counts['Unknown'] = self.milestone_statistics['unknown']
statuses = sorted(statuses, key=lambda status: status_counts[status], reverse=True)
chartdata = {'x': statuses, 'y': [status_counts[k] for k in statuses]}
context['charttype_status'] = 'discreteBarChart'
context['chartdata_status'] = chartdata
context['extra_status'] = {
'x_is_date': False,
'x_axis_format': '',
'tag_script_js': True,
'jquery_on_ready': False,
}
# *** Patch status chart ***
patch_statuses = []
patch_status_counts = {}
for maintplanlayer in maintplan.maintenanceplanlayerbranch_set.all():
layerbranch = maintplanlayer.layerbranch
patches = Patch.objects.filter(recipe__layerbranch=layerbranch)
for choice, desc in Patch.PATCH_STATUS_CHOICES:
if desc not in patch_statuses:
patch_statuses.append(desc)
patch_status_counts[desc] = patch_status_counts.get(desc, 0) + patches.filter(status=choice).count()
patch_statuses = sorted(patch_statuses, key=lambda status: patch_status_counts[status], reverse=True)
chartdata = {'x': patch_statuses, 'y': [patch_status_counts[k] for k in patch_statuses]}
context['charttype_patchstatus'] = 'discreteBarChart'
context['chartdata_patchstatus'] = chartdata
context['extra_patchstatus'] = {
'x_is_date': False,
'x_axis_format': '',
'tag_script_js': True,
'jquery_on_ready': False,
}
return context