Skip to content

Instantly share code, notes, and snippets.

@trestletech
Last active December 11, 2015 02:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trestletech/4531146 to your computer and use it in GitHub Desktop.
Save trestletech/4531146 to your computer and use it in GitHub Desktop.
Import My PivotalTracker Stories into Astrid
setup.sh
token
#Required Environment Variables:
# PIVOTAL_TOKEN - the API key. Obtained as described here: https://www.pivotaltracker.com/help/api?version=v3#retrieve_token
# PIVOTAL_PROJECT - the numerical ID of the project on which we're working.
# PIVOTAL_OWNER - Include only tasks owned by this user in parsing.
# ASTRID_SECRET - The secret Key of your Astrid Application on their API
# ASTRID_APP - The application ID you registered with Astrid
# LIST_NAME - The name of the list to apply to all tasks inserted into Astrid.
import os
import urllib2
import urllib
from xml.dom import minidom
import time
import md5
import simplejson
import getpass
def fetchAllPivotal () :
request = urllib2.Request("http://www.pivotaltracker.com/services/v3/projects/"+os.environ['PIVOTAL_PROJECT']+"/iterations/current?", headers={"X-TrackerToken" : os.environ['PIVOTAL_TOKEN']})
contents = urllib2.urlopen(request).read()
xml = minidom.parseString(contents)
return xml
def astridRequest (method, params) :
sigurl = method
params['app_id'] = os.environ['ASTRID_APP']
params['time'] = (str(int(time.time())))
for par in sorted(params.iterkeys()):
if not isinstance(params[par], (basestring,int)) and len(params[par]) > 1:
params[par] = sorted(params[par])
for p in params[par] :
sigurl += str(par) + str(p)
else :
sigurl += str(par) + str(params[par])
sig = md5.new(sigurl + os.environ['ASTRID_SECRET']).hexdigest()
params['sig'] = sig
data = urllib.urlencode(params, True)
request = urllib2.Request("http://astrid.com/api/7/" + method, data)
contents = urllib2.urlopen(request).read()
return [contents]
def doAstridLogin() :
#try fetching the existing token and test it
try:
f = open('token', 'r')
token = f.readline()
f.close()
return token
except IOError:
#no token, get new one.
return getNewToken()
def getNewToken () :
username = raw_input("Enter your Astrid Email: ")
# password = raw_input("Enter your Astrid password:")
password = getpass.getpass()
params = {'email': username, 'provider': 'password', 'secret': password}
req = astridRequest("user_signin", params)
decoded = simplejson.loads(req[0])
token = decoded['token']
f = open('token', 'w')
f.write(token)
f.close()
return str(token)
def saveTask (token, pivotalID, pivotalState, pivotalURL, pivotalDesc, pivotalName, dueDate, astridID=None):
url = "task_save"
params = {}
#If this is a new task, set the date to the end of the Sprint. If it's an existing task, just let Astrid manage the due date.
if astridID == None :
params['due'] = str(dueDate)
params['has_due_time'] = 1
if astridID != None :
params['id'] = astridID
params['notes'] = (pivotalURL) + " - " + (pivotalDesc)
params['title'] = (pivotalName)
params['token'] = token
params['tags[]'] = ['Work', os.environ['LIST_NAME']]
if (pivotalState == 1) :
params['completed_at'] = (str(int(time.time())))
if (pivotalState == 0) :
params['completed_at'] = 0
results = astridRequest(url, params)
#TODO: check for "Deleted_at" parameter. If it exists, unbind the Pivotal story and create a new Astrid task.
decoded = simplejson.loads(results[0])
return decoded['id']
def annotateStory (storyID, astridID, integrationID=18645) :
opener = urllib2.build_opener(urllib2.HTTPHandler)
payload = "<story><other_id>" + str(astridID) + "</other_id><integration_id>" + str(integrationID) + "</integration_id></story>"
request = urllib2.Request("http://www.pivotaltracker.com/services/v3/projects/"+os.environ['PIVOTAL_PROJECT']+"/stories/"+str(storyID), data=payload)
request.add_header('X-TrackerToken', os.environ['PIVOTAL_TOKEN'])
request.add_header('Content-Type', 'application/xml')
request.get_method = lambda: 'PUT'
url = opener.open(request)
contents = urllib2.urlopen(request).read()
#print contents
xml = fetchAllPivotal()
iterations = xml.getElementsByTagName('iteration')
print "Parsing " + str(len(iterations)) + " iterations..."
#First login a user so we can start interacting with their tasks.
#token = doAstridLogin(os.environ['ASTRID_USERNAME'], os.environ['ASTRID_PASSWORD'])
token = doAstridLogin()
for iter in iterations :
stories = iter.getElementsByTagName('story')
iterID = iter.getElementsByTagName('id')[0].childNodes[0].nodeValue
iterFinish = iter.getElementsByTagName('finish')[0].childNodes[0].nodeValue
iterFinish = int(time.mktime(time.strptime(iterFinish, '%Y/%m/%d %H:%M:%S UTC')))
print "Parsing " + str(len(stories)) + " stories in iteration #" + str(iterID)
for story in stories :
storyID = story.getElementsByTagName('id')[0].childNodes[0].nodeValue
storyState = story.getElementsByTagName('current_state')[0].childNodes[0].nodeValue
storyComplete = 0
if storyState == "finished" or storyState == "delivered" or storyState == "accepted" :
storyComplete = 1
storyURL = story.getElementsByTagName('url')[0].childNodes[0].nodeValue
storyDesc = "" #Check if description is given
if len(story.getElementsByTagName('description')[0].childNodes) > 0 :
storyDesc = story.getElementsByTagName('description')[0].childNodes[0].nodeValue
storyOwner = "" #Check if owner exists
if len(story.getElementsByTagName('owned_by')) > 0 :
storyOwner = story.getElementsByTagName('owned_by')[0].childNodes[0].nodeValue
storyName = story.getElementsByTagName('name')[0].childNodes[0].nodeValue
storyAstridID = None #Check if already bound to Astrid
if len(story.getElementsByTagName('other_id')) > 0 :
storyAstridID = story.getElementsByTagName('other_id')[0].childNodes[0].nodeValue
storyName = story.getElementsByTagName('name')[0].childNodes[0].nodeValue
if storyOwner == os.environ['PIVOTAL_OWNER'] :
astID = saveTask(token, storyID, storyComplete, storyURL, storyDesc, storyName, iterFinish, storyAstridID)
if (storyAstridID == None) :
print " Created Astrid task #" + str(astID)
#Now bind the Pivotal story to the Astrid task
annotateStory(storyID, astID)
if str(astID) == str(storyAstridID) :
print " Refreshed Astrid task #" + str(astID)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment