scrutiny/scrutiny/projects/utils.py

132 lines
4.4 KiB
Python

import re
import requests
from django.conf import settings
from django.core.cache import cache
from django.utils.encoding import force_text
CACHE_DURATION = 3600
def decorate_commit_line(line):
escaped_line = line.replace('<', '&lt;').replace('>', '&gt;')
if line.startswith('<'):
return '<span class="in">%s</span>' % escaped_line
elif line.startswith('>'):
return '<span class="out">%s</span>' % escaped_line
return '<span class="other">%s</span>' % escaped_line
class Issue(object):
def __init__(self, issue_id):
self.id = issue_id
self.commits = []
def update_content(self):
response = requests.get(
'%s/issues/%s.json' % (settings.REDMINE_URL, self.id),
headers={'X-Redmine-API-Key': settings.REDMINE_API_KEY},
)
response.raise_for_status()
content = response.json()
cache.set('issue-%s' % self.id, content, CACHE_DURATION)
def get_attribute(self, attr):
content = cache.get('issue-%s' % self.id)
if content:
return content.get('issue').get(attr)
try:
self.update_content()
except requests.RequestException:
return '---'
return self.get_attribute(attr)
@property
def subject(self):
return self.get_attribute('subject')
@property
def closed_on(self):
if self.get_attribute('closed_on'):
return self.get_attribute('closed_on')
# fallback on updated_on, as "resolved (to deploy)" is not considered
# "closed"
return self.get_attribute('updated_on')
@property
def url(self):
return '%s/issues/%s' % (settings.REDMINE_URL, self.id)
@property
def priority_class(self):
return 'priority-%s' % self.get_attribute('priority')['name'].lower()
def add_commit(self, commit):
self.commits.append(commit)
class CommitAndIssues(object):
def __init__(self, oneline):
self.issues = []
self.commit = oneline.strip()
self.commit_html = decorate_commit_line(self.commit)
@classmethod
def get_for_commits(cls, module, v1, v2):
difflog = module.get_diff_log(v1, v2, format='full', grep=r'\#[0-9]\+')
commits = re.findall(r'^commit.*?\n\n.*?\n\n', difflog, re.DOTALL | re.MULTILINE)
oneline_commits = module.get_diff_log(v1, v2, grep=r'\#[0-9]\+').splitlines()
objects = []
for commit, oneline in zip(commits, oneline_commits):
obj = cls(oneline.strip())
for issue_id in re.findall(r'#(\d+)', commit):
obj.add_issue(issue_id)
objects.append(obj)
return objects
def add_issue(self, issue_id):
self.issues.append(Issue(issue_id))
def get_issue_deployment_status(issue_id):
from .models import Module, InstalledService
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 force_text(line[1], 'utf-8', 'ignore').endswith('#%s)' % issue_id):
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)
if not version_hash in git_log_hashes:
continue
version_index = git_log_hashes.index(version_hash)
data['platforms'][service_name] = {
'version': version_number,
'status': 'ok' if version_index <= fix_index else 'nok',
}
if data:
break
return data