Exporting data from Pivotal Tracker is a pain in the ass. The following scripts let you download all the stories of a given project, and then (optionally) extract all the attachments linked to those, and download them
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
"""Download stories of a Pivotal Tracker project. | |
You need the project ID (an int) and your API token. The latter can be | |
obtained in ``https://www.pivotaltracker.com/profile``, or using curl:: | |
$ curl -u username:password -X GET https://www.pivotaltracker.com/services/v3/tokens/active | |
""" | |
import getpass | |
import pickle | |
import urllib2 | |
from xml.dom import minidom | |
__version__ = '0.1.0' | |
__author__ = 'German Larrain' | |
project_id = raw_input("Project ID: ") | |
auth_token = getpass.getpass("Auth token: ") | |
url_template = "http://www.pivotaltracker.com/services/v3/projects/%s/stories" | |
url = url_template % project_id | |
req = urllib2.Request(url, None, {'X-TrackerToken': auth_token}) | |
response = urllib2.urlopen(req) | |
dom = minidom.parseString(response.read()) | |
dom_as_xml = dom.toxml(encoding='utf-8') | |
pickle_filename = "xml_stories_%s.p" % project_id | |
pickle.dump(dom_as_xml, open(pickle_filename, 'wb')) |
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
"""Download stories attachments of a Pivotal Tracker project. | |
The shell scripts in this directory do not contain the actual code of them | |
but the instructions of how to get it. | |
Since I'm not the author of those scripts, I can't post them in this gist | |
without his permission. | |
""" | |
import getpass | |
import os | |
import pickle | |
import xml.dom.minidom | |
__version__ = '0.1.0' | |
__author__ = 'German Larrain' | |
def get_attachment_metadata(element_attachment): | |
def get_data_for_tag(tag_name): | |
elements_tag = element_attachment.getElementsByTagName(tag_name) | |
assert len(elements_tag) == 1 | |
element_tag = elements_tag[0] | |
assert len(element_tag.childNodes) == 1 | |
node_attachment_tag = element_tag.childNodes[0] | |
assert not node_attachment_tag.hasChildNodes() | |
return node_attachment_tag.data | |
return ( | |
get_data_for_tag('id'), | |
get_data_for_tag('filename'), | |
get_data_for_tag('url'), | |
) | |
def download_attachments(attachments_metadata, dir=None): | |
user = raw_input("Account user: ") | |
password = getpass.getpass("Account password: ") | |
exit_status = os.system("bash login-to-PT.sh %s %s" % (user, password)) | |
if exit_status: | |
print("`login-to-PT.sh` failed. Exit code: %s" % exit_status) | |
for metadata in attachments_metadata: | |
file_id = metadata[0] | |
server_filename = metadata[1] | |
filename = "%s - %s" % (file_id, server_filename) | |
file_path = filename if dir is None else os.path.join(dir, filename) | |
print("downloading %s" % file_id) | |
exit_status = os.system( | |
'bash get-attachment.sh %s "%s"' % (file_id, file_path)) | |
if exit_status: | |
print("`get-attachment.sh` failed. Exit code: %s" % exit_status) | |
def main(): | |
pickle_filename = raw_input("pickled file: ") # xml_stories_423507.p | |
pickle_file = open(pickle_filename, 'rb') | |
dom_as_xml = pickle.load(pickle_file) | |
dom = xml.dom.minidom.parseString(dom_as_xml) | |
elements_stories = dom.getElementsByTagName('stories') | |
assert len(dom.getElementsByTagName('stories')) == 1 | |
element_stories = elements_stories[0] | |
elements_story = element_stories.getElementsByTagName('story') | |
print("number of stories: %s" % len(elements_story)) | |
elements_attachments_dict = {} | |
attachments_metadata = [] | |
for ix, story in enumerate(elements_story): | |
element_attachments = story.getElementsByTagName('attachments') | |
if element_attachments: | |
elements_attachments_dict[ix] = element_attachments | |
print("number of stories with attachment(s): %s" % | |
len(elements_attachments_dict)) | |
for key in elements_attachments_dict: | |
assert len(elements_attachments_dict[key]) == 1 | |
element_attachments = elements_attachments_dict[key][0] | |
story_elements_attachment = element_attachments.getElementsByTagName('attachment') | |
assert len(story_elements_attachment) >= 1 | |
for element_attachment in story_elements_attachment: | |
attachments_metadata.append( | |
get_attachment_metadata(element_attachment)) | |
print("number of attachments: %s" % len(attachments_metadata)) | |
if attachments_metadata: | |
download_attachments(attachments_metadata, dir="attachments") | |
else: | |
print("[INFO] There are no attachments to be downloaded") | |
if __name__ == '__main__': | |
main() |
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
# get the second script in | |
# http://veryuniquename.blogspot.com/2013/06/downloading-pivotal-tracker-attachments.html | |
# (I haven't requested author's permission to post his code here) | |
# and replace the last line with: | |
# curl --silent --cookie cjar --cookie-jar cjar --output "$OUT_FILE" "$BASE_URL$ATT_ID" | |
# (I had to quote $OUT_FILE so the filename could have spaces) |
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
# get the first script in | |
# http://veryuniquename.blogspot.com/2013/06/downloading-pivotal-tracker-attachments.html | |
# (I haven't requested author's permission to post his code here) |
do you have means to extract story activity and review activities?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi! Is this really works? Can you give me instructions to work this out? I'll appreciate it! I'm not a dev and I have to export from pivotal with attachments.
Thank you in advance!