scrutiny/scrutiny/projects/views.py

312 lines
12 KiB
Python

import datetime
import json
import re
from django.http import HttpResponse
from django.utils import timezone
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from .models import Project, InstalledService, Module, InstalledVersion
from .utils import CommitAndIssues, decorate_commit_line
class ProjectDetailView(DetailView):
model = Project
def get_context_data(self, **kwargs):
context = super(ProjectDetailView, self).get_context_data(**kwargs)
platforms = self.object.platform_set.all()
services = self.object.service_set.all()
context['platforms'] = platforms
context['services'] = services
return context
class ModuleDiffView(TemplateView):
template_name = 'projects/diff.html'
def get_context_data(self, name, commit1, commit2, **kwargs):
context = super(ModuleDiffView, self).get_context_data(**kwargs)
context['module'] = Module.objects.get(name=name)
context['commit1'] = commit1
context['commit2'] = commit2
context['difflog'] = '\n'.join(
[decorate_commit_line(line) for line in \
context['module'].get_diff_log(commit1, commit2).splitlines()])
return context
class ModuleIssuesView(TemplateView):
template_name = 'projects/issues.html'
def get_context_data(self, name, commit1, commit2, **kwargs):
context = super(ModuleIssuesView, self).get_context_data(**kwargs)
context['module'] = Module.objects.get(name=name)
context['commit1'] = commit1
context['commit2'] = commit2
commits = CommitAndIssues.get_for_commits(
context['module'], commit1, commit2)
issues = {}
for commit in commits:
for issue in commit.issues:
if not int(issue.id) in issues:
issues[int(issue.id)] = issue
else:
issue = issues[int(issue.id)]
issue.add_commit(commit)
issues_list = list(issues.items())
issues_list.sort()
context['issues'] = [x[1] for x in issues_list]
return context
class ProjectHistoryView(DetailView):
model = Project
template_name_suffix = '_history'
def get_context_data(self, **kwargs):
context = super(ProjectHistoryView, self).get_context_data(**kwargs)
installed_versions = InstalledVersion.objects.filter(
service__platform__project=self.object).order_by('-timestamp')[:1000]
context['installed_versions'] = installed_versions
return context
class ProjectSummaryHistoryView(DetailView):
model = Project
template_name_suffix = '_summary_history'
# XXX: add an 'interesting' attribute to module model?
interesting_modules = [
'publik-base-theme', 'combo', 'wcs', 'hobo', 'authentic2',
'welco', 'chrono', 'corbo', 'passerelle', 'fargo',
]
def get_context_data(self, **kwargs):
context = super(ProjectSummaryHistoryView, self).get_context_data(**kwargs)
platforms = list(self.get_object().platform_set.all())
platform = platforms[-1]
installed_versions = list(InstalledVersion.objects.filter(
timestamp__gt=timezone.now() - datetime.timedelta(days=120),
version__module__name__in=self.interesting_modules,
service__platform=platform).exclude(
version__version='').order_by('-timestamp')[:1000])
installed_versions.reverse()
versions_and_day = {}
for installed in installed_versions:
installed_day = installed.timestamp.strftime('%Y-%m-%d')
if not installed_day in versions_and_day:
versions_and_day[installed_day] = {
'modules': {},
'day': installed.timestamp.date()
}
if installed.version.module.name in versions_and_day[installed_day]['modules']:
continue
versions_and_day[installed_day]['modules'][installed.version.module.name] = {
'name': installed.version.module.name,
'current_version': installed.version.version,
}
versions_sorted_by_day = list(versions_and_day.values())
versions_sorted_by_day.sort(key=lambda x: x.get('day'))
previous_versions = {}
for version_and_day in versions_sorted_by_day:
for module_name, module_versions in list(version_and_day['modules'].items()):
if module_name in previous_versions:
module_versions['previous_version'] = previous_versions[module_name]
if module_versions['previous_version'] == module_versions['current_version']:
del version_and_day['modules'][module_name]
else:
del version_and_day['modules'][module_name]
previous_versions[module_name] = module_versions['current_version']
if len(platforms) > 1:
validation_platform = platforms[-2]
future_versions = {
'modules': {},
'day': 'future'
}
module_names = previous_versions.keys()
for module_name in module_names:
try:
installed_version = InstalledVersion.objects.filter(
version__module__name=module_name,
service__platform=validation_platform).exclude(
version__version='').order_by('-timestamp')[0]
except IndexError:
continue
if not installed_version.version.version:
continue
if installed_version.version.version == previous_versions[module_name]:
continue
future_versions['modules'][module_name] = {
'name': module_name,
'previous_version': previous_versions[module_name],
'current_version': installed_version.version.version,
}
if future_versions['modules']:
versions_sorted_by_day.append(future_versions)
context['platform'] = platform
context['history'] = reversed(versions_sorted_by_day)
return context
class ModulesView(TemplateView):
template_name = 'projects/modules.html'
def get_context_data(self, **kwargs):
context = super(ModulesView, self).get_context_data(**kwargs)
context['modules'] = Module.objects.all().order_by('name')
return context
def try_int(x):
try:
return int(x)
except ValueError:
return 0
version_re = re.compile(r'[\.\+-]d?e?v?')
def cmp_version(v1, v2):
return cmp([try_int(x) for x in version_re.split(v1.version.version)],
[try_int(x) for x in version_re.split(v2.version.version)])
class ModuleDeploymentsView(TemplateView):
template_name = 'projects/deployments.html'
def get_context_data(self, name, **kwargs):
context = super(ModuleDeploymentsView, self).get_context_data(**kwargs)
context['versions'] = []
context['module'] = Module.objects.get(name=name)
module = context['module']
for service in InstalledService.objects.all():
version = module.get_installed_version(service.platform, service.service)
if version and not version in context['versions']:
if version.version.version:
context['versions'].append(version)
context['versions'].sort(lambda x, y: cmp_version(x, y))
return context
def module_deployments_json(request, name, **kwargs):
response = HttpResponse(content_type='application/json')
installed_versions = []
module = Module.objects.get(name=name)
for service in InstalledService.objects.all():
version = module.get_installed_version(service.platform, service.service)
if version and not version in installed_versions:
installed_versions.append(version)
json.dump([{'version': x.version.version,
'project': x.service.platform.project.slug,
'service': x.service.service.slug,
'platform': x.service.platform.slug} for x in installed_versions],
response)
return response
class IssuesSnippet(TemplateView):
template_name = 'projects/issues_snippet.html'
@csrf_exempt
def dispatch(self, *args, **kwargs):
return super(IssuesSnippet, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
return self.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(IssuesSnippet, self).get_context_data(**kwargs)
modules = json.loads(self.request.read().decode('utf-8'))
issues = {}
for module_info in modules.values():
module = Module.objects.get(name=module_info['name'])
if not module.repository_url:
continue
commits = CommitAndIssues.get_for_commits(
module,
str(module_info.get('previous_version')),
str(module_info.get('current_version')))
for commit in commits:
for issue in commit.issues:
if issue.subject == '---': # private issue
continue
if not int(issue.id) in issues:
issues[int(issue.id)] = issue
else:
issue = issues[int(issue.id)]
if not hasattr(issues[int(issue.id)], 'modules'):
issues[int(issue.id)].modules = {}
issues[int(issue.id)].modules[module_info['name']] = True
context['issues'] = list(issues.values())
context['issues'].sort(key=lambda x: x.closed_on)
context['issues'].reverse() # most recent on top
return context
def api_issues_json(request, *args, **kwargs):
response = HttpResponse(content_type='application/json')
data = {}
for module in Module.objects.all():
try:
git_log = module.get_git_log()
except OSError:
continue
git_log_hashes = [x[0][:7] for x in git_log]
for line in git_log:
if not unicode(line[1], 'utf-8', 'ignore').endswith('#%s)' % kwargs.get('issue')):
continue
commit_hash = line[0][:7]
fix_index = git_log_hashes.index(commit_hash)
data = {'platforms': {}}
for service in InstalledService.objects.all():
installed_version = module.get_installed_version(service.platform, service.service)
if not installed_version or not installed_version.version:
continue
version_number = installed_version.version.version
if not version_number:
continue
service_name = '%s / %s / %s' % (
installed_version.service.platform.project.title,
installed_version.service.platform.title,
installed_version.service.service.title)
version_hash = module.get_version_hash(version_number)
version_index = git_log_hashes.index(version_hash)
data['platforms'][service_name] = {
'version': version_number,
'status': 'ok' if version_index <= fix_index else 'nok'
}
else:
continue
break
json_str = json.dumps(data, indent=2)
for variable in ('jsonpCallback', 'callback'):
if variable in request.GET:
response = HttpResponse(content_type='application/json')
json_str = '%s(%s);' % (request.GET[variable], json_str)
break
response.write(json_str)
return response