Merge pull request #1298 from getredash/add_jql

Add: JIRA (JQL) query runner
This commit is contained in:
Arik Fraimovich 2016-09-26 17:08:39 +03:00 committed by GitHub
commit 808fdd4507
3 changed files with 183 additions and 1 deletions

View File

@ -63,7 +63,7 @@ Graphite
- **Options**:
- Url (mandatory)
- URL (mandatory)
- User
- Password
- Verify SSL certificate
@ -270,3 +270,15 @@ Microsoft SQL Server
- ``freetds-dev`` C library
- ``pymssql`` python package, requires FreeTDS to be installed first
JIRA (JQL)
----------
- **Options**:
- URL (your JIRA instance url)
- Username
- Password
For information on how to write JIRA/JQL queries, see :doc:`documentation </usage/jira_querying>`.

View File

@ -0,0 +1,35 @@
JIRA (JQL): Querying
#################
*Simple query, just return issues with no filtering:*
.. code:: json
{
}
*Return only specific fields:*
.. code:: json
{
"fields": "summary,priority"
}
*Return only specific fields and filter by priority:*
.. code:: json
{
"fields": "summary,priority",
"jql": "priority=medium"
}
*Count number of issues with `priority=medium`:*
.. code:: json
{
"queryType": "count",
"jql": "priority=medium"
}

135
redash/query_runner/jql.py Normal file
View File

@ -0,0 +1,135 @@
import json
import requests
from collections import OrderedDict
from redash.query_runner import *
# TODO: make this more general and move into __init__.py
class ResultSet(object):
def __init__(self):
self.columns = OrderedDict()
self.rows = []
def add_row(self, row):
for key in row.keys():
self.add_column(key)
self.rows.append(row)
def add_column(self, column, column_type=TYPE_STRING):
if column not in self.columns:
self.columns[column] = {'name': column, 'type': column_type, 'friendly_name': column}
def to_json(self):
return json.dumps({'rows': self.rows, 'columns': self.columns.values()})
def parse_issue(issue):
result = OrderedDict()
result['key'] = issue['key']
for k, v in issue['fields'].iteritems():
if k.startswith('customfield_'):
continue
if isinstance(v, dict):
if 'key' in v:
result['{}_key'.format(k)] = v['key']
if 'name' in v:
result['{}_name'.format(k)] = v['name']
if k in v:
result[k] = v[k]
if 'watchCount' in v:
result[k] = v['watchCount']
# elif isinstance(v, list):
# pass
else:
result[k] = v
return result
def parse_issues(data):
results = ResultSet()
for issue in data['issues']:
results.add_row(parse_issue(issue))
return results
def parse_count(data):
results = ResultSet()
results.add_row({'count': data['total']})
return results
class JiraJQL(BaseQueryRunner):
@classmethod
def configuration_schema(cls):
return {
'type': 'object',
'properties': {
'url': {
'type': 'string',
'title': 'JIRA URL'
},
'username': {
'type': 'string',
},
'password': {
'type': 'string'
}
},
'required': ['url', 'username', 'password'],
'secret': ['password']
}
@classmethod
def name(cls):
return "JIRA (JQL)"
@classmethod
def annotate_query(cls):
return False
def __init__(self, configuration):
super(JiraJQL, self).__init__(configuration)
self.syntax = 'json'
def run_query(self, query_string):
jql_url = '{}/rest/api/2/search'.format(self.configuration["url"])
try:
query = json.loads(query_string)
query_type = query.pop('queryType', 'select')
if query_type == 'count':
query['maxResults'] = 1
query['fields'] = ''
response = requests.get(jql_url, params=query, auth=(self.configuration.get('username'), self.configuration.get('password')))
if response.status_code == 401 or response.status_code == 403:
return None, "Authentication error. Please check username/password."
if response.status_code != 200:
return None, "JIRA returned unexpected status code ({})".format(response.status_code)
data = response.json()
if query_type == 'count':
results = parse_count(data)
else:
results = parse_issues(data)
return results.to_json(), None
except KeyboardInterrupt:
return None, "Query cancelled by user."
register(JiraJQL)