Skip to content
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

docs: clarify story history limitation in Known Limitations #89

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ignore pipenv default cookbook folder
cookbook/

# Python dev
.env
2 changes: 2 additions & 0 deletions pivotal-import/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ config.json

# Python
.coverage
.env
__pycache__
2 changes: 1 addition & 1 deletion pivotal-import/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The following are known limitations:
- **No story blockers:** Pivotal story blockers (the relationships between stories) are not imported.
- **Epics are imported as unstarted:** Imported epics are set to an unstarted "Todo" state.
- **No redirects:** The URLs in the descriptions and comments of your Pivotal stories/epics are not rewritten to point to imported Shortcut stories/epics; they remain unchanged.
- **No history:** Project history is not imported into Shortcut.
- **No history:** Project history and story history are not included in Pivotal Tracker's CSV export format and therefore cannot be imported into Shortcut.

Our intention is to attend to items higher on the list sooner than those lower.

Expand Down
36 changes: 36 additions & 0 deletions pivotal-import/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,36 @@
# Logging
logger = logging.getLogger(__name__)


# HTTP / Requests Exception Handling
# https://github.com/useshortcut/api-cookbook/issues/83
#
# When a non 200 status code is received, give the users information about
# the request and failure
#
def requests_error_decorator(func):
def inner_function(*args, **kwargs):
try:
func(*args, **kwargs)
except requests.exceptions.HTTPError as errh:
error_message = f"\nHTTP Error:\n"
error_message += f" Code: {errh.response.status_code}\n"
error_message += f" Url: {errh.request.url}\n"
error_message += f"\nServer Response:\n {errh.response.json()}"
raise requests.exceptions.HTTPError(error_message) from errh
except requests.exceptions.ConnectionError as errc:
print(f"Error Connecting: {errc}")
raise requests.exceptions.HTTPError(error_message) from errc
except requests.exceptions.Timeout as errt:
print(f"Timeout Error: {errt}")
raise requests.exceptions.HTTPError(error_message) from errt
except requests.exceptions.RequestException as err:
print(f"Unknown Http Error: {err}")
raise requests.exceptions.HTTPError(error_message) from err

return inner_function


# Rate limiting. See https://developer.shortcut.com/api/rest/v3#Rate-Limiting
# The Shortcut API limit is 200 per minute; the 200th request within 60 seconds
# will receive an HTTP 429 response.
Expand Down Expand Up @@ -65,6 +95,7 @@ def print_rate_limiting_explanation():


@rate_decorator(rate_mapping)
@requests_error_decorator
def sc_get(path, params={}):
"""
Make a GET api call.
Expand All @@ -75,10 +106,12 @@ def sc_get(path, params={}):
logger.debug("GET url=%s params=%s headers=%s" % (url, params, headers))
resp = requests.get(url, headers=headers, params=params)
resp.raise_for_status()
logger.debug("Server Response: %s" % (resp.content))
return resp.json()


@rate_decorator(rate_mapping)
@requests_error_decorator
def sc_post(path, data={}):
"""Make a POST api call.

Expand All @@ -97,6 +130,7 @@ def sc_post(path, data={}):


@rate_decorator(rate_mapping)
@requests_error_decorator
def sc_put(path, data={}):
"""
Make a PUT api call.
Expand All @@ -112,6 +146,7 @@ def sc_put(path, data={}):


@rate_decorator(rate_mapping)
@requests_error_decorator
def sc_upload_files(files):
"""Upload and associate `files` with the story with given `story_id`"""
url = f"{api_url_base}/files"
Expand Down Expand Up @@ -142,6 +177,7 @@ def sc_upload_files(files):


@rate_decorator(rate_mapping)
@requests_error_decorator
def sc_delete(path):
"""
Make a DELETE api call.
Expand Down
Loading