List of Redmine tickets and expired tickets Code to reduce with DataFrame.
The test code is still being written.
Markdown table, chat input library I have already made it.
#!/opt/anaconda3/bin/python3
# -*- coding: utf-8 -*-
"""Manage Redmine ticket status
Obtain ticket information and analyze the situation
Todo:
*Only Redmine and RocketChat yet. Make the same for other OSS
"""
################################################
# library
################################################
import datetime
import redminelib
import requests
import pandas as pd
import sys
from pprint import pprint
from redminelib import Redmine
#Individual library Load
################################################
#Unique exception definition
################################################
#class MaxRetryError(Exception):
# pass
#
################################################
#Information definition
################################################
#
## Redmine Instance
#HOST = "http://xxxxxxxxxxxxxxxxxxxxxxxxxx:3100/"
#API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx47ac"
#
##Extraction target
#PROJECT_ID = 'wbs-kaisui'
#PROJECT_NAME = 'Individual WBS (development promotion)'
#TRACKER_NAME ='things to do'
#
##Dataframe columns definition
#COLUMNS = ['Project','Tracker','Sprint','Parent ticket ID','Ticket ID','TicketTitle','In charge', 'Status','start date','Deadline']
#
##Search conditions
#QUERY = 'start date<= @TODAY and deadline< @TODAY'
#
##Sort condition
#SORT_KEY = ['In charge','Deadline']
#
################################################
# RedmineTicketManager
################################################
class RedmineTicketManager():
"""Redmine Ticket Management Class
Attributes:
API_KEY (int) :Redmine admin API key
HOST (bool) :Redmine host
"""
def __init__(self, HOST, API_KEY):
"""Redmine instance generation
API_KEY,Returns a Redmine instance from HOST
Args:
HOST (str): Redmine Host
API_KEY (str):API according to admin_KEY
Returns:
Raises:
TypeError:Defective argument type
Exception:Insufficient Redmine instance generation
Examples:
>>> redmine = RedmineUserManager(HOST, API_KEY)
Note:
The Redmine group must exist in advance.
Even if a new group is listed, it will not be created automatically on Redmine.
__init__Please note that you must not return bool
"""
#Argument check type
if not isinstance(HOST, str):
print(f'Arguments: HOST type is incorrect str<-> {type(HOST)}')
raise TypeError
if not isinstance(API_KEY, str):
print(f'Arguments: API_KEY type is incorrect str<-> {type(API_KEY)}')
raise TypeError
#Added TODO argument check
#Redmine instance generation (self.redmineļ¼
try:
self.redmine = Redmine(HOST, key=API_KEY)
except exception as e:
print(f'Redmine Instance generation failed')
print(f'Error details:{e}')
else:
if not isinstance(self.redmine, redminelib.Redmine):
print(f'Redmine Instance generation failed')
raise Exception
########################################################
#Expired ticket search process
########################################################
def createOverdueTicket(self, PROJECT_ID, TRACKER_NAME):
'''Search for expired tickets
Search for overdue tickets by specifying the project and tracker.
Args:
PROJECT_ID :str Redmine project ID (not project name)
TRACKER_NAME:str Redmine Search target tracker name
Returns:
All tickets that hit the project, tracker limit: DataFrame
Hit project, tracker conditions, and overdue tickets: DataFrame
Raises:
TypeError:Defective argument type
Exception:Exceptions when searching for tickets
Examples:
>>> RTM = RedmineTicketManager(HOST, API_KEY)
>>> df, df_overdue = RTM.createOverdueTicket(PROJECT_ID, TRACKER_NAME)
Note:
'''
#Dataframe columns definition
COLUMNS = ['Project','Tracker','Sprint','Parent ticket ID','Ticket ID','TicketTitle','In charge', 'Status','start date','Deadline']
#Search conditions
QUERY = 'start date<= @TODAY and deadline< @TODAY'
#Sort condition
SORT_KEY = ['In charge','Deadline']
#Date generation today
TODAY = datetime.date.today()
pprint(f'Judgment reference date: {TODAY}')
INIT_DATE = datetime.date(1900, 1, 1)
pprint(f'The first day: {INIT_DATE}')
print('-'*80)
print(f'Explore Redmine tickets')
try:
#Get all tickets with administrator privileges
tickets=self.redmine.issue.filter(
project_id=PROJECT_ID,
tracker_name=TRACKER_NAME,
)
except Exception as e:
print(f'Ticket acquisition failed:{PROJECT_ID} {TRACKER_NAME}')
print(f'Error details:{e}')
print()
else:
#Ticket delay judgment processing, data creation
#Prepare a temporary container
_list = []
#Ticket molding process
for ticket in tickets:
#Get information from ticket instance
projectName = ticket.project.name
id = ticket.id
subject = ticket.subject
authorName = ticket.author.name
authorID = ticket.author.id
status = ticket.status.name
tracker = ticket.tracker.name
fixed_version = ticket.fixed_version.name
#If the person in charge is not set, it is displayed as not set
try:
assigned_to = ticket.assigned_to.name
except:
assigned_to = "Not set"
#If the start date is not set, set the start date
try:
startDate = ticket.start_date
except:
startDate = INIT_DATE
#If no due date is set, set the start date
try:
dueDate = ticket.due_date
except:
dueDate = INIT_DATE
#Set to 0 if parent ticket is not set
try:
parent = ticket.parent
except:
parent = 0
#Accumulation
_list.append([projectName, tracker, fixed_version, parent, id, subject, assigned_to, status, startDate, dueDate])
print(f'Ticket extraction is complete')
#DataFrame conversion
df = pd.DataFrame(_list)
df.columns = COLUMNS
#Delayed ticket extraction
#For those whose start date is before today and whose deadline is overdue today
df_overdue = df.query(QUERY).sort_values(SORT_KEY).reset_index(drop=True)
print(f'Extracted overdue Redmine tickets')
print(f'Number of overdue tickets: {len(df_overdue)}')
return df ,df_overdue
########################################################
#Expired ticket search process by REST
########################################################
def createOverdueTicketByREST(self, RESTAPI, HEADERS, PROJECT_ID, TRACKER_ID):
'''Search for expired tickets By REST
Search for overdue tickets by specifying the project and tracker.
python_Get information directly using REST without using redmine.
Args:
PROJECT_ID :str Redmine project ID (not project name)
TRACKER_ID:str Redmine Search target tracker ID (not tracker name)
Returns:
All tickets that hit the project, tracker limit: DataFrame
Hit project, tracker conditions, and overdue tickets: DataFrame
Raises:
TypeError:Defective argument type
Exception:Exceptions when searching for tickets
Examples:
>>> RTM = RedmineTicketManagerByREST(HOST, API_KEY)
>>> df, df_overdue = RTM.createOverdueTicketByREST(PROJECT_ID, TRACKER_ID)
Note:
Whether it's a NAME or an ID, it feels awkward to use properly. .. ..
'''
#request parameter generation
#URL = f'http://192.168.10.104:3100'
#API = f'{URL}/projects/{PROJECT_ID}/issues.json?tracker_id={TRACKER_ID}'
#HEADERS = { 'Content-Type': 'application/json', 'X-Redmine-API-Key': '864b3f0933e8084295d47380bf07a168ba2947ac'}
#Date generation today
TODAY = datetime.date.today()
pprint(f'Judgment reference date: {TODAY}')
#Dataframe columns definition
COLUMNS = ['Project','Tracker','Sprint','Parent ticket ID','Ticket ID','TicketTitle','In charge', 'Status','start date','Deadline']
#Search conditions
QUERY = 'start date<= @TODAY and deadline< @TODAY'
#Sort condition
SORT_KEY = ['In charge','Deadline']
#Search processing execution
##Prepare a container
_list = []
#Search implementation
try:
response = requests.get(RESTAPI,
headers=HEADERS)
except Exception as e:
print(f'Redmine ticket search failed')
print(f'{e}')
else:
#Result processing
for _ in response.json()['issues']:
#In some cases, the parent and the person in charge do not exist as data
#Must be judged by try ~ catch
try:
parent = _['parent']['id']
except:
parent = 0
try:
assigned_to = _['assigned_to']['name']
except:
assigned_to = "None"
#There is a start and a deadline.
#None is included if there is no setting
if _['start_date'] != None:
startDate = _['start_date']
else:
startDate = '1900-01-01'
if _['due_date'] != None:
dueDate = _['due_date']
else:
dueDate = '1900-01-01'
#Data accumulation
_list.append([_['project']['name'],
_['tracker']['name'],
_['fixed_version']['name'],
parent,
_['id'],
_['description'],
assigned_to,
_['status']['name'],
startDate,
dueDate,
])
#Convert to DataFrame and perform extraction process
df = pd.DataFrame(_list)
df.columns = COLUMNS
df['start date'] = pd.to_datetime(df['start date'])
df['Deadline'] = pd.to_datetime(df['Deadline'])
#Delayed ticket extraction
#For those whose start date is before today and whose deadline is overdue today
df_overdue = df.query(QUERY).sort_values(SORT_KEY).reset_index(drop=True)
print(f'Extracted overdue Redmine tickets')
print(f'Number of overdue tickets: {len(df_overdue)}')
return df ,df_overdue
Recommended Posts