This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
sentry-redmine/sentry_redmine/plugin.py

237 lines
8.4 KiB
Python

from __future__ import absolute_import
import json
import six
from django.utils.translation import ugettext_lazy as _
from sentry.exceptions import PluginError
from sentry.plugins.bases.issue import IssuePlugin
from sentry.utils.http import absolute_uri
from .client import RedmineClient
from .forms import RedmineNewIssueForm
class RedminePlugin(IssuePlugin):
author = 'Sentry'
author_url = 'https://github.com/getsentry/sentry-redmine'
version = '0.1.0'
description = "Integrate Redmine issue tracking by linking a user account to a project."
resource_links = [
('Bug Tracker', 'https://github.com/getsentry/sentry-redmine/issues'),
('Source', 'https://github.com/getsentry/sentry-redmine'),
]
slug = 'redmine'
title = _('Redmine')
conf_title = 'Redmine'
conf_key = 'redmine'
new_issue_form = RedmineNewIssueForm
def __init__(self):
super(RedminePlugin, self).__init__()
self.client_errors = []
self.fields = []
def has_project_conf(self):
return True
def is_configured(self, project, **kwargs):
return all((self.get_option(k, project) for k in ('host', 'key', 'project_id')))
def get_new_issue_title(self, **kwargs):
return 'Create Redmine Task'
def get_initial_form_data(self, request, group, event, **kwargs):
return {
'description': self._get_group_description(request, group, event),
'title': self._get_group_title(request, group, event),
}
def _get_group_description(self, request, group, event):
output = [
absolute_uri(group.get_absolute_url()),
]
body = self._get_group_body(request, group, event)
if body:
output.extend([
'',
'<pre>',
body,
'</pre>',
])
return '\n'.join(output)
def get_client(self, project):
return RedmineClient(
host=self.get_option('host', project),
key=self.get_option('key', project),
)
def create_issue(self, group, form_data, **kwargs):
"""
Create a Redmine issue
"""
client = self.get_client(group.project)
default_priority = self.get_option('default_priority', group.project)
if default_priority is None:
default_priority = 4
issue_dict = {
'project_id': self.get_option('project_id', group.project),
'tracker_id': self.get_option('tracker_id', group.project),
'priority_id': default_priority,
'subject': form_data['title'].encode('utf-8'),
'description': form_data['description'].encode('utf-8'),
}
extra_fields_str = self.get_option('extra_fields', group.project)
if extra_fields_str:
extra_fields = json.loads(extra_fields_str)
else:
extra_fields = {}
issue_dict.update(extra_fields)
response = client.create_issue(issue_dict)
return response['issue']['id']
def get_issue_url(self, group, issue_id, **kwargs):
host = self.get_option('host', group.project)
return '{}/issues/{}'.format(host.rstrip('/'), issue_id)
def build_config(self):
host = {'name':'host',
'label':'Host',
'type':'text',
'help':'e.g. http://bugs.redmine.org',
'required':True,}
key = {'name':'key',
'label':'Key',
'type':'text',
'help':'Your API key is available on your account page after enabling the Rest API (Administration -> Settings -> Authentication)',
'required':True,}
project_id = {'name':'project_id',
'label':'Project*',
'type':'select',
'choices':[],
'required':False,}
tracker_id = {'name':'tracker_id',
'label':'Tracker*',
'type':'select',
'choices':[],
'required':False,}
default_priority = {'name':'default_priority',
'label':'Default Priority*',
'type':'select',
'choices':[],
'required':False,}
extra_fields = {'name':'extra_fields',
'label':'Extra Fields',
'type':'text',
'help':'Extra attributes (custom fields, status id, etc.) in JSON format',
'required':False,}
return [host, key, project_id, tracker_id, default_priority, extra_fields]
def add_choices(self, field_name, choices, default):
for field in self.fields:
if field_name == field['name']:
field['choices'] = choices
field['default'] = default
return
def remove_field(self, field_name):
for field in self.fields:
if field['name'] == field_name:
self.fields.remove(field)
return
def build_initial(self, inital_args, project):
initial = {}
fields = ['host', 'key', 'project_id', 'tracker_id', 'default_priority', 'extra_fields']
for field in fields:
value = inital_args.get(field) or self.get_option(field, project)
if value is not None:
initial[field] = value
return initial
def get_config(self, project, **kwargs):
self.client_errors = []
self.fields = self.build_config()
initial_args = kwargs.get('initial') or {}
initial = self.build_initial(initial_args, project)
has_credentials = all(initial.get(k) for k in ('host', 'key'))
if has_credentials:
client = RedmineClient(initial['host'], initial['key'])
try:
projects = client.get_projects()
except Exception:
has_credentials = False
self.client_errors.append('There was an issue authenticating with Redmine')
else:
choices_value = self.get_option('project_id', project)
project_choices = [('', '--') ] if not choices_value else []
project_choices += [
(p['id'], '%s (%s)' % (p['name'], p['identifier']))
for p in projects['projects']
]
self.add_choices('project_id', project_choices, choices_value)
if has_credentials:
try:
trackers = client.get_trackers()
except Exception:
self.remove_field('tracker_id')
else:
choices_value = self.get_option('tracker_id', project)
tracker_choices = [('', '--') ] if not choices_value else []
tracker_choices += [
(p['id'], p['name'])
for p in trackers['trackers']
]
self.add_choices('tracker_id', tracker_choices, choices_value)
try:
priorities = client.get_priorities()
except Exception:
self.remove_field('default_priority')
else:
choices_value = self.get_option('default_priority', project)
tracker_choices = [('', '--') ] if not choices_value else []
tracker_choices += [
(p['id'], p['name'])
for p in priorities['issue_priorities']
]
self.add_choices('default_priority', tracker_choices, choices_value)
if not has_credentials:
for field_name in ['project_id', 'tracker_id', 'default_priority', 'extra_fields']:
self.remove_field(field_name)
return self.fields
def validate_config(self, project, config, actor):
super(RedminePlugin, self).validate_config(project, config, actor)
self.client_errors = []
required_fields = ['project_id', 'tracker_id', 'default_priority']
index = [2, 3, 4]
try:
for field in required_fields:
for i in index:
if self.fields[i]['name'] == field:
if config[field] == None or config[field] == '':
self.logger.exception(six.text_type('{} required.'.format(field)))
self.client_errors.append(field)
except IndexError:
pass
if self.client_errors:
raise PluginError(', '.join(self.client_errors) + ' required.')
return config