Managing The Joys of Jira
Managing the joys of Jira
We all know and love Jira, especially when one needs to log time and perform other soul-sucking activities.
I wrote the following script to help make working with Jira a little bit more palatable.
Functions include deleting all the annoying email-footer images that get attached to tickets when a person emails to Jira, closing Jira tickets in the "In Review" state, etc.
This is a work in progress. One of those "time permitting" things.
#!/usr/bin/env python
"""
http://jira.readthedocs.org/en/latest/
http://pythonhosted.org/jira/
"""
from __future__ import print_function
import datetime
import hashlib
import argparse
import logging
from jira.exceptions import JIRAError
from jira.client import JIRA
from config import password, username
from tzlocal import get_localzone
tz = get_localzone()
logging.captureWarnings(True)
image_sha1 = [
'd4eb62ac1b88ad4a39aa1e907dc51093a11e4c2c',
'14ccfccf0a01c66df43601c13d09f3a7172f8de3',
'c263a5ec4306721aa039d5f55ae108a5cb60efea',
'6f53c75a06cb0ccc700e81c2a40315204dc89c53',
'a97c6451630ad10047cf33d505f1326f5247add0',
'72ebf3111b34e565aec8b23b4dba9533c3d976a2',
'4bf304bcd472cc92ae63b2df0d476618c2890428',
'f4d0668f235368a8951fb42b2112d5f162c816af',
'695cfde3e0d49fe546a3de07b8b2ceb89f657aac',
]
searches = {
'inreview': 'assignee=%s AND status = "In Review"' % username,
'bycreate': ('assignee=%s AND resolution = Unresolved '
'order by updated DESC') % username,
'bypriority': ('assignee=%s AND status NOT IN (Closed, Resolved, Done)'
'order by Priority') % username,
'done_unresolved': ('assignee=%s AND resolution = Unresolved and'
'status = done order by updated DESC') % username,
}
issues = {
'ADMIN-56': 'General Admin',
'ADMIN-7': 'Non-client Meetings',
'ADMIN-58': 'Internal design requests',
'ADMIN-66': 'wiChillaz',
'ADMIN-12': 'Internal process improvements',
'DEVOPS-461': 'DevOps Core Activity',
}
def initial_monthly(jira_connection):
d = datetime.datetime.now()
started_date = tz.localize(datetime.datetime(d.year, d.month, 1))
# started_date = tz.localize(started_date)
for issue in issues:
jira_connection.add_worklog(issue, timeSpent='1m',
comment='Initial worklog',
started=started_date)
print(issue)
def print_issue(jira_connection, issue_list, attachments=False):
for _issue in issue_list:
try:
issue = jira_connection.issue(_issue)
except JIRAError:
print('Issue %s does not exist' % _issue)
continue
print('%-12s %-25s %-16s %-8s %-8s %-12s %-18s %-18s %s' %
(issue.key,
issue.fields.status,
issue.fields.resolution,
issue.fields.timespent,
issue.fields.timeestimate,
issue.fields.priority,
issue.fields.assignee,
issue.fields.reporter,
issue.fields.summary))
attachments = issue.fields.attachment
for attachment in attachments:
# content = attachment.get()
# sha1 = hashlib.sha1(content).hexdigest()
print('\t\t\t%20s %s' % (attachment.filename, ''))
def list_issues(jira_connection, verbose, search):
myissues = jira_connection.search_issues(searches[search])
for item in myissues:
issue = jira_connection.issue(item)
if verbose:
print_issue(jira_connection, issue)
else:
s = u'%-12s %-20s %s %s' % (
item,
issue.fields.status,
get_date(issue.fields.created),
issue.fields.summary)
s = s.encode('ascii', 'ignore').decode('ascii')
print(s)
def remove_images(jira_connection, issue, image_name=None):
issue = jira_connection.issue(issue[0])
attachments = issue.fields.attachment
for attachment in attachments:
if image_name == attachment.filename:
content = attachment.get()
sha1 = hashlib.sha1(content).hexdigest()
if sha1 in image_sha1:
print('Deleting %s...' % attachment.filename, end=' ')
attachment.delete()
print(' done')
else:
print('Skipping %s...' % attachment.filename)
def delete_issue(jira_connection, issue):
print('Delete issue %s' % (issue,))
issue = jira_connection.issue(issue)
issue.delete()
def make_done_resolved(jira_connection, issue_list):
if issue_list == 'all':
issue_list = jira_connection.search_issues(searches['inreview'])
for issue in issue_list:
transitions = jira_connection.transitions(issue)
enum = enumerate(transitions)
while True:
e = enum.next()
id = e[0]
if e[1]['name'] == 'Done':
transition_id = e[1]['id']
break
to_id = transitions[id]['to']['id']
print('issue=%s transtion(id=%s, state=%s)' %
(issue, str(transition_id), str(to_id)))
jira_connection.transition_issue(issue, transition_id,
resolution={'id': to_id})
def __make_done_resolved(jira_connection, issue):
transitions = jira_connection.transitions(issue)
print(transitions)
# jira_connection.transition_issue(issue, '51')
# jira_connection.transition_issue(issue, '21')
def get_date(datestr):
return datestr.split('T')[0]
def get_definition(issue):
return issue.fields.description
def set_lorum_definition(issue):
if not issue.fields.description:
with open('lorum.txt', 'rb') as f:
issue.update(description=f.read())
def projects():
pass
def list_searches():
txt = 'List issues using one of the following searches:\n'
for search in searches.keys():
txt += '\t%s\n' % search
return txt
def parse_args():
parser = argparse.ArgumentParser(description='Jira Tool')
parser.add_argument('-v', '--verbose',
dest='verbose', action='store_true', default=False)
parser.add_argument('-d', '--delete-issue',
dest='delete_issue', action='store', default='')
parser.add_argument('-0', '--remove-image',
dest='remove_image', action='store', default='')
parser.add_argument('-l', '--list-issues',
dest='list_issues', action='store', default='',
choices=searches.keys(), help=list_searches())
parser.add_argument('-i', '--issue', nargs='+',
dest='issue', action='store', default='')
parser.add_argument('-r', '--resolve-done', dest='resolve_done',
action='store', default='')
parser.add_argument('--lorum', dest='lorum_issue', action='store',
default=None)
parser.add_argument('--initialise', dest='initialise', action='store_true',
default=False)
# parser.add_argument('', '', dest='', action='', default=)
args = parser.parse_args()
return args, parser
def jira_con():
return JIRA(options={'server': 'https://wigroup2.atlassian.net'},
basic_auth=(username, password))
if __name__ == "__main__":
args, parser = parse_args()
global verbose
verbose = args.verbose
jira_connection = jira_con()
if args.issue:
print_issue(jira_connection, args.issue, attachments=False)
elif args.remove_image and args.remove_image:
image_name = args.remove_image
remove_images(jira_connection, args.issue, image_name)
elif args.delete_issue:
delete_issue(jira_connection, args.delete_issue)
elif args.resolve_done:
make_done_resolved(jira_connection, args.resolve_done)
elif args.list_issues:
list_issues(jira_connection, verbose, args.list_issues)
elif args.lorum_issue:
issue = jira_connection.issue(args.lorum_issue)
set_lorum_definition(issue)
elif args.initialise:
initial_monthly(jira_connection)
else:
parser.print_help()