132 lines
4.4 KiB
Python
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('<', '<').replace('>', '>')
|
|
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:
|
|
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:
|
|
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 InstalledService, Module
|
|
|
|
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
|