-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New functionality from all forks #1
base: master
Are you sure you want to change the base?
Changes from all commits
6fdd3c2
34dabef
b124193
35f5fcd
ed36d85
4cb6ff5
4158e92
ea2ad47
ef82e47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.pyc |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,9 +14,25 @@ def __init__(self, token, secure=True, parse_xml=True): | |
these options by setting 'secure' or 'parse_xml' to False""" | ||
self.__token = token | ||
protocol = "https" if secure else "http" | ||
self.__base_url = "%(protocol)s://www.pivotaltracker.com/services/v2/" % dict(protocol=protocol) | ||
self.__base_url = "%(protocol)s://www.pivotaltracker.com/services/v4/" % dict(protocol=protocol) | ||
self.__parse_xml = parse_xml | ||
|
||
|
||
def get_activity(self,limit=None,occurred_since_date=None): | ||
"""gets activity for all projects""" | ||
params = {} | ||
if limit: | ||
params["limit"] = limit | ||
if occurred_since_date: | ||
params["occurred_since_date"] = occurred_since_date | ||
if params: | ||
# we have parameters to send | ||
encoded_params = urllib.urlencode(params) | ||
return self.__remote_http_get("activities?%s" % (encoded_params)) | ||
else: | ||
# no arguments, get all stories | ||
return self.__remote_http_get("activities" ) | ||
return self.__remote_http_get("activities") | ||
|
||
def get_project(self, project_id): | ||
"""gets a project from the tracker""" | ||
return self.__remote_http_get("projects/%s" % project_id) | ||
|
@@ -28,10 +44,15 @@ def get_all_projects(self): | |
def get_story(self, project_id, story_id): | ||
"""gets an individual story""" | ||
return self.__remote_http_get("projects/%s/stories/%s" % (project_id, story_id)) | ||
|
||
def get_story_activity(self, project_id, story_id): | ||
"""get story activities""" | ||
return self.__remote_http_get("projects/%s/stories/%s/activities" % (project_id, story_id)) | ||
|
||
def get_stories(self, project_id, query=None, limit=None, offset=None): | ||
"""gets stories from a project. These stories can be filtered via 'query', and | ||
paginated via 'limit' and 'offset'""" | ||
# WARNING The name filter just doesn't work due to some PT api bug. You'll either get back nothing or everthing, irrespective of search terms. | ||
params = {} | ||
if query: | ||
params["filter"] = query | ||
|
@@ -47,6 +68,30 @@ def get_stories(self, project_id, query=None, limit=None, offset=None): | |
# no arguments, get all stories | ||
return self.__remote_http_get("projects/%s/stories" % project_id) | ||
|
||
def get_task(self, project_id, story_id, task_id): | ||
"""gets a specific task associated with an individual story""" | ||
return self.__remote_http_get("projects/%s/stories/%s/tasks/%s" % (project_id, story_id, task_id)) | ||
|
||
def get_tasks(self, project_id, story_id): | ||
"""gets the tasks associated with an individual story""" | ||
return self.__remote_http_get("projects/%s/stories/%s/tasks" % (project_id, story_id)) | ||
|
||
def add_task(self, project_id, story_id, description, complete=None): | ||
"""adds a task to a story""" | ||
xml = self.__get_task_xml(description, complete) | ||
data = xml.toxml() | ||
return self.__remote_http_post("projects/%s/stories/%s/tasks" % (project_id, story_id), data=data) | ||
|
||
def update_task(self, project_id, story_id, task_id, description, complete=None): | ||
"""updates a task on a story""" | ||
xml = self.__get_task_xml(description, complete) | ||
data = xml.toxml() | ||
return self.__remote_http_post("projects/%s/stories/%s/tasks/%s" % (project_id, story_id, task_id), data=data) | ||
|
||
def delete_task(self, project_id, story_id, task_id): | ||
"""deletes a task in a story""" | ||
return self.__remote_http_delete("projects/%s/stories/%s/tasks/%s" % (project_id, story_id, task_id)) | ||
|
||
def get_iterations(self, project_id, limit=None, offset=None): | ||
"""gets iterations from a project. These iterations can be paginated via 'limit' and 'offset'""" | ||
return self.__iterations_request_helper(sub_url="iterations", project_id=project_id, limit=limit, offset=offset) | ||
|
@@ -67,16 +112,23 @@ def get_backlog_iterations(self, project_id, limit=None, offset=None): | |
|
||
def add_story(self, project_id, name, description, story_type, requested_by=None, estimate=None, current_state=None, labels=None): | ||
"""adds a story to a project""" | ||
xml = self.__get_story_xml(project_id, name, description, requested_by, story_type, estimate, current_state, labels) | ||
#WARNING: Wait for 3 seconds after adding a story before trying to retrieve it to let the API catch up | ||
xml = self.__get_story_xml(name, description, requested_by, story_type, estimate, current_state, labels) | ||
data = xml.toxml() | ||
return self.__remote_http_post("projects/%s/stories" % project_id, data=data) | ||
|
||
def update_story(self, project_id, story_id, name=None, description=None, requested_by=None, story_type=None, estimate=None, current_state=None, labels=None): | ||
"""updates a story in a project""" | ||
xml = self.__get_story_xml(project_id, name, description, requested_by, story_type, estimate, current_state, labels) | ||
xml = self.__get_story_xml(name, description, requested_by, story_type, estimate, current_state, labels) | ||
data = xml.toxml() | ||
return self.__remote_http_put("projects/%s/stories/%s" % (project_id, story_id), data=data) | ||
|
||
def move_story(self, project_id, story_id, target_story_id, precedence=None): | ||
"""moves a story before (default) or after another story""" | ||
xml = self.__get_move_xml(target_story_id, precedence) | ||
data = xml.toxml() | ||
return self.__remote_http_post("projects/%s/stories/%s/moves" % (project_id, story_id), data=data) | ||
|
||
def delete_story(self, project_id, story_id): | ||
"""deletes a story in a project""" | ||
return self.__remote_http_delete("projects/%s/stories/%s" % (project_id, story_id)) | ||
|
@@ -102,7 +154,7 @@ def deliver_all_finished_stories(self, project_id): | |
for live testing.""" | ||
return self.__remote_http_put("projects/%s/stories/deliver_all_finished" % project_id) | ||
|
||
def __get_story_xml(self, project_id, name, description, requested_by, story_type, estimate, current_state, labels): | ||
def __get_story_xml(self, name, description, requested_by, story_type, estimate, current_state, labels): | ||
|
||
# build XML elements | ||
elements = [] | ||
|
@@ -131,6 +183,38 @@ def __get_story_xml(self, project_id, name, description, requested_by, story_typ | |
xml = minidom.parseString(xml_string.strip()) | ||
return xml | ||
|
||
def __get_task_xml(self, description, complete): | ||
|
||
# build XML elements | ||
elements = [] | ||
if description is not None: | ||
elements.append("<description>%s</description>" % description) | ||
if complete is not None: | ||
elements.append("<complete type=\"boolean\">%s</complete>" % complete) | ||
else: | ||
elements.append("<complete type=\"boolean\">false</complete>") | ||
|
||
# build XML | ||
xml_string = "<task>%s</task>" % "".join(elements) | ||
xml = minidom.parseString(xml_string.strip()) | ||
return xml | ||
|
||
def __get_move_xml(self, target_story_id, precedence): | ||
|
||
# build XML elements | ||
elements = [] | ||
if target_story_id is not None: | ||
elements.append("<target>%s</target>" % target_story_id) | ||
if precedence is not None: | ||
elements.append("<move>%s</move>" % precedence) | ||
else: | ||
elements.append("<move>before</move>") | ||
|
||
# build XML | ||
xml_string = "<move>%s</move>" % "".join(elements) | ||
xml = minidom.parseString(xml_string.strip()) | ||
return xml | ||
|
||
def __iterations_request_helper(self, sub_url, project_id, limit, offset): | ||
params = {} | ||
if limit is not None: | ||
|
@@ -187,7 +271,7 @@ def parse_by_type(node): | |
return value | ||
|
||
elif obj_type == "commalist": | ||
value = node.childNodes[0].wholeText.strip() | ||
value = ''#node.childNodes[0].wholeText.strip() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the reason for using empty string here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before I merge this in, I'd like to confirm the reasoning behind this change - was this some stray debugging that accidentally got committed? |
||
return value.split(",") | ||
|
||
elif obj_type == "dictionary": | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you bring this up with the Pivotal team?