From d4729fc164cf8578de7956a326d0ec4399736324 Mon Sep 17 00:00:00 2001 From: "Shane M. Clements" Date: Mon, 12 May 2014 10:53:05 -0600 Subject: [PATCH 01/14] Retry connecting to github because sometimes the connection is refused. --- gh-issues-import.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index ee354e0..f81a842 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -202,22 +202,27 @@ def send_request(which, url, post_data=None): req.add_header("Content-Type", "application/json") req.add_header("Accept", "application/json") req.add_header("User-Agent", "IQAndreas/github-issues-import") - - try: - response = urllib.request.urlopen(req) - json_data = response.read() - except urllib.error.HTTPError as error: - - error_details = error.read(); - error_details = json.loads(error_details.decode("utf-8")) - - if error.code in http_error_messages: - sys.exit(http_error_messages[error.code]) - else: - error_message = "ERROR: There was a problem importing the issues.\n%s %s" % (error.code, error.reason) - if 'message' in error_details: - error_message += "\nDETAILS: " + error_details['message'] - sys.exit(error_message) + + retry = True + while retry: + retry = False + try: + response = urllib.request.urlopen(req) + json_data = response.read() + except urllib.error.HTTPError as error: + + error_details = error.read(); + error_details = json.loads(error_details.decode("utf-8")) + + if error.code in http_error_messages: + sys.exit(http_error_messages[error.code]) + else: + error_message = "ERROR: There was a problem importing the issues.\n%s %s" % (error.code, error.reason) + if 'message' in error_details: + error_message += "\nDETAILS: " + error_details['message'] + sys.exit(error_message) + except urllib.error.URLError as error: + retry = True return json.loads(json_data.decode("utf-8")) From 95896761146a3282b3103f0b786608655d371e98 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Wed, 18 Mar 2015 17:41:08 -0400 Subject: [PATCH 02/14] Fixed issue closing. - Required updating the send_request function to pass the HTTP method. - Makes separate PATCH request to close issues. --- gh-issues-import.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index ee354e0..451f21d 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -187,13 +187,13 @@ def format_comment(template_data): template = config.get('format', 'comment_template', fallback=default_template) return format_from_template(template, template_data) -def send_request(which, url, post_data=None): +def send_request(which, url, post_data=None, method=None): if post_data is not None: post_data = json.dumps(post_data).encode("utf-8") full_url = "%s/%s" % (config.get(which, 'url'), url) - req = urllib.request.Request(full_url, post_data) + req = urllib.request.Request(full_url, post_data, method=method) username = config.get(which, 'username') password = config.get(which, 'password') @@ -326,7 +326,7 @@ def get_label_by_name(name): # Temporary fix for marking closed issues if issue['closed_at']: - new_issue['title'] = "[CLOSED] " + new_issue['title'] + new_issue['state'] = "closed" if config.getboolean('settings', 'import-comments') and 'comments' in issue and issue['comments'] != 0: num_new_comments += int(issue['comments']) @@ -411,6 +411,12 @@ def get_label_by_name(name): print(" > Successfully added", len(result_comments), "comments.") result_issues.append(result_issue) + + # add issue closing + if 'state' in issue and issue['state'] == 'closed': + number = result_issue['number'] + result_issue = send_request('target', 'issues/%s' % number, issue, 'PATCH') + print(" > Successfully closed issue '%s'" % result_issue['title']) state.current = state.IMPORT_COMPLETE From 08e3a4bc23c465e58023de66e44956050279560f Mon Sep 17 00:00:00 2001 From: Lachlan Cannon Date: Tue, 27 Dec 2016 15:25:38 +1100 Subject: [PATCH 03/14] Ensure all labels are loaded. --- gh-issues-import.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index ee354e0..aee1cc0 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -225,7 +225,15 @@ def get_milestones(which): return send_request(which, "milestones?state=open") def get_labels(which): - return send_request(which, "labels") + page = 1 + labels = [] + while True: + next_labels = send_request(which, "labels?page=%s" % page) + if next_labels: + labels.extend(next_labels) + page += 1 + else: + return labels def get_issue_by_id(which, issue_id): return send_request(which, "issues/%d" % issue_id) @@ -273,7 +281,6 @@ def import_label(source): "name": source['name'], "color": source['color'] } - result_label = send_request('target', "labels", source) print("Successfully created label '%s'" % result_label['name']) return result_label From 4f885346bd583f325ab34bd7c8fa7a2cb3bc6593 Mon Sep 17 00:00:00 2001 From: Lachlan Cannon Date: Tue, 27 Dec 2016 15:27:43 +1100 Subject: [PATCH 04/14] Restore newline. --- gh-issues-import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gh-issues-import.py b/gh-issues-import.py index aee1cc0..8ee5107 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -281,6 +281,7 @@ def import_label(source): "name": source['name'], "color": source['color'] } + result_label = send_request('target', "labels", source) print("Successfully created label '%s'" % result_label['name']) return result_label From 1c0407deaf1185b98fd029fc86b5a8f35d2916b8 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 09:45:00 -0600 Subject: [PATCH 05/14] ignore pr --- gh-issues-import.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index 0e0d72b..fb336d8 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -54,6 +54,8 @@ def init_config(): arg_parser.add_argument('--ignore-comments', dest='ignore_comments', action='store_true', help="Do not import comments in the issue.") arg_parser.add_argument('--ignore-milestone', dest='ignore_milestone', action='store_true', help="Do not import the milestone attached to the issue.") arg_parser.add_argument('--ignore-labels', dest='ignore_labels', action='store_true', help="Do not import labels attached to the issue.") + arg_parser.add_argument('--ignore-pullrequests', dest='ignore_pullrequests', action='store_true', help="Do not import issues that are pull requests.") + arg_parser.add_argument('--issue-template', help="Specify a template file for use with issues.") arg_parser.add_argument('--comment-template', help="Specify a template file for use with comments.") @@ -108,6 +110,7 @@ def load_config_file(config_file_name): config.set('settings', 'import-open-issues', str(args.import_all or args.import_open)); config.set('settings', 'import-closed-issues', str(args.import_all or args.import_closed)); + config.set('settings', 'import-pullrequests', str(not args.ignore_pullrequests)); # Make sure no required config values are missing @@ -250,11 +253,15 @@ def get_issues_by_id(which, issue_ids): def get_issues_by_state(which, state): issues = [] page = 1 + import_pullrequests = config.getboolean('settings', 'import-pullrequests') while True: new_issues = send_request(which, "issues?state=%s&direction=asc&page=%d" % (state, page)) if not new_issues: break - issues.extend(new_issues) + if import_pullrequests: + issues.extend(new_issues) + else: + issues.extend(filter(lambda issue:'pull_request' not in issue ,new_issues)) page += 1 return issues From ef7c2dd972fa1416d2b080c86f0b16d9121532b1 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 09:55:44 -0600 Subject: [PATCH 06/14] Only retry if encountering 403 --- gh-issues-import.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index 07f9461..616e45b 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -6,6 +6,7 @@ import sys, os import datetime import argparse, configparser +import time import query @@ -28,7 +29,6 @@ class state: http_error_messages = {} http_error_messages[401] = "ERROR: There was a problem during authentication.\nDouble check that your username and password are correct, and that you have permission to read from or write to the specified repositories." -http_error_messages[403] = http_error_messages[401]; # Basically the same problem. GitHub returns 403 instead to prevent abuse. http_error_messages[404] = "ERROR: Unable to find the specified repository.\nDouble check the spelling for the source and target repositories. If either repository is private, make sure the specified user is allowed access to it." @@ -217,15 +217,17 @@ def send_request(which, url, post_data=None, method=None): error_details = error.read(); error_details = json.loads(error_details.decode("utf-8")) - if error.code in http_error_messages: + if error.code == 403: + print("Got 403 [%s], assuming rate limit error and waiting for 1 minute...", error_details['message']) + time.sleep(60) + retry = True + elif error.code in http_error_messages: sys.exit(http_error_messages[error.code]) else: error_message = "ERROR: There was a problem importing the issues.\n%s %s" % (error.code, error.reason) if 'message' in error_details: error_message += "\nDETAILS: " + error_details['message'] sys.exit(error_message) - except urllib.error.URLError as error: - retry = True return json.loads(json_data.decode("utf-8")) From bd357f71deefdece7f3ac87f07e8a1d6cb2e0cf4 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:09:19 -0600 Subject: [PATCH 07/14] Added a gh issues importer feature --- gh-issues-import.py | 157 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 8 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index 616e45b..21d5521 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -55,7 +55,7 @@ def init_config(): arg_parser.add_argument('--ignore-milestone', dest='ignore_milestone', action='store_true', help="Do not import the milestone attached to the issue.") arg_parser.add_argument('--ignore-labels', dest='ignore_labels', action='store_true', help="Do not import labels attached to the issue.") arg_parser.add_argument('--ignore-pullrequests', dest='ignore_pullrequests', action='store_true', help="Do not import issues that are pull requests.") - + arg_parser.add_argument('--use-github-import-api', dest='use_github_import_api', action='store_true', help="Use the new github import api") arg_parser.add_argument('--issue-template', help="Specify a template file for use with issues.") arg_parser.add_argument('--comment-template', help="Specify a template file for use with comments.") @@ -65,7 +65,7 @@ def init_config(): include_group.add_argument("--all", dest='import_all', action='store_true', help="Import all issues, regardless of state.") include_group.add_argument("--open", dest='import_open', action='store_true', help="Import only open issues.") include_group.add_argument("--closed", dest='import_closed', action='store_true', help="Import only closed issues.") - include_group.add_argument("-i", "--issues", type=int, nargs='+', help="The list of issues to import."); + include_group.add_argument("-i", "--issues", type=int, nargs='+', help="The list of issues to import.") args = arg_parser.parse_args() @@ -108,9 +108,10 @@ def load_config_file(config_file_name): config.set('settings', 'import-milestone', str(not args.ignore_milestone)) config.set('settings', 'import-labels', str(not args.ignore_labels)) - config.set('settings', 'import-open-issues', str(args.import_all or args.import_open)); - config.set('settings', 'import-closed-issues', str(args.import_all or args.import_closed)); - config.set('settings', 'import-pullrequests', str(not args.ignore_pullrequests)); + config.set('settings', 'import-open-issues', str(args.import_all or args.import_open)) + config.set('settings', 'import-closed-issues', str(args.import_all or args.import_closed)) + config.set('settings', 'import-pullrequests', str(not args.ignore_pullrequests)) + config.set('settings', 'use-github-import-api', str(args.use_github_import_api)) # Make sure no required config values are missing @@ -190,7 +191,7 @@ def format_comment(template_data): template = config.get('format', 'comment_template', fallback=default_template) return format_from_template(template, template_data) -def send_request(which, url, post_data=None, method=None): +def send_request(which, url, post_data=None, method=None, accept=None): if post_data is not None: post_data = json.dumps(post_data).encode("utf-8") @@ -203,7 +204,10 @@ def send_request(which, url, post_data=None, method=None): req.add_header("Authorization", b"Basic " + base64.urlsafe_b64encode(username.encode("utf-8") + b":" + password.encode("utf-8"))) req.add_header("Content-Type", "application/json") - req.add_header("Accept", "application/json") + if accept is not None: + req.add_header("Accept", accept) + else: + req.add_header("Accept", "application/json") req.add_header("User-Agent", "IQAndreas/github-issues-import") retry = True @@ -319,6 +323,140 @@ def import_comments(comments, issue_number): return result_comments +def import_issues_golden_comet(issues): + state.current = state.GENERATING + + known_milestones = get_milestones('target') + def get_milestone_by_title(title): + for milestone in known_milestones: + if milestone['title'] == title : return milestone + return None + + known_labels = get_labels('target') + def get_label_by_name(name): + for label in known_labels: + if label['name'] == name : return label + return None + + issue_migrations = [] + new_milestones = [] + num_new_comments = 0 + new_labels = [] + + for issue in issues: + issue_migration = {} + new_issue = [] + new_issue['title'] = issue['title'] + new_issue['closed_at'] = issue['closed_at'] + new_issue['created_at'] = issue['created_at'] + new_issue['updated_at'] = issue['updated_at'] + # TODO new_issue['assignee'] = issue['assignee'] + new_issue['closed'] = issue['closed_at'] != None + + if config.getboolean('settings', 'import-milestone') and 'milestone' in issue and issue['milestone'] is not None: + # Since the milestones' ids are going to differ, we will compare them by title instead + found_milestone = get_milestone_by_title(issue['milestone']['title']) + if found_milestone: + new_issue['milestone_object'] = found_milestone + else: + new_milestone = issue['milestone'] + new_issue['milestone_object'] = new_milestone + known_milestones.append(new_milestone) # Allow it to be found next time + new_milestones.append(new_milestone) # Put it in a queue to add it later + + if config.getboolean('settings', 'import-labels') and 'labels' in issue and issue['labels'] is not None: + new_issue['label_objects'] = [] + for issue_label in issue['labels']: + found_label = get_label_by_name(issue_label['name']) + if found_label: + new_issue['label_objects'].append(found_label) + else: + new_issue['label_objects'].append(issue_label) + known_labels.append(issue_label) # Allow it to be found next time + new_labels.append(issue_label) # Put it in a queue to add it later + + comments = [] + if config.getboolean('settings', 'import-comments') and 'comments' in issue and issue['comments'] != 0: + num_new_comments += int(issue['comments']) + original_comments = get_comments_on_issue('source', issue) + for original_comment in original_comments: + comment = [] + ctemplate_data = {} + ctemplate_data['user_name'] = original_comment['user']['login'] + ctemplate_data['user_url'] = original_comment['user']['html_url'] + ctemplate_data['user_avatar'] = original_comment['user']['avatar_url'] + ctemplate_data['date'] = format_date(original_comment['created_at']) + ctemplate_data['url'] = original_comment['html_url'] + ctemplate_data['body'] = original_comment['body'] + + comment['body'] = format_comment(ctemplate_data) + comment['created_at'] = original_comment['created_at'] + comments.append(comment) + + template_data = {} + template_data['user_name'] = issue['user']['login'] + template_data['user_url'] = issue['user']['html_url'] + template_data['user_avatar'] = issue['user']['avatar_url'] + template_data['date'] = format_date(issue['created_at']) + template_data['url'] = issue['html_url'] + template_data['body'] = issue['body'] + + if "pull_request" in issue and issue['pull_request']['html_url'] is not None: + new_issue['body'] = format_pull_request(template_data) + else: + new_issue['body'] = format_issue(template_data) + + issue_migration['issue'] = new_issue + issue_migration['comments'] = comments + + issue_migrations.append(issue_migration) + + state.current = state.IMPORT_CONFIRMATION + + print("You are about to add to '" + config.get('target', 'repository') + "':") + print(" *", len(issue_migrations), "new issues") + print(" *", num_new_comments, "new comments") + print(" *", len(new_milestones), "new milestones") + print(" *", len(new_labels), "new labels") + if not query.yes_no("Are you sure you wish to continue?"): + sys.exit() + + state.current = state.IMPORTING + + for milestone in new_milestones: + result_milestone = import_milestone(milestone) + milestone['number'] = result_milestone['number'] + milestone['url'] = result_milestone['url'] + + for label in new_labels: + result_label = import_label(label) + + migration_results = [] + for issue in new_issues: + + if 'milestone_object' in issue: + issue['milestone'] = issue['milestone_object']['number'] + del issue['milestone_object'] + + if 'label_objects' in issue: + issue_labels = [] + for label in issue['label_objects']: + issue_labels.append(label['name']) + issue['labels'] = issue_labels + del issue['label_objects'] + + migration_result = send_request('target', "import/issues", issue, POST, "application/vnd.github.golden-comet-preview+json") + print("Sent import request. Status: '%s'. Status url: '%s'" % (migration_result['status'], migration_result['import_issues_url'])) + + migration_results.append(migration_result) + + state.current = state.IMPORT_COMPLETE + + # TODO wait for import requests to complete + + return result_issues + + # Will only import milestones and issues that are in use by the imported issues, and do not exist in the target repository def import_issues(issues): @@ -470,7 +608,10 @@ def get_label_by_name(name): # Further states defined within the function # Finally, add these issues to the target repository - import_issues(issues) + if config.getboolean('settings', 'use-github-import-api'): + import_issues_golden_comet(issues) + else: + import_issues(issues) state.current = state.COMPLETE From 4c09795b7e4f9ae1c519d07ba95485e08a969478 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:14:53 -0600 Subject: [PATCH 08/14] Fix some syntax issues --- gh-issues-import.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index 21d5521..f692b38 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -345,7 +345,7 @@ def get_label_by_name(name): for issue in issues: issue_migration = {} - new_issue = [] + new_issue = {} new_issue['title'] = issue['title'] new_issue['closed_at'] = issue['closed_at'] new_issue['created_at'] = issue['created_at'] @@ -380,7 +380,7 @@ def get_label_by_name(name): num_new_comments += int(issue['comments']) original_comments = get_comments_on_issue('source', issue) for original_comment in original_comments: - comment = [] + comment = {} ctemplate_data = {} ctemplate_data['user_name'] = original_comment['user']['login'] ctemplate_data['user_url'] = original_comment['user']['html_url'] From 8a409cbca39d5ef66792ffa3cd2e9c80a625fe37 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:27:55 -0600 Subject: [PATCH 09/14] Fixed milestone and label post data --- gh-issues-import.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index f692b38..eeeb515 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -290,7 +290,7 @@ def import_milestone(source): "due_on": source['due_on'] } - result_milestone = send_request('target', "milestones", source) + result_milestone = send_request('target', "milestones", data) print("Successfully created milestone '%s'" % result_milestone['title']) return result_milestone @@ -300,7 +300,7 @@ def import_label(source): "color": source['color'] } - result_label = send_request('target', "labels", source) + result_label = send_request('target', "labels", data) print("Successfully created label '%s'" % result_label['name']) return result_label From 4ecaf8c4a0169eabb3dc84648da1f74cb4302a34 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:38:04 -0600 Subject: [PATCH 10/14] Simplified closed at logic --- gh-issues-import.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index eeeb515..27b3082 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -347,11 +347,12 @@ def get_label_by_name(name): issue_migration = {} new_issue = {} new_issue['title'] = issue['title'] - new_issue['closed_at'] = issue['closed_at'] + if issue['closed_at'] is not None: + new_issue['closed_at'] = issue['closed_at'] + new_issue['closed'] = True new_issue['created_at'] = issue['created_at'] new_issue['updated_at'] = issue['updated_at'] # TODO new_issue['assignee'] = issue['assignee'] - new_issue['closed'] = issue['closed_at'] != None if config.getboolean('settings', 'import-milestone') and 'milestone' in issue and issue['milestone'] is not None: # Since the milestones' ids are going to differ, we will compare them by title instead From 9468cc130633aae31f7ca015cee8b571cdc92017 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:38:23 -0600 Subject: [PATCH 11/14] Fixed variable names --- gh-issues-import.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index 27b3082..a8cc43d 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -433,8 +433,8 @@ def get_label_by_name(name): result_label = import_label(label) migration_results = [] - for issue in new_issues: - + for issue_migration in issue_migrations: + issue = issue_migration['issue'] if 'milestone_object' in issue: issue['milestone'] = issue['milestone_object']['number'] del issue['milestone_object'] @@ -446,7 +446,7 @@ def get_label_by_name(name): issue['labels'] = issue_labels del issue['label_objects'] - migration_result = send_request('target', "import/issues", issue, POST, "application/vnd.github.golden-comet-preview+json") + migration_result = send_request('target', "import/issues", issue_migration, "POST", "application/vnd.github.golden-comet-preview+json") print("Sent import request. Status: '%s'. Status url: '%s'" % (migration_result['status'], migration_result['import_issues_url'])) migration_results.append(migration_result) From f84505b23e39ea5e4c81778489cc140aeeb3edc0 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:45:03 -0600 Subject: [PATCH 12/14] Use url instead of import issues url --- gh-issues-import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index a8cc43d..7845af5 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -447,7 +447,7 @@ def get_label_by_name(name): del issue['label_objects'] migration_result = send_request('target', "import/issues", issue_migration, "POST", "application/vnd.github.golden-comet-preview+json") - print("Sent import request. Status: '%s'. Status url: '%s'" % (migration_result['status'], migration_result['import_issues_url'])) + print("Sent import request. Status: '%s'. Status url: '%s'" % (migration_result['status'], migration_result['url'])) migration_results.append(migration_result) From 9536ba0228db12ea807c2b18595c7711f8e768f3 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 11:45:12 -0600 Subject: [PATCH 13/14] Fixed return var --- gh-issues-import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index 7845af5..e077bb6 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -455,7 +455,7 @@ def get_label_by_name(name): # TODO wait for import requests to complete - return result_issues + return issue_migrations # Will only import milestones and issues that are in use by the imported issues, and do not exist in the target repository From a677e512b0f3cae4e39377de3baa799b24c2e4df Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 4 Jul 2017 12:07:20 -0600 Subject: [PATCH 14/14] Fixed rate limit error message formatting --- gh-issues-import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gh-issues-import.py b/gh-issues-import.py index e077bb6..a295ba4 100755 --- a/gh-issues-import.py +++ b/gh-issues-import.py @@ -222,7 +222,7 @@ def send_request(which, url, post_data=None, method=None, accept=None): error_details = json.loads(error_details.decode("utf-8")) if error.code == 403: - print("Got 403 [%s], assuming rate limit error and waiting for 1 minute...", error_details['message']) + print("Got 403 [%s], assuming rate limit error and waiting for 1 minute..." % error_details['message']) time.sleep(60) retry = True elif error.code in http_error_messages: