-
-
Save ryanmark/2661823 to your computer and use it in GitHub Desktop.
Unfuddle ticket generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Takes a markdown formatted sked of milestones and tickets and | |
# pushes it all into unfuddle. Tries to prevent duplicates, but | |
# doesn't do a great job because Unfuddle's API acts strangely. | |
# | |
# TODO: Figure out why new tickets don't show up in the get tickets API request | |
# | |
# usage: import_tix.py sked.txt | |
# | |
# File format: | |
# | |
# # Project Name | |
# | |
# ## Iteration 1 (Nov. 18) | |
# * Write a script to import all these tasks | |
# * build a website | |
# - this is a description of the website to build | |
# | |
# ## Iteration 2 (Nov. 25) | |
# * Launch the website | |
# - Don't forget to tell people | |
# * Profit!!! | |
import os.path | |
import os | |
import sys | |
import requests | |
import json | |
import re | |
import time | |
from dateutil.parser import parse | |
from pprint import pprint | |
auth=( | |
"UNFUDDLE_USERNAME", | |
"UNFUDDLE_PASSWORD" | |
) | |
unfuddle_domain = 'example.unfuddle.com' | |
def get_project(name): | |
# return the dictionary of a project with a name like the one given | |
r=requests.get( | |
'https://%s/api/v1/projects' % unfuddle_domain, | |
auth=auth, | |
headers={'Accept':'application/json'} | |
) | |
if r.ok: | |
projects = json.loads(r.content) | |
for p in projects: | |
if name.strip().lower() == p['title'].lower() or name.strip().lower() == p['short_name']: | |
return p | |
return None | |
else: | |
raise Exception('API call failed') | |
def get_or_create_milestone(project_id, title, due_date): | |
# return the dictionary of the milestone with the given title. | |
# Create it if a matching one can't be found | |
milestone = get_milestone(project_id, title) | |
if not milestone: | |
# didn't find a match, create it | |
r=requests.post( | |
'https://%s/api/v1/projects/%i/milestones' % (unfuddle_domain, project_id), | |
auth=auth, | |
headers={'Accept':'application/json', 'Content-Type':'application/xml'}, | |
data="<milestone><due-on>%s</due-on><title>%s</title></milestone>" % | |
(due_date.strftime('%Y/%m/%d'), title) | |
) | |
milestone = get_milestone(project_id, title) | |
if not milestone: | |
raise Exception('API call failed') | |
return milestone | |
def get_milestone(project_id, title): | |
r=requests.get( | |
'https://%s/api/v1/projects/%i/milestones' % (unfuddle_domain, project_id), | |
auth=auth, | |
headers={'Accept':'application/json'} | |
) | |
if r.ok: | |
milestones = json.loads(r.content) | |
for m in milestones: | |
if title.strip().lower() == m['title'].lower(): | |
return m | |
return None | |
else: | |
raise Exception('API call failed') | |
def get_or_create_ticket(project_id, milestone_id, summary, description, priority=3): | |
# return the dictionary of the milestone with the given title. | |
# Create it if a matching one can't be found | |
ticket = get_ticket(project_id, milestone_id, summary) | |
if not ticket: | |
# didn't find a match, create it | |
r=requests.post( | |
'https://%s/api/v1/projects/%i/tickets' % (unfuddle_domain, project_id), | |
auth=auth, | |
headers={'Accept':'application/json', 'Content-Type':'application/xml'}, | |
data="""<ticket> | |
<milestone-id type="integer">%i</milestone-id> | |
<priority>%i</priority> | |
<description>%s</description> | |
<summary>%s</summary> | |
</ticket>""" % | |
(milestone_id, priority, description, summary) | |
) | |
if not r.ok: | |
raise Exception('API call failed') | |
ticket = get_ticket(project_id, milestone_id, summary) | |
if not ticket: | |
print("WARNING: Ticket was created, but I couldn't retrieve it.") | |
return ticket | |
def get_ticket(project_id, milestone_id, summary): | |
r=requests.get( | |
'https://%s/api/v1/projects/%i/tickets' % (unfuddle_domain, project_id), | |
auth=auth, | |
headers={'Accept':'application/json'} | |
) | |
if r.ok: | |
tickets = json.loads(r.content) | |
for t in tickets: | |
if summary.strip().lower() == t['summary'].lower(): | |
return t | |
return None | |
else: | |
raise Exception('API call failed') | |
if __name__ == "__main__": | |
# A line that begins with # is the name of the project | |
# A line that begins with ## is the name of the milestone | |
# Milestones need due dates: ## Milestone 1 (due date) | |
# A line that begins with an * is a ticket | |
# A line that begins with an - and follows a line that starts | |
# with a * is a ticket description | |
# Any other line is ignored | |
datafile = sys.argv[1] | |
f = open(datafile, "U") | |
project = None | |
milestone = None | |
lines = f.readlines() | |
for idx, line in enumerate(lines): | |
if line.startswith('##'): | |
# milestone and due date | |
if not project: | |
raise Exception("Don't know which project to put this stuff in!") | |
milestone_title, due_date = re.match( | |
r'##\s+([\w\s]+)\s+\(([^\)]+)\)', | |
line.strip() ).group(1,2) | |
print('Adding tickets to milestone "%s"...' % milestone_title) | |
milestone = get_or_create_milestone(project['id'], milestone_title, parse(due_date)) | |
elif line.startswith('#'): | |
# project name | |
project_name = line.strip()[1:].strip() | |
print('Switching to project "%s"...' % project_name) | |
project = get_project(project_name) | |
if not project: | |
raise Exception("Couldn't find project '%s'" % project_name) | |
elif line.startswith('*'): | |
# ticket | |
if not project or not milestone: | |
raise Exception("Don't know which project or milestone to put this stuff in!") | |
# title | |
ticket_title = line.strip()[1:].strip() | |
# description | |
position = idx + 1 | |
ticket_description = [] | |
while lines[position].strip().startswith('-'): | |
ticket_description.append(lines[position].strip()) | |
if position + 1 < len(lines): | |
position += 1 | |
else: | |
break | |
print 'Adding ticket "%s"...' % ticket_title | |
ticket = get_or_create_ticket( | |
project['id'], milestone['id'], ticket_title, "\n".join(ticket_description)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment